PT EN
Sign in Sign up →
Proprietary API · Broad access

Full API

This API gives broad access to a delivery company's operation — orders, customers, couriers, vehicle types, webhooks. Use it when your system integrates with one specific delivery company that gave you an API key (e.g., an ERP or internal dashboard connected to its operation). Endpoints are named in Portuguese; payloads and responses are JSON.

Are you a digital menu, a restaurant system or a marketplace? If you send orders on behalf of merchants that hire a delivery company, this is not the right API. Use the OpenDelivery standard — multi-customer, OAuth, the same contract iFood/Anota AI/Saipos already use. See the OpenDelivery documentation →

Introduction

The Full integration gives access to the same set of operations the delivery company uses in its own Admin Panel: creating orders, tracking status, managing the customers who request deliveries, looking up the available vehicle types and subscribing to webhooks. Unlike OpenDelivery, which is multi-customer and uses OAuth, Full is one-to-one: a fixed API key issued by the delivery company itself, with permission over its operation.

Typical flow:

  1. The delivery company gives you the API key (Bearer token).
  2. You use POST /v1/orders/calcular to simulate price and distance before the consumer confirms.
  3. You create the order with POST /v1/orders (or do everything in a single call with POST /v1/chamar-entregador).
  4. You track it in real time via webhook, subscribing to the events you use, or by polling GET /v1/orders/{id}.

Base URL

All endpoints below are relative to this base, on the delivery company's domain:

https://entregasexpressas.com.br/api/v1
In sandbox, the base is the same — what changes is the API key, which belongs to an isolated test hub created when you created the app. Get the key in the Credentials tab of your app in the Portal.

🔑 Authentication

Every call requires the header Authorization: Bearer <your-api-key>. The key is static (it does not expire over time); it only changes if it is regenerated manually. Treat it like a password — do not expose it in front-end code. You can regenerate it at any time in the Credentials tab of the app in the Portal.

Always send Accept: application/json and Content-Type: application/json as well on requests with a body.

Two kinds of key

The delivery company can issue two kinds of API key, and what each one reaches is different:

KeyWhat it reaches
Hub key The entire operation of that hub: orders from all customers, user records, couriers, wallet entries and blocks.
Customer key Only what belongs to that customer: its own orders, its own record and its own balance. Moving money, blocking and looking up couriers respond with 403.

The split exists because the two things are not the same: whoever reads their own balance cannot credit it, and the courier team belongs to the company, not to whoever hires the delivery.

// 403 — the credential does not reach the resource
{"mensagem": "Esta credencial não tem acesso a este recurso"}

cURL example

curl https://entregasexpressas.com.br/api/v1/tipos-veiculos \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Accept: application/json"

Calculate price

Before sending the order you can simulate its price by sending the delivery data — it returns the distance, the gross price and formatted descriptions. Nothing is created in the system.

POST /v1/orders/calcular 200 400

Request body

FieldTypeDescription
tipo_veiculo_id requiredintegerVehicle Type ID (see /v1/tipos-veiculos).
categoria_id integerID of the vehicle type's Category (/v1/tipos-veiculos/{id}/categorias).
endereco_coleta requiredobjectPickup address object — see the schema below.
endereco_coleta.endereco requiredstringText description of the address. If latitude/longitude are not sent, we geocode from this.
endereco_coleta.latitudenumberLatitude. Required if you do not send the text address.
endereco_coleta.longitudenumberLongitude. Required if you do not send the text address.
endereco_coleta.nomestringName of the contact at the pickup.
endereco_coleta.telefonestringContact's phone number.
enderecos_entrega requiredobject[]Array of delivery addresses, minimum 1.
enderecos_entrega[].endereco requiredstringDescription of the delivery address.
enderecos_entrega[].latitudenumberLatitude of the address.
enderecos_entrega[].longitudenumberLongitude of the address.
enderecos_entrega[].nomestringRecipient's name.
enderecos_entrega[].telefonestringRecipient's phone number.
cliente_idintegerCustomer ID (required if the cliente object is not sent).
dimensoes_pacoteobjectPackage dimensions — may be required for some vehicle types.
dimensoes_pacote.pesonumberPackage weight.
dimensoes_pacote.larguranumberPackage width.
dimensoes_pacote.alturanumberPackage height.
dimensoes_pacote.comprimentonumberPackage length.
retorno_necessariobooleanWhether the courier must return to the pickup location after the last delivery.
prova_entrega_necessariabooleanWhether the courier must collect a signature and document at each delivery.

Example

curl -X POST https://entregasexpressas.com.br/api/v1/orders/calcular \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "tipo_veiculo_id": 1,
    "categoria_id": 3,
    "cliente_id": 3,
    "endereco_coleta": {
      "endereco": "Rua teste, 123 - Teste, São Paulo - SP, 00000-000",
      "latitude": -23.570914,
      "longitude": -46.645079,
      "nome": "João",
      "telefone": "(11) 99999-9923"
    },
    "enderecos_entrega": [
      {
        "endereco": "Rua teste, 33 - Teste 2, São Paulo - SP, 00000-000",
        "latitude": -23.585292,
        "longitude": -46.655723,
        "nome": "Maria",
        "telefone": "(11) 12131-9923"
      }
    ],
    "dimensoes_pacote": { "peso": 15, "largura": 15, "altura": 15, "comprimento": 15 },
    "retorno_necessario": true,
    "prova_entrega_necessaria": false
  }'

200 response

