Pular para o conteúdo

Eventos de status

A cada mudança de status, a RaptorX envia um POST para a URL de webhook cadastrada na sua integração, exatamente como foi cadastrada (inclusive a query string).

Header Descrição
Content-Type application/json
X-App-MerchantId Merchant ID da loja
X-App-Signature HMAC-SHA256 do corpo bruto, em hexadecimal minúsculo, com o clientSecret como chave
X-App-Id App ID cadastrado. Só é enviado se foi configurado

Calcule o HMAC-SHA256 do corpo bruto (os bytes recebidos, antes de qualquer parse de JSON) com o seu clientSecret e compare com X-App-Signature em tempo constante. Rejeite a requisição se não bater.

import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";
const app = express();
const clientSecret = process.env.RAPTORX_CLIENT_SECRET;
// guarda o corpo bruto para assinar exatamente o que foi recebido
app.post("/webhooks/raptorx", express.raw({ type: "application/json" }), (req, res) => {
const received = String(req.header("X-App-Signature") ?? "");
const expected = createHmac("sha256", clientSecret).update(req.body).digest("hex");
const a = Buffer.from(received);
const b = Buffer.from(expected);
if (a.length !== b.length || !timingSafeEqual(a, b)) {
return res.sendStatus(401);
}
const evento = JSON.parse(req.body.toString("utf8"));
// processe de forma idempotente e responda rápido
res.sendStatus(200);
});
{
"deliveryId": "0b6f9f0e-3c9a-4f0e-9c1e-2f6a8b1d7c55",
"orderId": "pedido-84321",
"orderDisplayId": "4321",
"merchant": { "id": "loja-001", "name": "Pizzaria Exemplo" },
"customerName": "Maria Souza",
"event": { "type": "ACCEPTED", "datetime": "2026-10-07T14:10:00.000Z" },
"vehicle": { "type": "MOTORBIKE_BAG", "container": "NORMAL" },
"deliveryPerson": { "id": "5d1c2b7a-...", "name": "Carlos Lima", "phone": "+5519988887777" },
"deliveryPrice": {
"price": { "value": 7.5, "currency": "BRL" },
"pricingList": "NORMAL",
"additionalPricePercentual": 0
},
"eta": {
"updateMethod": "OFFLINE",
"pickupEtaInMinutes": 5,
"pickupEtaDatetime": "2026-10-07T14:15:00.000Z",
"deliveryEtaInMinutes": 25,
"deliveryEtaDatetime": "2026-10-07T14:35:00.000Z",
"maxDeliveryTime": "2026-10-07T14:35:00.000Z"
}
}
Campo Descrição
deliveryId Identificador da entrega na RaptorX
orderId Seu orderId
orderDisplayId Seu orderDisplayId
merchant.id / merchant.name Merchant ID e nome da loja
customerName Nome do destinatário
event.type Tipo do evento (tabela abaixo)
event.datetime Momento do envio do evento
event.message Só em CANCELLED: motivo, até 200 caracteres. É o reason enviado por você ou, em cancelamento feito pela operação, um texto livre
event.rejectionInfo Só em REJECTED: { "reason": "NO_DELIVERYPERSON_AVAILABLE", "metadata": { "description"?: "..." } }
vehicle A partir de ACCEPTED, com entregador atribuído. type: MOTORBIKE_BAG, CAR ou BICYCLE; container: NORMAL
deliveryPerson A partir de ACCEPTED, com entregador atribuído: id, name, phone
deliveryPrice A partir de ACCEPTED. Valor da entrega em BRL; pricingList é NORMAL e additionalPricePercentual é 0
eta A partir de ACCEPTED. Estimativas, não garantias. pickupEtaInMinutes é um valor fixo de referência (5)

Os eventos PENDING, REJECTED e CANCELLED não trazem vehicle, deliveryPerson, deliveryPrice nem eta.

Uma mudança de status pode gerar dois eventos seguidos, enviados em requisições separadas.

Quando Eventos enviados
Entrega criada PENDING
Entregador aceitou ACCEPTED, PICKUP_ONGOING
Pedido retirado ORDER_PICKED, DELIVERY_ONGOING
Entregador chegou ao cliente ARRIVED_AT_CUSTOMER
Entrega concluída ORDER_DELIVERED, DELIVERY_FINISHED
Entrega cancelada (por você ou pela operação) CANCELLED
Nenhum entregador aceitou até rejectAfter REJECTED
Devolução iniciada RETURNING_TO_MERCHANT
Devolvido à loja RETURNED_TO_MERCHANT
  • Responda com qualquer status 2xx, em até 10 segundos. Faça o processamento pesado depois de responder.
  • Resposta fora de 2xx, timeout ou erro de rede contam como falha.
  • Redirecionamentos (3xx) não são seguidos e contam como falha: cadastre a URL final.
  • Em caso de falha, a RaptorX tenta de novo: até 4 rodadas, com intervalos de 1, 5 e 30 minutos entre elas. Em cada rodada, falhas 5xx, 429 e de rede ainda são reenviadas algumas vezes em poucos segundos.
  • Depois disso, o evento não é reenviado automaticamente.
  • A entrega é pelo menos uma vez: o mesmo evento pode chegar duplicado, e eventos de uma rodada anterior podem chegar fora de ordem. Use deliveryId e event.type para tratar de forma idempotente e não retroceda um status já mais avançado.
  • event.datetime é o momento do envio e não do acontecimento.
  • A URL de webhook precisa ser HTTPS e pública.