← voltar

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

recomendado pra integradores ERP

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.

features motoxpress-only

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.

⚠️ Não misture os 2 modos numa única api_key. Se você setar 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:

2. Credenciais

Envie um email para parceiros@motoxpress.app informando:

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.

TempoStatus internoEvento ODEvento v1
T+0aguardando_aceitecorrida.criada
T+1minaceitaDRIVER_DISPATCHEDcorrida.aceita
T+2minaguardando_coletaAT_PICKUP_LOCATIONcorrida.aguardando_coleta
T+3mincoletadaGOT_PICKUPcorrida.coletada
T+5minentregueCONCLUDEDcorrida.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