FieldTypeDescription
preconumberOrder price (gross).
distancianumberDistance in km from the pickup address to the last delivery address (or the return, if applicable).
precoDescricaostringPrice formatted in R$.
distanciaDescricaostringFormatted distance (e.g., 5,42 km).
{
  "preco": 12.50,
  "distancia": 5.42,
  "precoDescricao": "R$ 12,50",
  "distanciaDescricao": "5,42 km"
}

New order

Creates a delivery order. The pickup and delivery addresses must contain latitude/longitude, or the text address for automatic geocoding. Prerequisite: the customer exists (use cliente_id), or you send the nested cliente object.

POST /v1/orders 201 400, 403 500

Request body

FieldTypeDescription
tipo_veiculo_id requiredintegerVehicle Type ID.
categoria_idintegerCategory ID.
endereco_coleta requiredobjectSame schema as /calcular, plus external_id (string).
endereco_coleta.external_idstringExternal ID of the address in your system.
enderecos_entrega requiredobject[]Same schema as /calcular, plus external_id and order_display_id.
enderecos_entrega[].external_idstringExternal ID of the delivery address.
enderecos_entrega[].order_display_idstringDisplay ID of the order associated with the address (visible when external ID display is enabled).
cliente_idintegerCustomer ID. Required if you do not send the cliente object.
clienteobjectCreates the user inline. Required if you do not send cliente_id.
cliente.nome required with clientestringCustomer's name.
cliente.email required with clientestringCustomer's email.
cliente.telefone required with clientestringCustomer's phone number.
cliente.senha required with clientestringPassword (minimum 6 characters).
external_idstringExternal ID of the order, for reference in your system. It appears in every subsequent webhook.
dimensoes_pacoteobjectPackage dimensions: peso, largura, altura, comprimento (see /calcular).
retorno_necessariobooleanReturn to the pickup location after the last delivery.
prova_entrega_necessariabooleanCollect a photo/signature/document at each delivery.
observacaostringFree-text note for the order (the courier sees it in the app).
metodo_pagamentoenumfaturadocarteira — default: faturado.
status_inicialenumpendingpreparing — pending searches for a courier immediately; preparing keeps the order in preparation. Default: pending.
agendamento_segundosintegerSeconds from now to schedule the order. When sent, status_inicial is ignored and the order enters as scheduled.
201 response: returns the full Order object. See the schema in Order object.
Order status progresses through: pending → accepted → arrived_pickup_location → collected → delivered → completed. Special cases: scheduled, preparing, waiting, cancelled. Use webhooks to follow it without polling.

List orders

Lists orders, paginated. You can also look up specific orders by id or external_id.

GET /v1/orders 200

Query string

ParamTypeDescription
pageintegerPage number (default: 1).
limitintegerItems per page (max: 100, default: 50).
idintegerFilter by order ID (direct lookup, no pagination).
public_idstringFilter by order number (public_id, direct lookup, no pagination).
external_idstringFilter by the order's external ID (direct lookup, no pagination).

200 response

Returns Laravel's standard pagination, with data[] containing one Order object per item — full schema in Order object.

{
  "current_page": 1,
  "data": [ /* Order objects */ ],
  "first_page_url": "...",
  "from": 1,
  "last_page": 4,
  "last_page_url": "...",
  "limit": 50,
  "next_page_url": "...",
  "path": "https://entregasexpressas.com.br/api/v1/orders",
  "prev_page_url": null,
  "to": 50,
  "total": 187
}

Get order

Fetches the data of a specific order by its ID.

GET /v1/orders/{id} 200 404

URL params

ParamTypeDescription
order requiredinteger | stringOrder ID or its public_id. Example: 127 or A7K2.

200 response

Returns the full Order object — see Order object.

// 404
{"mensagem": "Pedido não encontrado"}

Cancel order

Cancels an order. Available only for orders that have not been accepted yet (pending, waiting, scheduled or preparing).

DELETE /v1/orders/{id} 200 400, 404

Responses

// 200 OK
{"mensagem": "Pedido cancelado"}

// 400 — the current status does not allow cancellation
{"mensagem": "O pedido não pode ser cancelado"}

// 404
{"mensagem": "Pedido não encontrado"}

Call a courier (one-shot)

Creates an order of the call a courier type, where the delivery addresses are set by the courier at pickup time. You must provide the number of delivery locations (num_locais_entrega). It also creates the user inline if cliente_id is not sent.

POST /v1/chamar-entregador 201 400

Request body

FieldTypeDescription
cliente_idintegerCustomer ID. Required if you do not send the cliente object.
clienteobjectCreates the user inline. Required if you do not send cliente_id.
cliente.nome required with clientestringCustomer's name.
cliente.email required with clientestringCustomer's email.
cliente.telefone required with clientestringCustomer's phone number.
cliente.senha required with clientestringPassword (minimum 6 characters).
endereco_coleta requiredobjectPickup address, with endereco, latitude and longitude required.
num_locais_entrega requiredintegerNumber of delivery locations the courier will enter.
tipo_veiculo_idintegerVehicle Type ID.
retorno_necessariobooleanReturn to the pickup location.
prova_entregabooleanCollect proof of delivery.
observacaostringOrder note.
metodo_pagamentoenumfaturadocarteira_digital
status_inicialenumpendingpreparing — default pending.
agendamento_segundosintegerSeconds from now to schedule. When sent, status_inicial is ignored.

201 response — example

{
  "id": 128,
  "order_status": "pending",
  "status": "Pendente",
  "total_value": 0,
  "distance": 0,
  "pickup_location_data": {
    "endereco": "Rua teste, 123 - Teste, São Paulo - SP, 00000-000",
    "latitude": -23.570914,
    "longitude": -46.645079
  },
  "delivery_locations_data": [
    {"endereco": "Endereço de Entrega #1 (Definido no momento da entrega)", "latitude": null, "longitude": null, "delivered": false},
    {"endereco": "Endereço de Entrega #2 (Definido no momento da entrega)", "latitude": null, "longitude": null, "delivered": false}
  ]
}

