Sandbox
Ambiente isolado pra testar sua integração com a API Motoxpress sem afetar dados reais. Mesma API de produção, banco e credenciais separados, com simulador de motorista que progride os status automaticamente em ~5 minutos.
Funciona pros 2 caminhos de integração: Open Delivery (Abrasel) e API Motoxpress v1 proprietária. Escolha um modo abaixo.
Escolha o modo
Modo OD (Open Delivery)
Spec aberta da Abrasel. Mesmo formato usado por iFood, Aiqfome, Metre, Sischef. Webhooks em formato canônico (DRIVER_DISPATCHED, AT_PICKUP_LOCATION, etc).
Callback: setado no callbackUrl do payload de cada request.
Modo v1 (proprietária)
Mais campos (valor, distância, código humano), webhooks em formato Motoxpress (corrida.aceita, corrida.coletada, etc). Pra quando OD ficar curto.
Callback: setado uma única vez no webhook_url da api_key.
webhook_url na key E criar via endpoint OD, vai receber 2 webhooks duplicados por evento (um no formato OD, outro no formato v1). Use 1 key por modo.1. Endpoint
https://api.dev.motoxpress.app/v1
Mesmo base URL para os 2 modos. O routing acontece pelo path:
- OD:
POST /v1/orders/{orderId}/deliveries,GET /v1/deliveries/{id}, etc - v1:
POST /v1/corridas,GET /v1/corridas/{id},POST /v1/corridas/{id}/cancelar, etc
2. Credenciais
Envie um email para parceiros@motoxpress.app informando:
- Nome da empresa + CNPJ
- Volume estimado de pedidos/mês
- Modo desejado (OD, v1 ou ambos — receberá 1 key por modo)
- Pra modo v1: URL do seu endpoint de webhook (ex:
https://seu-sistema.com/webhooks/motoxpress)
Liberamos credenciais em até 1 dia útil. Token vem no formato mx_test_xxxxxxxx. Use no header Authorization: Bearer mx_test_xxx.
3. Simulador de motorista
Toda corrida criada no sandbox (independente do modo) passa pelos status em ondas. Não precisa de app entregador rodando.
| Tempo | Status interno | Evento OD | Evento v1 |
|---|---|---|---|
| T+0 | aguardando_aceite | — | corrida.criada |
| T+1min | aceita | DRIVER_DISPATCHED | corrida.aceita |
| T+2min | aguardando_coleta | AT_PICKUP_LOCATION | corrida.aguardando_coleta |
| T+3min | coletada | GOT_PICKUP | corrida.coletada |
| T+5min | entregue | CONCLUDED | corrida.entregue |
Total ~5min do criar ao entregue. Cron sandbox-progress roda a cada 1min; mudanças de status disparam webhooks via webhook-dispatcher (também 1min). Latência observada entre criar e primeiro evento: até 2 minutos.
4. Formato dos webhooks
Modo OD
POST <callbackUrl-do-payload>
Headers:
X-Motoxpress-Event: od.driver_dispatched
X-Motoxpress-Signature: sha256=<hmac do body>
X-Motoxpress-Delivery: <uuid>
Body:
{
"tipo": "od.driver_dispatched",
"dados": {
"fullCode": "DRIVER_DISPATCHED",
"orderId": "ORD-001",
"occurredAt": "2026-06-01T12:01:00Z",
"driverInfo": {
"name": "Sandbox",
"phone": "5500000000000"
}
}
}Modo v1
POST <webhook_url-da-api_key>
Headers:
X-Motoxpress-Event: corrida.aceita
X-Motoxpress-Signature: sha256=<hmac do body>
X-Motoxpress-Delivery: <uuid>
Body:
{
"tipo": "corrida.aceita",
"dados": {
"id": "uuid",
"codigo": "MX1234",
"status": "aceita",
"lojista_id": "...",
"entregador_id": "00000000-0000-0000-0000-0000005a4dee",
"cliente_nome": "Maria", // primeiro nome se mascarado
"cliente_telefone": "****0001", // últimos 4 dígitos por default
"entrega_bairro": "Caicaras",
"entrega_cep": "38700100",
"valor_entrega_cent": 1200,
"distancia_km": 2.3,
"eta_min": 8,
"criada_em": "...",
"aceita_em": "...",
"evento_em": "2026-06-01T12:01:00Z"
}
}PII mascarada por default (mascarar_pii_webhook=true). Pra receber telefone completo, peça mascarar_pii_webhook=false ao solicitar credenciais (exige consentimento explícito por LGPD).
5. Validar assinatura HMAC
Os 2 modos usam o mesmo esquema: HMAC-SHA256 do body bruto, com o webhook_secret enviado junto da sua credencial. Header X-Motoxpress-Signature: sha256=<hex>.
// Node.js
import crypto from 'crypto';
function validateSignature(rawBody, signatureHeader, secret) {
const expected = crypto.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const received = signatureHeader.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(received, 'hex'),
);
}Use timingSafeEqual pra evitar timing attack. Rejeite eventos com assinatura inválida. Política de retry: 1min → 5min → 30min → 3h (5 tentativas, depois desistido).
6. Exemplo cURL — Modo OD
# Criar delivery (callbackUrl no payload)
curl -X POST "https://api.dev.motoxpress.app/v1/orders/ORD-001/deliveries" \
-H "Authorization: Bearer mx_test_xxxx" \
-H "X-Request-Id: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"callbackUrl": "https://seu-receiver.com/webhooks/od",
"customer": { "name": "Maria", "phone": "5534999990001" },
"pickup": {
"merchantName": "Loja Teste",
"address": {
"streetName": "Rua Major Gote", "streetNumber": "123",
"neighborhood": "Centro", "city": "Patos de Minas",
"state": "MG", "postalCode": "38700000",
"coordinates": { "latitude": -18.574, "longitude": -46.515 }
}
},
"deliveryAddress": {
"streetName": "Av JK", "streetNumber": "999",
"neighborhood": "Caicaras", "city": "Patos de Minas",
"state": "MG", "postalCode": "38700100",
"coordinates": { "latitude": -18.585, "longitude": -46.520 }
},
"payment": { "method": "PIX", "amount": 5000 }
}'
# Resposta 201: { "id": "uuid", "trackingCode": "MX1234", "status": "WAITING_DRIVER", ... }
# Consultar status
curl "https://api.dev.motoxpress.app/v1/deliveries/<id>" \
-H "Authorization: Bearer mx_test_xxxx"
# Cancelar
curl -X POST "https://api.dev.motoxpress.app/v1/deliveries/<id>/cancel" \
-H "Authorization: Bearer mx_test_xxxx" \
-H "Content-Type: application/json" \
-d '{"reason": "lojista mudou de ideia"}'7. Exemplo cURL — Modo v1
# Criar corrida (webhook_url já vinculado à api_key — não passa aqui)
curl -X POST "https://api.dev.motoxpress.app/v1/corridas" \
-H "Authorization: Bearer mx_test_xxxx" \
-H "Content-Type: application/json" \
-d '{
"cliente_nome": "Maria",
"cliente_telefone": "5534999990001",
"entrega_rua": "Av JK",
"entrega_numero": "999",
"entrega_bairro": "Caicaras",
"entrega_cidade": "Patos de Minas",
"entrega_uf": "MG",
"entrega_cep": "38700100",
"entrega_lat": -18.585,
"entrega_lng": -46.520,
"metodo_pagamento": "pix",
"valor_pedido_cent": 5000,
"idempotency_key": "550e8400-e29b-41d4-a716-446655440000"
}'
# Resposta 201: { "id": "uuid", "codigo": "MX1234", "status": "aguardando_aceite",
# "valor_entrega_cent": 800, "distancia_km": 2.3, "eta_min": 8, ... }
# Listar suas corridas
curl "https://api.dev.motoxpress.app/v1/corridas?status=aceita&limit=20" \
-H "Authorization: Bearer mx_test_xxxx"
# Consultar uma
curl "https://api.dev.motoxpress.app/v1/corridas/<id>" \
-H "Authorization: Bearer mx_test_xxxx"
# Cancelar (só em aguardando_aceite)
curl -X POST "https://api.dev.motoxpress.app/v1/corridas/<id>/cancelar" \
-H "Authorization: Bearer mx_test_xxxx"8. Limites e dicas
- Dados de teste podem ser deletados a qualquer momento sem aviso
- Rate limit: 120 req/min por token (igual prod — sandbox não restringe mais)
- Webhook precisa de URL pública — use webhook.site, ngrok ou smee.io em dev local
- Lat/lng do entregador sandbox é fixa (centro de Patos de Minas) — apenas o status progride, motorista não "anda"
- Idempotency: passe
X-Request-Id(UUID v4) em OD ouidempotency_keyno body em v1 — retry seguro - Cancelar via OD funciona em qualquer status pré-final; via v1 só em
aguardando_aceite