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.
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:
- The delivery company gives you the API key (Bearer token).
- You use POST /v1/orders/calcular to simulate price and distance before the consumer confirms.
- You create the order with POST /v1/orders (or do everything in a single call with POST /v1/chamar-entregador).
- 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
🔑 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:
| Key | What 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.
Request body
| Field | Type | Description |
|---|---|---|
tipo_veiculo_id required | integer | Vehicle Type ID (see /v1/tipos-veiculos). |
categoria_id | integer | ID of the vehicle type's Category (/v1/tipos-veiculos/{id}/categorias). |
endereco_coleta required | object | Pickup address object — see the schema below. |
endereco_coleta.endereco required | string | Text description of the address. If latitude/longitude are not sent, we geocode from this. |
endereco_coleta.latitude | number | Latitude. Required if you do not send the text address. |
endereco_coleta.longitude | number | Longitude. Required if you do not send the text address. |
endereco_coleta.nome | string | Name of the contact at the pickup. |
endereco_coleta.telefone | string | Contact's phone number. |
enderecos_entrega required | object[] | Array of delivery addresses, minimum 1. |
enderecos_entrega[].endereco required | string | Description of the delivery address. |
enderecos_entrega[].latitude | number | Latitude of the address. |
enderecos_entrega[].longitude | number | Longitude of the address. |
enderecos_entrega[].nome | string | Recipient's name. |
enderecos_entrega[].telefone | string | Recipient's phone number. |
cliente_id | integer | Customer ID (required if the cliente object is not sent). |
dimensoes_pacote | object | Package dimensions — may be required for some vehicle types. |
dimensoes_pacote.peso | number | Package weight. |
dimensoes_pacote.largura | number | Package width. |
dimensoes_pacote.altura | number | Package height. |
dimensoes_pacote.comprimento | number | Package length. |
retorno_necessario | boolean | Whether the courier must return to the pickup location after the last delivery. |
prova_entrega_necessaria | boolean | Whether 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
| Field | Type | Description |
|---|---|---|
preco | number | Order price (gross). |
distancia | number | Distance in km from the pickup address to the last delivery address (or the return, if applicable). |
precoDescricao | string | Price formatted in R$. |
distanciaDescricao | string | Formatted 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.
Request body
| Field | Type | Description |
|---|---|---|
tipo_veiculo_id required | integer | Vehicle Type ID. |
categoria_id | integer | Category ID. |
endereco_coleta required | object | Same schema as /calcular, plus external_id (string). |
endereco_coleta.external_id | string | External ID of the address in your system. |
enderecos_entrega required | object[] | Same schema as /calcular, plus external_id and order_display_id. |
enderecos_entrega[].external_id | string | External ID of the delivery address. |
enderecos_entrega[].order_display_id | string | Display ID of the order associated with the address (visible when external ID display is enabled). |
cliente_id | integer | Customer ID. Required if you do not send the cliente object. |
cliente | object | Creates the user inline. Required if you do not send cliente_id. |
cliente.nome required with cliente | string | Customer's name. |
cliente.email required with cliente | string | Customer's email. |
cliente.telefone required with cliente | string | Customer's phone number. |
cliente.senha required with cliente | string | Password (minimum 6 characters). |
external_id | string | External ID of the order, for reference in your system. It appears in every subsequent webhook. |
dimensoes_pacote | object | Package dimensions: peso, largura, altura, comprimento (see /calcular). |
retorno_necessario | boolean | Return to the pickup location after the last delivery. |
prova_entrega_necessaria | boolean | Collect a photo/signature/document at each delivery. |
observacao | string | Free-text note for the order (the courier sees it in the app). |
metodo_pagamento | enum | faturadocarteira — default: faturado. |
status_inicial | enum | pendingpreparing — pending searches for a courier immediately; preparing keeps the order in preparation. Default: pending. |
agendamento_segundos | integer | Seconds from now to schedule the order. When sent, status_inicial is ignored and the order enters as scheduled. |
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.
Query string
| Param | Type | Description |
|---|---|---|
page | integer | Page number (default: 1). |
limit | integer | Items per page (max: 100, default: 50). |
id | integer | Filter by order ID (direct lookup, no pagination). |
public_id | string | Filter by order number (public_id, direct lookup, no pagination). |
external_id | string | Filter 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.
URL params
| Param | Type | Description |
|---|---|---|
order required | integer | string | Order 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).
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.
Request body
| Field | Type | Description |
|---|---|---|
cliente_id | integer | Customer ID. Required if you do not send the cliente object. |
cliente | object | Creates the user inline. Required if you do not send cliente_id. |
cliente.nome required with cliente | string | Customer's name. |
cliente.email required with cliente | string | Customer's email. |
cliente.telefone required with cliente | string | Customer's phone number. |
cliente.senha required with cliente | string | Password (minimum 6 characters). |
endereco_coleta required | object | Pickup address, with endereco, latitude and longitude required. |
num_locais_entrega required | integer | Number of delivery locations the courier will enter. |
tipo_veiculo_id | integer | Vehicle Type ID. |
retorno_necessario | boolean | Return to the pickup location. |
prova_entrega | boolean | Collect proof of delivery. |
observacao | string | Order note. |
metodo_pagamento | enum | faturadocarteira_digital |
status_inicial | enum | pendingpreparing — default pending. |
agendamento_segundos | integer | Seconds 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
| Query param | Type | Description |
|---|---|---|
email | string | Filter by the user's email. |
external_id | string | Filter by the user's external ID. |
Get user
// 404
{"mensagem": "Usuário não encontrado"}
Create user
| Field | Type | Description |
|---|---|---|
nome required | string | User's name (max 191). |
email required | string | Email (unique per customer). |
senha required | string | Password (minimum 6, max 191). |
telefone required | string | Phone number (max 191). |
external_id | string | External 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.
| Field | Type | Description |
|---|---|---|
nome | string | New name. |
telefone | string | New phone number. |
external_id | string | New external ID. |
senha | string | New password (minimum 6). |
bloqueado | boolean | Blocks 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)
| Field | Type | Description |
|---|---|---|
data.id | integer | User ID. |
data.nome | string | User's name. |
data.email | string | User's email. |
data.telefone | string | User's phone number. |
data.external_id | string | External ID in your system. |
data.faturamento | boolean | Indicates whether invoicing is enabled for the user. |
data.saldo | number | Digital wallet balance. |
data.bloqueado | boolean | Indicates whether the customer is blocked from placing orders. |
data.has_media | boolean | Indicates whether the user has an image. |
data.media | object[] | User's images. |
data.data_criacao | string | Date 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.
| Field | Type | Description |
|---|---|---|
nome required | string | User's name. |
email required | string | User's email. |
senha required | string | User's password. |
telefone required | string | User'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.
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.
| Endpoint | What it does |
|---|---|
GET /v1/usuarios/{id}/carteira | Customer's current balance. |
GET /v1/usuarios/{id}/carteira/transacoes | Customer's statement, paginated. |
POST /v1/usuarios/{id}/carteira/creditos | Adds balance. |
POST /v1/usuarios/{id}/carteira/debitos | Removes balance. |
POST /v1/usuarios/{id}/carteira/recargas | Records a top-up that has already been paid, with the fee. |
GET /v1/entregadores/{id}/carteira | Courier's current balance. |
GET /v1/entregadores/{id}/carteira/transacoes | Courier's statement, paginated. |
POST /v1/entregadores/{id}/carteira/creditos | Adds balance. |
POST /v1/entregadores/{id}/carteira/debitos | Removes balance. |
POST /v1/entregadores/{id}/carteira/recargas | Records 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.
- First call: 201 with
"duplicada": false. - Retry with the same
external_id: 200 with"duplicada": trueand the same entry — nothing is created, nothing is added.
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
// 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
| Query param | Type | Description |
|---|---|---|
operacao | enum | creditodebito |
external_id | string | Finds the entry by its idempotency key — this is how you check whether a POST that timed out went through. |
por_pagina | integer | 1 to 200. Default 50. |
pagina | integer | Default 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).
| Field | Type | Description |
|---|---|---|
valor required | number | Greater than zero. Two decimal places. |
descricao | string | Text shown on the statement (max 191). Left blank, it becomes -. |
external_id | string | Idempotency 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
| Field | Type | Description |
|---|---|---|
valor required | number | Greater than zero. |
descricao | string | Text shown on the statement. |
external_id | string | Idempotency key. |
permitir_saldo_negativo | boolean | Default 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:
- the payment method is required and is stored on the statement;
- the top-up fee configured by the delivery company is applied by default — the same one that applies when the payment arrives through the gateway. It becomes a debit of its own, linked to the top-up, and shows on the statement as "Taxa de recarga" (top-up fee).
| Field | Type | Description |
|---|---|---|
valor required | number | Greater than zero. |
forma_pagamento required | enum | pixboletocredit_carddinheirotransferenciaoutro |
descricao | string | Text shown on the statement. |
external_id | string | Idempotency key. |
aplicar_taxa | boolean | Default 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).
- The courier's balance goes negative in normal use of the operation — that is how the app's commission is charged to them. That is why the debit does not check the balance by default.
- On the courier's
carteira/recargasthere is no fee: the top-up fee is configured for the customer and does not describe a courier's deposit.forma_pagamentois still required, so the statement says where the money came from.
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.
List couriers
| Query param | Type | Description |
|---|---|---|
email | string | Filter by email. |
telefone | string | Filter by phone number. |
cpf | string | Filter by document number. |
placa | string | Filter by the vehicle's license plate. |
ativo | boolean | Working in the app right now. |
bloqueado | boolean | Blocked or not blocked. |
aprovado | boolean | Registration approved or not. |
por_pagina | integer | 1 to 200. Default 50. |
pagina | integer | Default 1. |
Entregador object (response)
| Field | Type | Description |
|---|---|---|
id | integer | Courier ID — this is what the wallet and block endpoints take. |
nome | string | Courier's name. |
email | string | Email. |
telefone | string | Phone number. |
cpf | string | Document number. |
ativo | boolean | Whether they are working in the app right now. They are the one who turns this on and off, in the app. |
aprovado | boolean | Whether the registration was approved by the company. |
bloqueado | boolean | Whether they are blocked. |
bloqueado_ate | string | Date of the automatic unblock, if any. |
veiculo | object | modelo, cor and placa. |
tipos_servico | object[] | Service types they handle (id, nome). |
saldo | number | Their wallet balance. |
saque_bloqueado | boolean | Whether wallet withdrawals are blocked. See Block withdrawals. |
data_criacao | string | Date 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.
| Query param | Type | Description |
|---|---|---|
status | string | available or busy. Without it, both are returned. |
por_pagina | integer | 1 to 200. Default 50. |
pagina | integer | Default 1. |
Get courier
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.
| Field | Type | Description |
|---|---|---|
bloqueado_ate | string | Date/time of the automatic unblock (ISO 8601), in the future. Without it, the block lasts until someone unblocks. |
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.
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
| Query param | Type | Description |
|---|---|---|
nome | string | Filters by the vehicle type's name (LIKE search). |
Response fields
| Field | Type | Description |
|---|---|---|
id | integer | Vehicle type ID. |
nome | string | Vehicle type name. |
peso_e_dimensoes | boolean | Indicates whether the vehicle type requires the package's weight/dimensions. |
limitar_peso_e_dimensoes | boolean | Indicates whether weight/dimensions are limited (orders above the maximums are rejected). |
altura_maxima | number | Maximum height allowed for the package. |
largura_maxima | number | Maximum width allowed. |
comprimento_maximo | number | Maximum length allowed. |
peso_maximo | number | Maximum weight allowed. |
has_media | boolean | Indicates whether the vehicle type has an image. |
media | object[] | Vehicle type images. |
Get vehicle type
// 200
{"id": 1, "nome": "Moto"}
// 404
{"mensagem": "Tipo de veículo não encontrado"}
List a vehicle type's categories
| Query param | Type | Description |
|---|---|---|
nome | string | Filters by the category's name (LIKE search). |
Response fields
| Field | Type | Description |
|---|---|---|
id | integer | Category ID. |
nome | string | Category name. |
has_media | boolean | Indicates whether the category has an image. |
media | object[] | 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.
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}.
| Event | When it is sent |
|---|---|
ORDER_CREATED | Order created. |
ORDER_SEARCHING_COURIER | The order started searching for a courier (pending), on creation or when it goes back to searching. |
ORDER_ACCEPTED | A courier accepted the order (accepted). |
COURIER_ASSIGNED | The order's courier was changed after acceptance. On the acceptance itself, only ORDER_ACCEPTED is sent. |
ORDER_ARRIVED_AT_PICKUP | The courier arrived at the pickup location (arrived_pickup_location). |
ORDER_COLLECTED | Order collected (collected). |
ORDER_COMPLETED | Order completed (completed). |
ORDER_CANCELLED | Order cancelled (cancelled). |
ORDER_UPDATED | Any 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_DELETED | Order deleted. |
COURIER_ONLINE plan | The courier went online. |
COURIER_OFFLINE plan | The courier went offline, including because of a block (in that case status comes as blocked). |
COURIER_LOCATION_UPDATED plan | The courier's position. Sent roughly once a minute per courier, and only when they have moved since the last delivery. |
courier.
Headers sent on delivery
| Header | Value |
|---|---|
Content-Type | application/json |
Accept | application/json |
webhook-security | Security code configured in codigo_seguranca (if set). Use it to validate that the request came from the Platform. |
Order status (order_status)
| Status | Description |
|---|---|
waiting | Order with online payment, awaiting payment (only on orders with online payment). |
scheduled | Order scheduled to move to pending in the future. |
preparing | Order in preparation (only when the option is enabled for the hub). |
pending | Searching for a courier. |
accepted | Accepted by a courier. |
arrived_pickup_location | Courier at the pickup location. |
collected | Order collected. |
delivered | All deliveries completed; courier on the way back (only on orders with a return). |
completed | Order finished successfully. |
cancelled | Order cancelled. |
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 webhook
Register webhook
| Field | Type | Description |
|---|---|---|
url required | string | HTTPS URL that will receive the POSTs. Unique per hub. |
codigo_seguranca | string | Security 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 recommended | string[] | 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.
// Request
{"eventos": ["ORDER_CREATED", "ORDER_CANCELLED", "COURIER_ONLINE", "COURIER_OFFLINE"]}
Remove webhook
// 200
{"mensagem": "Webhook removido com sucesso"}
// 404
{"mensagem": "Webhook não encontrado"}
Webhook object (response)
| Field | Type | Description |
|---|---|---|
id | integer | Webhook URL ID. |
url | string | Configured URL. |
codigo_seguranca | string | Security code (sent in the webhook-security header). |
eventos | string[]|null | Subscribed 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.
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.
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
| Field | Type | Description |
|---|---|---|
id | integer | Order ID, for API calls. |
public_id | string | Order number as people see it on the platform (e.g. "A7K2"). This is the number to display in your system. |
uuid | string | Universally unique identifier of the order. |
central_id | integer | ID of the order's central/hub. |
external_id | string | External ID of the order, for reference in your system. |
user_id | integer | ID of the customer who placed the order. |
started_at | string | Date/time the order started being processed. |
order_status | enum | waitingscheduledpreparingpendingacceptedarrived_pickup_locationcollecteddeliveredcompletedcancelled |
order_status_date | string | Date/time of the last status change. |
status | string | Translated description of the status (e.g., "Aceito"). |
status_observation | string | Note about the status (e.g., cancellation reason). |
tracking_url | string | Public tracking URL (show it to the end consumer). |
pickup_code | string? | Code the courier presents at pickup (if enabled by the administrator). Nullable. |
customer_observation | string | Free-text note from the consumer. |
Addresses
| Field | Type | Description |
|---|---|---|
pickup_location | string | Text description of the pickup address. |
pickup_location_data | object | Structured pickup address. |
pickup_location_data.endereco | string | Description of the address. |
pickup_location_data.latitude | number | Latitude. |
pickup_location_data.longitude | number | Longitude. |
pickup_location_data.nome | string | Contact's name. |
pickup_location_data.telefone | string | Contact's phone number. |
pickup_location_data.external_id | string | External ID of the address. |
delivery_locations_data | object[] | List of delivery addresses. |
delivery_locations_data[].id | string | Unique ID of the stop (generated by the Platform). |
delivery_locations_data[].latitude | number | Latitude. |
delivery_locations_data[].longitude | number | Longitude. |
delivery_locations_data[].endereco | string | Full address. |
delivery_locations_data[].rua | string | Street. |
delivery_locations_data[].numero | string | Street number. |
delivery_locations_data[].bairro | string | Neighborhood. |
delivery_locations_data[].cidade | string | City. |
delivery_locations_data[].estado | string | State (two-letter code). |
delivery_locations_data[].complemento | string | Address line 2 (apartment, suite, etc.). |
delivery_locations_data[].cep | string | Postal code (CEP). |
delivery_locations_data[].nome | string | Recipient's name. |
delivery_locations_data[].telefone | string | Recipient's phone number. |
delivery_locations_data[].external_id | string | External ID of the delivery address. |
delivery_locations_data[].order_display_id | string | Display ID of the order at this address. |
delivery_locations_data[].codigo_confirmacao | string | Confirmation code of the address (if enabled by the administrator). |
delivery_locations_data[].delivered | boolean | Whether the address has already been delivered. |
delivery_locations_data[].delivered_date | string | Date/time of the delivery. |
delivery_locations_data[].delivery_failed | boolean | Whether the delivery failed. Triggers the auto-flip of need_return_to_pickup_location when applicable (see the callout in Webhooks). |
delivery_locations_data[].evidence | object | Proof of delivery collected. |
delivery_locations_data[].evidence.photo | string | Photo URL. |
delivery_locations_data[].evidence.photos | string[] | URLs of all photos (the first one is also in photo). |
delivery_locations_data[].evidence.signature | string | Signature URL. |
delivery_locations_data[].evidence.document | string | Recipient's document number (e.g., CPF). |
delivery_locations_data[].evidence.name | string | Recipient's name as given. |
delivery_locations_data[].evidence.observation | string | Note left by the courier. |
need_return_to_pickup_location | boolean | Indicates 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_proof | boolean | Whether the courier must collect a signature/document at each delivery. |
distance | number | Total distance of the order (km). |
return_distance | number | Distance of the return to the pickup location (km). |
Package and vehicle
| Field | Type | Description |
|---|---|---|
category_id | integer | Category ID. |
vehicle_type_id | integer | Vehicle type ID. |
category | object | Expanded category object: { id, name }. |
vehicle_type | object | Expanded vehicle type object: { id, name }. |
height | number | Package height. |
length | number | Package length. |
width | number | Package width. |
weight | number | Package weight. |
Payment
| Field | Type | Description |
|---|---|---|
total_value | number | Total amount of the order. |
valor_pedidos | number | Declared value of the goods. |
pagamento_faturado | boolean | Whether the payment is invoiced by the delivery company. |
offline_payment_method_id | integer | ID of the offline payment method (when applicable). |
payment_gateway | string | Payment gateway used (e.g., carteira_digital). |
gateway_method | string | Gateway-specific method. |
payment_code | string | Payment code (e.g., Pix copy-and-paste code). |
payment_base64 | string | Payment data in base64 (e.g., Pix QR Code). |
payment_url | string | Payment URL. |
payment_expiration_date | string | Payment expiration date. |
payment_status | string | Payment status. |
Lifecycle timestamps
| Field | Type | Description |
|---|---|---|
created_at | string | Creation date. |
updated_at | string | Date of the last update. |
accepted_at | string | When the courier accepted. |
arrived_pickup_location_at | string | When the courier arrived at the pickup. |
arrived_limit_date | string | Deadline for arriving at the pickup before additional charges apply (if configured). |
picked_up_at | string | When the order was collected. |
finished_at | string | When the order was finished. |
collect_limit_date | string | Deadline for the pickup before additional charges apply (if configured). |
Courier
| Field | Type | Description |
|---|---|---|
courier | string | Courier's name (shortcut). |
courier_data | object | Expanded courier object. |
courier_data.id | integer | Courier ID. |
courier_data.name | string | Courier's name. |
courier_data.location | object | The courier's real-time location. Sent only while the order is in progress. |
courier_data.location.latitude | number | Courier's latitude. |
courier_data.location.longitude | number | Courier's longitude. |
Order customer (user)
| Field | Type | Description |
|---|---|---|
user.id | integer | Customer ID. |
user.name | string | Name. |
user.email | string | Email. |
user.external_id | string | External 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.
| Field | Type | In the webhook | Description |
|---|---|---|---|
id | integer | yes | Courier ID, the same as courier_data.id on the order. |
name | string | yes | Courier's name. |
phone | string | — | Phone number. |
online | boolean | yes | Whether they are online in the app right now. |
status | string | yes | available (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_at | string | yes | Date of the last location sent by the app. |
location | object|null | yes | Current position or the last known one (latitude, longitude). |
vehicle | object | — | model, color and plate. |
vehicle_types | object[] | — | Service types they handle (id, name), like the order's vehicle_type. |
active_orders | object[] | yes | Orders in progress with them (id, external_id, order_status). Empty when there are none. |
updated_at | string | — | 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
| HTTP | When |
|---|---|
| 200/201 | Success. 201 on creation. |
| 400 | Malformed request (invalid JSON, missing required fields). |
| 401 | API key missing, invalid or deactivated. |
| 403 | Valid API key but without permission for this resource (e.g., a sub-user with restricted permission). |
| 404 | Order/user/resource not found. |
| 422 | Business rule validation failed (e.g., cancelling an order that was already delivered, invalid status). |
| 500 | Internal 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:
- A sandbox hub (Central) isolated from the real operation.
- An admin user for that hub, which you can access through the Access the app's sandbox platform button (at the top of the app page or in the Credentials tab) — useful to see how things look through the administrator's eyes.
- An admin test token, valid only inside that hub.
- An Inspection tab with every request you make (body, response, headers, status).
Step by step
- Create a Full app in the Dashboard.
- Credentials tab: copy the
Bearer Tokenand use it in theAuthorizationheader. - Webhook tab: paste your HTTPS URL to receive events during testing.
- Make calls from your system/cURL/Postman. Each request shows up in Inspection within seconds.
- 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.