Full response schema in Order object.

Users (customers)

CRUD for the users (customers) who place orders through the company. Each user belongs to a central (hub) — the hub ID is implicit in the API key.

List / search users

GET /v1/usuarios 200
Query paramTypeDescription
emailstringFilter by the user's email.
external_idstringFilter by the user's external ID.

Get user

GET /v1/usuarios/{id} 200 404
// 404
{"mensagem": "Usuário não encontrado"}

Create user

POST /v1/usuarios 201 400
FieldTypeDescription
nome requiredstringUser's name (max 191).
email requiredstringEmail (unique per customer).
senha requiredstringPassword (minimum 6, max 191).
telefone requiredstringPhone number (max 191).
external_idstringExternal ID of the user in your system (max 191).
// Request
{
  "nome": "Novo Usuário",
  "email": "[email protected]",
  "senha": "0346nlkasd",
  "telefone": "(11) 12532-1234",
  "external_id": "12516"
}

// 400 — validation
{"mensagem": "Erro de validação", "errors": {"email": ["O email informado está em uso"]}}

Update user

Updates the data of an existing user. Only the fields you send are updated.

PUT /v1/usuarios/{id} 200 404
FieldTypeDescription
nomestringNew name.
telefonestringNew phone number.
external_idstringNew external ID.
senhastringNew password (minimum 6).
bloqueadobooleanBlocks or unblocks the customer. It only applies when the field is sent — omitting it keeps the current state. See Block / unblock.
// 404
{"mensagem": "Usuário não encontrado"}

User object (response)

FieldTypeDescription
data.idintegerUser ID.
data.nomestringUser's name.
data.emailstringUser's email.
data.telefonestringUser's phone number.
data.external_idstringExternal ID in your system.
data.faturamentobooleanIndicates whether invoicing is enabled for the user.
data.saldonumberDigital wallet balance.
data.bloqueadobooleanIndicates whether the customer is blocked from placing orders.
data.has_mediabooleanIndicates whether the user has an image.
data.mediaobject[]User's images.
data.data_criacaostringDate the record was created.

Generate access token

Generates an access token for a user. If the user does not exist, it is created automatically with the data you send — which is why every field of the record is required.

POST /v1/generateAccessToken 201 400
FieldTypeDescription
nome requiredstringUser's name.
email requiredstringUser's email.
senha requiredstringUser's password.
telefone requiredstringUser's phone number.
// 201
{"token": "aB3dEf4gHi5jKl6mNo7pQr8sTu9vWx0yZ1aB2cD3eF4gH5iJ6kL7mN8oP9q"}

// 400 — validation
{"mensagem": "Erro de validação", "errors": {"email": ["O campo email é obrigatório"]}}

Block / unblock a customer

Blocking cuts off the intake: the customer can no longer place orders, through the portal or the API. It does not cancel or interrupt what is already in progress — an order out for delivery keeps being handled normally.

POST /v1/usuarios/{id}/bloqueio 200 403 404
DELETE /v1/usuarios/{id}/bloqueio 200

Both return the updated User object, with the bloqueado field. No body is needed.

The same state can also be sent on PUT /v1/usuarios/{id}, in the optional bloqueado field — it is the same thing, for those who sync the whole record in a single call. Omitting the field keeps the current state.

curl -X POST https://entregasexpressas.com.br/api/v1/usuarios/3/bloqueio \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Accept: application/json"

// 200
{"data": {"id": 3, "nome": "Loja Centro", "bloqueado": true, "saldo": 152.40}}

Wallet (balance, statement and entries)

The digital wallet is the prepaid balance the delivery company keeps for each customer and for each courier. These endpoints read the balance, read the statement and make manual entries — the same ones the Admin Panel makes on the "Adicionar saldo" (add balance) and "Remover saldo" (remove balance) screens.

These endpoints do not charge anyone. They record money that has already come in or gone out. None of them generates a Pix, a boleto or a card charge — charging is still done through the payment methods of the Admin Panel, and when a charge is confirmed the balance is credited on its own.
EndpointWhat it does
GET /v1/usuarios/{id}/carteiraCustomer's current balance.
GET /v1/usuarios/{id}/carteira/transacoesCustomer's statement, paginated.
POST /v1/usuarios/{id}/carteira/creditosAdds balance.
POST /v1/usuarios/{id}/carteira/debitosRemoves balance.
POST /v1/usuarios/{id}/carteira/recargasRecords a top-up that has already been paid, with the fee.
GET /v1/entregadores/{id}/carteiraCourier's current balance.
GET /v1/entregadores/{id}/carteira/transacoesCourier's statement, paginated.
POST /v1/entregadores/{id}/carteira/creditosAdds balance.
POST /v1/entregadores/{id}/carteira/debitosRemoves balance.
POST /v1/entregadores/{id}/carteira/recargasRecords a deposit made by the courier.

Safe retries (external_id)

Every entry accepts an external_id — the identifier of that entry in your system. It exists for a practical reason: network timeouts are the common case in an integration, and without an idempotency key, retrying a money POST credits twice.

The key is unique per wallet. Use a value your system can reproduce on the retry (the ID of the transaction in your ERP, for example) — a value drawn at random on each attempt protects nothing. Without external_id, every call is a new entry.

Get balance

