📡 Rally Partner Webhook Spec

v1.3.0 · atualizado 2026-05-18 · acesso público · JSON ⇩

Documentação técnica do padrão Partner Integrations do Rally de Vendas. Use esse spec pra construir integrações bidirecionais com o Rally: transportadoras, fulfillment, ERP, BI, atendimento, AI, etc.

Referência viva em produção: Frete.Center auto-despacho Flex Mercado Livre.

Índice

1. Conceito

O padrão Partner Integrations conecta um serviço externo ao Rally com:

  1. Vínculo por código de convite — você gera um código 8-char no seu painel, manda pro cliente, ele cola no Rally → vínculo estabelecido em 1 clique. Sem catálogo público.
  2. Eventos Rally → você — quando o cliente recebe um pedido (ou outro trigger), o Rally chama um endpoint seu.
  3. Atualizações você → Rally — você notifica mudanças de status via webhook reverso.
  4. Cobrança P2P — opcional. PIX direto cliente↔você. O Rally só exibe sua chave PIX e armazena comprovantes; nunca movimenta dinheiro.

2. Autenticação — HMAC SHA-256

Todos os webhooks Rally ↔ parceiro usam HMAC SHA-256 sobre o body raw. O secret de 64 chars é compartilhado nos dois lados via .env.

Headers obrigatórios

X-Rally-Signature: sha256=<hex_digest>
X-Rally-Timestamp: <unix_seconds>
Content-Type: application/json

Cálculo da assinatura

signature = "sha256=" + hex(hmac_sha256(SHARED_SECRET, RAW_BODY))

Anti-replay (5 minutos)

Toda request precisa de timestamp dentro de ±300s do time() do receptor. Fora disso = 401 stale_timestamp.

⚠️ Nunca assine o JSON serializado de novo no receptor — pode ter diferenças de whitespace/encoding. Sempre assine/verifique sobre o body raw exato.

3. Webhooks que o Rally RECEBE de você

Esses três endpoints estão prontos no Rally e esperam HMAC + timestamp:

EndpointBodyQuando enviar
POST /webhooks/{partner-name}/status
{
  "rally_user_id": "...",
  "dispatch_id": "your_external_id",
  "status": "accepted|picked_up|in_transit|delivered|refused|cancelled",
  "note": "..."
}
Job mudou de status
POST /webhooks/{partner-name}/invite-code
{
  "code": "ABC12345",
  "carrier_id": "...",
  "carrier_name": "...",
  "expires_at": "2026-05-21T13:00:00-03:00"
}
Você gerou novo código (push)
POST /webhooks/{partner-name}/payment-confirmed
{
  "rally_user_id": "...",
  "rally_dispatch_id": "..."
}
Você confirmou PIX recebido

Substitua {partner-name} pelo identificador do seu sistema (ex: frete-center, shopee-flash). Combine com a equipe Rally na hora do onboarding.

4. Endpoints que VOCÊ precisa expor

O Rally vai consumir esses endpoints com a mesma autenticação HMAC (você verifica do mesmo jeito que o Rally verifica os seus webhooks).

Método + Path (sugestão)Body / QueryRetorno esperado
GET /api/v1/carriers/by-invite-code?code=XXX code (8 chars)
{
  "carrier_id": "...",
  "carrier_name": "...",
  "pix_key": "...",
  "pix_key_type": "cnpj|email|phone|random",
  "logo_url": "https://...",
  "expires_at": "..."
}
GET /api/v1/quote?carrier_id&cep_o&cep_d&peso_g&pacotes parâmetros query
{
  "price": 12.50,
  "currency": "BRL",
  "eta_hours": 2
}
POST /api/v1/dispatch
{
  "external_order_id": "...",
  "ml_shipment_id": "...",
  "carrier_id": "...",
  "pickup_point_id": "...",
  "buyer_address": {...},
  "package": {"weight_g": 500, "dimensions_cm": [20,15,5]},
  "callback_url": "https://rallydevendas.com.br/webhooks/{name}/status",
  "meta": {"rally_user_id": "...", "rally_dispatch_id": "..."}
}
{
  "dispatch_id": "...",
  "quoted_price": 12.50,
  "eta": "2026-05-18T16:00:00Z"
}
POST /api/v1/dispatch/{id}/cancel { "ok": true }
GET /api/v1/dispatch/{id} { "dispatch_id": "...", "status": "...", "last_event_at": "..." }

5. Fluxo end-to-end

1. Você gera código no seu painel:  POST your-system → "ABC12345"
2. Webhook: POST /webhooks/{name}/invite-code (Rally cacheia)
3. Cliente cola código no Rally:    https://painel.rally.com/transportadoras/vincular?code=ABC12345
4. Rally chama: GET /api/v1/carriers/by-invite-code?code=ABC12345
   ← você retorna metadata (pix, nome, etc.)
5. Vínculo criado.

6. Cliente vende algo no ML (logistic_type=self_service).
7. Webhook ML → Rally → Rally chama: POST /api/v1/dispatch
   ← você retorna { dispatch_id, quoted_price }
8. Você notifica seu motoboy (WA/push).
9. Motoboy aceita → você manda: POST /webhooks/{name}/status { status: "accepted" }
10. Motoboy coleta → POST /webhooks/{name}/status { status: "picked_up" }
11. ... in_transit → delivered

12. Toda semana o Rally consolida dispatches abertos em fechamento PIX.
13. Cliente paga via PIX direto, anexa comprovante no Rally.
14. Você verifica o PIX recebido no seu banco.
15. Você manda: POST /webhooks/{name}/payment-confirmed { rally_dispatch_id }
    → Rally marca como pago.

6. Erros & status codes

CodeErroCausa
400invalid_jsonBody não é JSON parseável
401invalid_signatureHMAC não bate. Verificar secret + assinatura sobre body raw exato
401stale_timestampTimestamp fora da janela ±5min. Sincronizar relógio do servidor (NTP)
422missing_required_fieldsBody válido mas campo obrigatório ausente. Conferir spec do endpoint
503webhook_secret_missingRally não está configurado (FRETECENTER_INBOUND_SECRET ausente). Pedir Rally pra setar

7. Exemplo curl autêntico

SECRET="seu-secret-64-chars-aqui"
BODY='{"rally_user_id":"user_abc","dispatch_id":"job_xyz","status":"accepted","note":"motoboy a caminho"}'
TS=$(date +%s)
SIG="sha256=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')"

curl -X POST https://rallydevendas.com.br/webhooks/frete-center/status \
  -H "Content-Type: application/json" \
  -H "X-Rally-Signature: $SIG" \
  -H "X-Rally-Timestamp: $TS" \
  --data-raw "$BODY"

8. Checklist de produção

9. Contato