GET /v1/usuarios/{id}/carteira 200 404
// 200
{"data": {"usuario_id": 3, "saldo": 152.40}}

usuario_id is the owner of the wallet. When the ID you query belongs to a sub-user, the response carries the account owner's ID: a sub-user has no wallet of its own, it spends the store's.

Statement

GET /v1/usuarios/{id}/carteira/transacoes 200
Query paramTypeDescription
operacaoenumcreditodebito
external_idstringFinds the entry by its idempotency key — this is how you check whether a POST that timed out went through.
por_paginainteger1 to 200. Default 50.
paginaintegerDefault 1.
// 200
{
  "data": [
    {
      "id": 8813,
      "uuid": "1f0a…",
      "operacao": "credito",
      "tipo": "adicao_saldo",
      "valor": 200.00,
      "descricao": "Recarga via Pix — comprovante 8812",
      "status": "concluido",
      "external_id": "erp-recarga-4410",
      "forma_pagamento": "pix",
      "referencia_id": null,
      "data_criacao": "2026-09-09T14:02:11.000000Z"
    }
  ],
  "meta": {"pagina": 1, "por_pagina": 50, "total": 137, "saldo": 448.90}
}

Add balance

Manual credit — the same entry the Admin Panel makes in "Adicionar saldo" (add balance).

POST /v1/usuarios/{id}/carteira/creditos 201 400 403 404
FieldTypeDescription
valor requirednumberGreater than zero. Two decimal places.
descricaostringText shown on the statement (max 191). Left blank, it becomes -.
external_idstringIdempotency key (max 191). See above.
curl -X POST https://entregasexpressas.com.br/api/v1/usuarios/3/carteira/creditos \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{"valor": 100.50, "descricao": "Bônus de campanha", "external_id": "erp-credito-9931"}'

// 201
{
  "data": {"id": 8812, "operacao": "credito", "tipo": "adicao_saldo", "valor": 100.50, "status": "concluido", "external_id": "erp-credito-9931"},
  "saldo": 252.90,
  "duplicada": false
}

Remove balance

POST /v1/usuarios/{id}/carteira/debitos 201 400
FieldTypeDescription
valor requirednumberGreater than zero.
descricaostringText shown on the statement.
external_idstringIdempotency key.
permitir_saldo_negativobooleanDefault true, as in the Admin Panel. With false, the call is rejected when the balance does not cover the amount.
// 400 — only when permitir_saldo_negativo = false
{"mensagem": "Saldo insuficiente para o débito"}

Record a top-up

Records a top-up the customer has already paid. It is the same credit as carteira/creditos, with two differences:

POST /v1/usuarios/{id}/carteira/recargas 201 400
FieldTypeDescription
valor requirednumberGreater than zero.
forma_pagamento requiredenumpixboletocredit_carddinheirotransferenciaoutro
descricaostringText shown on the statement.
external_idstringIdempotency key.
aplicar_taxabooleanDefault true. With false, the full amount is credited and no fee is recorded.

The fee only exists for pix, boleto and credit_card, and only when the delivery company has configured it — for the other methods, and where it is not configured, the full amount is credited and the taxa block does not appear in the response.

// 201
{
  "data": {"id": 8813, "operacao": "credito", "tipo": "adicao_saldo", "valor": 200.00, "forma_pagamento": "pix"},
  "taxa": {"valor": 4.00, "transacao_id": 8814},
  "saldo": 448.90,
  "duplicada": false
}

Courier wallet

The same four endpoints exist for the courier, replacing usuarios with entregadores and the customer's ID with the courier's ID (the id returned by /v1/entregadores).

Couriers

Look up the company's courier team, their real-time status, block access and block withdrawals only. Their wallet is covered in the Wallet section.

Registering a courier is not done here, on purpose. Registration involves submitting documents, approval and creating the app login — doing that through an integration POST would approve someone as a side effect. Use the self-registration flow or the Admin Panel.

List couriers

GET /v1/entregadores 200 403
Query paramTypeDescription
emailstringFilter by email.
telefonestringFilter by phone number.
cpfstringFilter by document number.
placastringFilter by the vehicle's license plate.
ativobooleanWorking in the app right now.
bloqueadobooleanBlocked or not blocked.
aprovadobooleanRegistration approved or not.
por_paginainteger1 to 200. Default 50.
paginaintegerDefault 1.

Entregador object (response)

FieldTypeDescription
idintegerCourier ID — this is what the wallet and block endpoints take.
nomestringCourier's name.
emailstringEmail.
telefonestringPhone number.
cpfstringDocument number.
ativobooleanWhether they are working in the app right now. They are the one who turns this on and off, in the app.
aprovadobooleanWhether the registration was approved by the company.
bloqueadobooleanWhether they are blocked.
bloqueado_atestringDate of the automatic unblock, if any.
veiculoobjectmodelo, cor and placa.
tipos_servicoobject[]Service types they handle (id, nome).
saldonumberTheir wallet balance.
saque_bloqueadobooleanWhether wallet withdrawals are blocked. See Block withdrawals.
data_criacaostringDate the record was created.
// 200
{
  "data": [
    {
      "id": 12,
      "nome": "João Souza",
      "email": "[email protected]",
      "telefone": "(11) 99999-8888",
      "cpf": "000.000.000-00",
      "ativo": true,
      "aprovado": true,
      "bloqueado": false,
      "bloqueado_ate": null,
      "veiculo": {"modelo": "Honda CG 160", "cor": "Vermelho", "placa": "ABC1D23"},
      "tipos_servico": [{"id": 1, "nome": "Moto"}],
      "saldo": -18.70,
      "saque_bloqueado": false,
      "data_criacao": "2026-03-02T11:20:00.000000Z"
    }
  ],
  "meta": {"pagina": 1, "por_pagina": 50, "total": 34}
}

Online couriers

Only the couriers who are online now, from the one who sent a position most recently to the oldest, with the same pagination as the listing. Each item is a full Courier object; the webhook's courier events carry a subset of it.

GET /v1/entregadores/online 200 403
Query paramTypeDescription
statusstringavailable or busy. Without it, both are returned.
por_paginainteger1 to 200. Default 50.
paginaintegerDefault 1.
To follow the fleet without querying this route periodically, subscribe to the courier events on the webhook.

Get courier

GET /v1/entregadores/{id} 200 404

Block / unblock a courier

Blocking takes the courier out of operation: they stop receiving order offers and cannot accept what was already on their screen. It does not interrupt an order in progress — blocking in the middle of a shift cannot leave a delivery orphaned on the street; they finish what they are carrying.

POST /v1/entregadores/{id}/bloqueio 200 400 404
FieldTypeDescription
bloqueado_atestringDate/time of the automatic unblock (ISO 8601), in the future. Without it, the block lasts until someone unblocks.
DELETE /v1/entregadores/{id}/bloqueio 200
Unblocking does not set the courier back to "active". They are the one who goes on duty, by opening the app — reactivating them through the API would leave them receiving orders without having opened the app. It is the same rule as the platform's automatic unblock. Expect bloqueado: false and ativo as it was.
curl -X POST https://entregasexpressas.com.br/api/v1/entregadores/12/bloqueio \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{"bloqueado_ate": "2026-09-20T18:00:00-03:00"}'

// 200
{"data": {"id": 12, "nome": "João Souza", "ativo": false, "bloqueado": true, "bloqueado_ate": "2026-09-20T21:00:00.000000Z"}}

Block / unblock withdrawals

Blocks only the withdrawals and advances from the wallet. The courier stays online, receiving, accepting and delivering orders normally. The response is the Entregador object, with saque_bloqueado updated.

POST /v1/entregadores/{id}/bloqueio-saque 200 404
DELETE /v1/entregadores/{id}/bloqueio-saque 200 404
curl -X POST https://entregasexpressas.com.br/api/v1/entregadores/12/bloqueio-saque \
  -H "Authorization: Bearer <your-api-key>"

// 200
{"data": {"id": 12, "nome": "João Souza", "ativo": true, "saque_bloqueado": true, ...}}

Vehicle types & categories

Each company configures which vehicle types it operates (motorcycle, car, etc.) and, optionally, categories within each type (e.g., "Moto com bag" vs "Moto sem bag"). Use these endpoints to build the pickers in your system and to find out weight/dimension limits before sending the order.

List vehicle types

GET /v1/tipos-veiculos 200
Query paramTypeDescription
nomestringFilters by the vehicle type's name (LIKE search).

Response fields

FieldTypeDescription
idintegerVehicle type ID.
nomestringVehicle type name.
peso_e_dimensoesbooleanIndicates whether the vehicle type requires the package's weight/dimensions.
limitar_peso_e_dimensoesbooleanIndicates whether weight/dimensions are limited (orders above the maximums are rejected).
altura_maximanumberMaximum height allowed for the package.
largura_maximanumberMaximum width allowed.
comprimento_maximonumberMaximum length allowed.
peso_maximonumberMaximum weight allowed.
has_mediabooleanIndicates whether the vehicle type has an image.
mediaobject[]Vehicle type images.

Get vehicle type

GET /v1/tipos-veiculos/{id} 200 404
// 200
{"id": 1, "nome": "Moto"}

// 404
{"mensagem": "Tipo de veículo não encontrado"}

List a vehicle type's categories

GET /v1/tipos-veiculos/{id}/categorias 200 404
Query paramTypeDescription
nomestringFilters by the category's name (LIKE search).

Response fields

FieldTypeDescription
idintegerCategory ID.
nomestringCategory name.
has_mediabooleanIndicates whether the category has an image.
mediaobject[]Category images.
// 404
{"message": "Tipo de veículo não encontrado"}

Webhooks

Instead of polling /orders/{id}, register a webhook URL with the list of events it should receive. On each event, the Platform sends a JSON POST to that URL, with the event name in event. The URL is configured through the endpoints below or in the delivery company's Admin Panel.

Respond fast and process later. We recommend storing the event and responding right away, leaving the processing to a queue on your side. Slow responses, or a return other than 200 or 201, on a recurring basis lead to the webhook URL being deactivated.

Events

Subscribe only to what your integration uses. Each URL receives exactly the events in its eventos list, which can be changed at any time through PATCH /v1/webhooks/{id}.

EventWhen it is sent
ORDER_CREATEDOrder created.
ORDER_SEARCHING_COURIERThe order started searching for a courier (pending), on creation or when it goes back to searching.
ORDER_ACCEPTEDA courier accepted the order (accepted).
COURIER_ASSIGNEDThe order's courier was changed after acceptance. On the acceptance itself, only ORDER_ACCEPTED is sent.
ORDER_ARRIVED_AT_PICKUPThe courier arrived at the pickup location (arrived_pickup_location).
ORDER_COLLECTEDOrder collected (collected).
ORDER_COMPLETEDOrder completed (completed).
ORDER_CANCELLEDOrder cancelled (cancelled).
ORDER_UPDATEDAny other change to the order: data, amounts, stops and the statuses with no event of their own (delivered, preparing…). Changes made in sequence may arrive together in a single delivery.
ORDER_DELETEDOrder deleted.
COURIER_ONLINE planThe courier went online.
COURIER_OFFLINE planThe courier went offline, including because of a block (in that case status comes as blocked).
COURIER_LOCATION_UPDATED planThe courier's position. Sent roughly once a minute per courier, and only when they have moved since the last delivery.
Courier events are available on the Premium and Platina plans, and also during the trial period. Only the hub credential can subscribe to them. The body carries the Courier object in courier.

Headers sent on delivery

HeaderValue
Content-Typeapplication/json
Acceptapplication/json
webhook-securitySecurity code configured in codigo_seguranca (if set). Use it to validate that the request came from the Platform.

Order status (order_status)

StatusDescription
waitingOrder with online payment, awaiting payment (only on orders with online payment).
scheduledOrder scheduled to move to pending in the future.
preparingOrder in preparation (only when the option is enabled for the hub).
pendingSearching for a courier.
acceptedAccepted by a courier.
arrived_pickup_locationCourier at the pickup location.
collectedOrder collected.
deliveredAll deliveries completed; courier on the way back (only on orders with a return).
completedOrder finished successfully.
cancelledOrder cancelled.
Delivery failure. When a delivery fails, the object for that address in delivery_locations_data comes with delivery_failed = true. If the order had no return (need_return_to_pickup_location = false) and the "return on failure" setting is enabled, need_return_to_pickup_location is automatically changed to true.

List webhooks

GET /v1/webhooks 200

Get webhook

GET /v1/webhooks/{id} 200 404

Register webhook

POST /v1/webhooks 201 400 403
FieldTypeDescription
url requiredstringHTTPS URL that will receive the POSTs. Unique per hub.
codigo_segurancastringSecurity code that will be sent in the webhook-security header on each POST. Max 191. Use it to validate the origin of the request.
eventos recommendedstring[]Events the URL will receive (see Events). Without this field, the URL is registered in the legacy format.
// Request
{
  "url": "https://entregas-expressas.teste",
  "codigo_seguranca": "Aas#asdg@fngasd",
  "eventos": ["ORDER_ACCEPTED", "ORDER_COLLECTED", "ORDER_COMPLETED", "ORDER_CANCELLED", "COURIER_LOCATION_UPDATED"]
}

// 400 — validation
{"mensagem": "Erro de validação", "errors": {"url": ["Uma URL de webhook com este endereço já existe"]}}

// 403 — courier event not included in the plan
{"mensagem": "Eventos de entregador estão disponíveis nos planos Premium e Platina"}

Update webhook

Changes the events or the security code of a URL that is already registered. Only the fields you send change. It is also the way to migrate a URL from the legacy format: just send the eventos list.

PATCH /v1/webhooks/{id} 200 400 403 404
// Request
{"eventos": ["ORDER_CREATED", "ORDER_CANCELLED", "COURIER_ONLINE", "COURIER_OFFLINE"]}

Remove webhook

DELETE /v1/webhooks/{id} 200 404
// 200
{"mensagem": "Webhook removido com sucesso"}

// 404
{"mensagem": "Webhook não encontrado"}

Webhook object (response)

FieldTypeDescription
idintegerWebhook URL ID.
urlstringConfigured URL.
codigo_segurancastringSecurity code (sent in the webhook-security header).
eventosstring[]|nullSubscribed events. null indicates a URL in the legacy format.

Payload delivered to your URL

For order events, the delivery is a POST with event + the full Order object (see Order object). Use order_status and the order's date fields as the source of truth: the arrival order between two events is not guaranteed.

{
  "event": "ORDER_ACCEPTED",
  "order": {
    "id": 1234,
    "public_id": "A7K2",
    "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "external_id": null,
    "user_id": 10,
    "started_at": "2025-01-15 10:30:00",
    "pickup_location": "Rua Exemplo, 100 - Centro",
    "pickup_location_data": {
      "latitude": -23.5505,
      "longitude": -46.6333,
      "endereco": "Rua Exemplo, 100 - Centro"
    },
    "delivery_locations_data": [
      {
        "id": "abc123",
        "latitude": -23.5605,
        "longitude": -46.6433,
        "endereco": "Rua Destino, 200 - Bairro",
        "rua": "Rua Destino",
        "numero": "200",
        "bairro": "Bairro",
        "cidade": "Sao Paulo",
        "estado": "SP",
        "complemento": "Apto 101",
        "cep": "01001-000",
        "nome": "Joao Silva",
        "telefone": "(11) 99999-9999",
        "external_id": "123",
        "order_display_id": "PED-001",
        "delivered": false,
        "delivered_date": null,
        "delivery_failed": false,
        "evidence": {
          "photo": "https://exemplo.com/foto.jpg",
          "photos": ["https://exemplo.com/foto.jpg"],
          "signature": null,
          "document": "123.456.789-00",
          "name": "Joao Silva",
          "observation": null
        }
      }
    ],
    "need_return_to_pickup_location": false,
    "need_delivery_proof": false,
    "distance": 5.2,
    "return_distance": 0,
    "total_value": 15.50,
    "customer_observation": "Pedido via integração",
    "valor_pedidos": 89.90,
    "offline_payment_method_id": null,
    "pagamento_faturado": false,
    "payment_gateway": "carteira_digital",
    "gateway_method": null,
    "payment_code": null,
    "payment_base64": null,
    "payment_expiration_date": null,
    "payment_url": null,
    "payment_status": "paid",
    "order_status": "accepted",
    "type": "delivery",
    "status_observation": null,
    "category_id": 1,
    "vehicle_type_id": 1,
    "height": null,
    "length": null,
    "width": null,
    "weight": null,
    "created_at": "2025-01-15T10:30:00.000000Z",
    "updated_at": "2025-01-15T10:35:00.000000Z",
    "accepted_at": "2025-01-15T10:35:00.000000Z",
    "arrived_pickup_location_at": null,
    "arrived_limit_date": null,
    "picked_up_at": null,
    "finished_at": null,
    "collect_limit_date": null,
    "pickup_code": "1234",
    "status": "Aceito",
    "courier": "Carlos Entregador",
    "courier_data": {
      "id": 5,
      "name": "Carlos Entregador",
      "location": {
        "latitude": -23.5510,
        "longitude": -46.6340
      }
    },
    "category": {"id": 1, "name": "Alimentação"},
    "vehicle_type": {"id": 1, "name": "Moto"},
    "user": {
      "id": 10,
      "email": "[email protected]",
      "name": "Restaurante Exemplo",
      "external_id": null
    },
    "tracking_url": "https://entregasexpressas.com.br/tracking/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}

Payload of courier events

event + a subset of the Courier object in courier, the same in all three events, with the status and position at the time of sending: id, name, online, status, last_seen_at, location and active_orders. Vehicle, phone and service types are available at /v1/entregadores/online.

The location is not real time. COURIER_LOCATION_UPDATED is sent roughly once a minute per courier, and only when they have moved since the last delivery: a stationary courier generates no event. Use last_seen_at to know when the position is from.
{
  "event": "COURIER_LOCATION_UPDATED",
  "courier": {
    "id": 12,
    "name": "João Souza",
    "online": true,
    "status": "busy",
    "last_seen_at": "2026-09-28T14:02:11.000000Z",
    "location": {"latitude": -23.5505, "longitude": -46.6333},
    "active_orders": [{"id": 48213, "external_id": "PED-001", "order_status": "collected"}]
  }
}

Legacy format

URLs registered without eventos ("eventos": null in the response) keep working as before, for compatibility: they receive ORDER_CREATED, ORDER_UPDATED (any change of status or of order data) and ORDER_DELETED for all orders, with the same Order object. They do not receive courier events.

New integrations should use the event list. To migrate an existing URL, send eventos on PATCH /v1/webhooks/{id}. If you want the same volume as before, subscribe to all order events.

Order object (full schema)

Schema of the response of the endpoints POST /v1/orders, GET /v1/orders (in data[]), GET /v1/orders/{id}, POST /v1/chamar-entregador and of the webhook payload (in order).

Main fields

FieldTypeDescription
idintegerOrder ID, for API calls.
public_idstringOrder number as people see it on the platform (e.g. "A7K2"). This is the number to display in your system.
uuidstringUniversally unique identifier of the order.
central_idintegerID of the order's central/hub.
external_idstringExternal ID of the order, for reference in your system.
user_idintegerID of the customer who placed the order.
started_atstringDate/time the order started being processed.
order_statusenumwaitingscheduledpreparingpendingacceptedarrived_pickup_locationcollecteddeliveredcompletedcancelled
order_status_datestringDate/time of the last status change.
statusstringTranslated description of the status (e.g., "Aceito").
status_observationstringNote about the status (e.g., cancellation reason).
tracking_urlstringPublic tracking URL (show it to the end consumer).
pickup_codestring?Code the courier presents at pickup (if enabled by the administrator). Nullable.
customer_observationstringFree-text note from the consumer.

Addresses

FieldTypeDescription
pickup_locationstringText description of the pickup address.
pickup_location_dataobjectStructured pickup address.
pickup_location_data.enderecostringDescription of the address.
pickup_location_data.latitudenumberLatitude.
pickup_location_data.longitudenumberLongitude.
pickup_location_data.nomestringContact's name.
pickup_location_data.telefonestringContact's phone number.
pickup_location_data.external_idstringExternal ID of the address.
delivery_locations_dataobject[]List of delivery addresses.
delivery_locations_data[].idstringUnique ID of the stop (generated by the Platform).
delivery_locations_data[].latitudenumberLatitude.
delivery_locations_data[].longitudenumberLongitude.
delivery_locations_data[].enderecostringFull address.
delivery_locations_data[].ruastringStreet.
delivery_locations_data[].numerostringStreet number.
delivery_locations_data[].bairrostringNeighborhood.
delivery_locations_data[].cidadestringCity.
delivery_locations_data[].estadostringState (two-letter code).
delivery_locations_data[].complementostringAddress line 2 (apartment, suite, etc.).
delivery_locations_data[].cepstringPostal code (CEP).
delivery_locations_data[].nomestringRecipient's name.
delivery_locations_data[].telefonestringRecipient's phone number.
delivery_locations_data[].external_idstringExternal ID of the delivery address.
delivery_locations_data[].order_display_idstringDisplay ID of the order at this address.
delivery_locations_data[].codigo_confirmacaostringConfirmation code of the address (if enabled by the administrator).
delivery_locations_data[].deliveredbooleanWhether the address has already been delivered.
delivery_locations_data[].delivered_datestringDate/time of the delivery.
delivery_locations_data[].delivery_failedbooleanWhether the delivery failed. Triggers the auto-flip of need_return_to_pickup_location when applicable (see the callout in Webhooks).
delivery_locations_data[].evidenceobjectProof of delivery collected.
delivery_locations_data[].evidence.photostringPhoto URL.
delivery_locations_data[].evidence.photosstring[]URLs of all photos (the first one is also in photo).
delivery_locations_data[].evidence.signaturestringSignature URL.
delivery_locations_data[].evidence.documentstringRecipient's document number (e.g., CPF).
delivery_locations_data[].evidence.namestringRecipient's name as given.
delivery_locations_data[].evidence.observationstringNote left by the courier.
need_return_to_pickup_locationbooleanIndicates a return to the pickup location. It may be changed automatically to true if a delivery fails and the "return on failure" setting is enabled.
need_delivery_proofbooleanWhether the courier must collect a signature/document at each delivery.
distancenumberTotal distance of the order (km).
return_distancenumberDistance of the return to the pickup location (km).

Package and vehicle

FieldTypeDescription
category_idintegerCategory ID.
vehicle_type_idintegerVehicle type ID.
categoryobjectExpanded category object: { id, name }.
vehicle_typeobjectExpanded vehicle type object: { id, name }.
heightnumberPackage height.
lengthnumberPackage length.
widthnumberPackage width.
weightnumberPackage weight.

Payment

FieldTypeDescription
total_valuenumberTotal amount of the order.
valor_pedidosnumberDeclared value of the goods.
pagamento_faturadobooleanWhether the payment is invoiced by the delivery company.
offline_payment_method_idintegerID of the offline payment method (when applicable).
payment_gatewaystringPayment gateway used (e.g., carteira_digital).
gateway_methodstringGateway-specific method.
payment_codestringPayment code (e.g., Pix copy-and-paste code).
payment_base64stringPayment data in base64 (e.g., Pix QR Code).
payment_urlstringPayment URL.
payment_expiration_datestringPayment expiration date.
payment_statusstringPayment status.

Lifecycle timestamps

FieldTypeDescription
created_atstringCreation date.
updated_atstringDate of the last update.
accepted_atstringWhen the courier accepted.
arrived_pickup_location_atstringWhen the courier arrived at the pickup.
arrived_limit_datestringDeadline for arriving at the pickup before additional charges apply (if configured).
picked_up_atstringWhen the order was collected.
finished_atstringWhen the order was finished.
collect_limit_datestringDeadline for the pickup before additional charges apply (if configured).

Courier

FieldTypeDescription
courierstringCourier's name (shortcut).
courier_dataobjectExpanded courier object.
courier_data.idintegerCourier ID.
courier_data.namestringCourier's name.
courier_data.locationobjectThe courier's real-time location. Sent only while the order is in progress.
courier_data.location.latitudenumberCourier's latitude.
courier_data.location.longitudenumberCourier's longitude.

Order customer (user)

FieldTypeDescription
user.idintegerCustomer ID.
user.namestringName.
user.emailstringEmail.
user.external_idstringExternal ID of the customer in your system.

Courier object

Each item of /v1/entregadores/online carries the full object; the webhook's courier events carry a subset of it in courier (see which fields). The names follow the Order object: id, name and location are the same as in courier_data, and each order in active_orders uses order_status.

FieldTypeIn the webhookDescription
idintegeryesCourier ID, the same as courier_data.id on the order.
namestringyesCourier's name.
phonestring—Phone number.
onlinebooleanyesWhether they are online in the app right now.
statusstringyesavailable (online, no order), busy (online, with an order in progress), offline or blocked (blocked by the company; an order they are still finishing stays in active_orders).
last_seen_atstringyesDate of the last location sent by the app.
locationobject|nullyesCurrent position or the last known one (latitude, longitude).
vehicleobject—model, color and plate.
vehicle_typesobject[]—Service types they handle (id, name), like the order's vehicle_type.
active_ordersobject[]yesOrders in progress with them (id, external_id, order_status). Empty when there are none.
updated_atstring—Date of the last change to the record or to the position.
{
  "id": 12,
  "name": "João Souza",
  "phone": "(11) 99999-8888",
  "online": true,
  "status": "busy",
  "last_seen_at": "2026-09-28T14:02:11.000000Z",
  "location": {"latitude": -23.5505, "longitude": -46.6333},
  "vehicle": {"model": "Honda CG 160", "color": "Vermelho", "plate": "ABC1D23"},
  "vehicle_types": [{"id": 1, "name": "Moto"}],
  "active_orders": [{"id": 48213, "external_id": "PED-001", "order_status": "collected"}],
  "updated_at": "2026-09-28T14:02:11.000000Z"
}

Error codes

HTTPWhen
200/201Success. 201 on creation.
400Malformed request (invalid JSON, missing required fields).
401API key missing, invalid or deactivated.
403Valid API key but without permission for this resource (e.g., a sub-user with restricted permission).
404Order/user/resource not found.
422Business rule validation failed (e.g., cancelling an order that was already delivered, invalid status).
500Internal error — retry with backoff.

Error responses follow the Platform's standard — the message is in mensagem (not message):

{
  "mensagem": "Erro de validação",
  "errors": {
    "tipo_veiculo_id": ["O campo tipo_veiculo_id é obrigatório"]
  }
}

On lookup routes, not-found comes as {"mensagem": "Pedido não encontrado"} (likewise for user, webhook, vehicle type). The categories endpoint, however, uses message ({"message": "Tipo de veículo não encontrado"}) — a small inherited inconsistency.

Using the developer Dashboard

The full test cycle happens in the Portal. Each Full app automatically gets:

Step by step

  1. Create a Full app in the Dashboard.
  2. Credentials tab: copy the Bearer Token and use it in the Authorization header.
  3. Webhook tab: paste your HTTPS URL to receive events during testing.
  4. Make calls from your system/cURL/Postman. Each request shows up in Inspection within seconds.
  5. Use the Access the app's sandbox platform button to see the created order from the company's side (map, assignment, finance) — useful for debugging behavior that depends on rules configured by the company.

Create / access my apps   See the OpenDelivery guide