Documentation Index
Fetch the complete documentation index at: https://docs.waysdrop.com/llms.txt
Use this file to discover all available pages before exploring further.
Webhooks
Waysdrop sends webhooks for key order and delivery lifecycle events. Webhooks are delivered asynchronously and retried on failure.
Delivery & signature
Webhook payloads are POSTed to the webhook URL configured for the API key.
Environments
Webhooks are scoped to the environment of the API key:
- Live:
https://api.waysdrop.com
- Staging:
https://staging-api.waysdrop.com
Configure your webhook URL in the matching dashboard:
Payload
{
"event": "delivery.in.transit",
"data": {}
}
Content-Type: application/json
User-Agent: Waysdrop-Webhook/1.0
X-Webhook-Log-Id: <logId>
x-waysdrop-signature: <hex signature>
Idempotency
Use X-Webhook-Log-Id as an idempotency key. The same event may be retried and delivered more than once; you should safely ignore duplicates by storing processed log IDs.
Signature
x-waysdrop-signature is computed as:
- Algorithm:
sha256
- Secret: your API key value (the same string you send in
api-key)
- Input:
JSON.stringify({ event, data })
Verification example (Node.js)
import crypto from "crypto";
export function verifyWaysdropSignature({ apiKey, body, signature }) {
const computed = crypto
.createHmac("sha256", apiKey)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(computed),
Buffer.from(signature),
);
}
Your webhook response
Waysdrop treats any successful 2xx response as “delivered”. Your endpoint should respond quickly (Waysdrop times out at 5 seconds).
Recommended response
Waysdrop stores your response body in the webhook log for debugging (if any).
Retries and delivery guarantees
Webhooks are delivered asynchronously and retried until one of these happens:
- delivered successfully
- exhausted retry attempts (max: 10)
Retry conditions
- Retries on network errors/timeouts.
- Retries on
408 and 429.
- Retries on all
5xx.
- Does not retry for other
4xx responses.
Backoff
nextRetryAt uses exponential backoff: 2^attempts seconds.
- A repeat job runs roughly every 60 seconds and attempts retries once
nextRetryAt is due.
Webhook events
All timestamps are serialized as ISO strings.
p2p.delivery.created
{
"event": "p2p.delivery.created",
"data": {
"status": "string",
"trackingId": "string",
"deliveryId": "uuid",
"p2pDeliveryId": "uuid",
"userId": "uuid",
"profileId": "uuid",
"totalWeight": "number",
"totalValue": "number",
"costs": {
"total": "number",
"weight": "number",
"urgency": "number",
"fleet": "number",
"insurance": "number",
"base": "number"
},
"paymentMethodType": "string",
"courierSelection": "string",
"urgencyType": "string",
"origin": {},
"destination": {},
"createdAt": "2026-01-24T12:34:56.789Z"
}
}
p2p.delivery.cancelled
{
"event": "p2p.delivery.cancelled",
"data": {
"trackingId": "string",
"deliveryId": "uuid",
"p2pDeliveryId": "uuid",
"status": "CANCELLED",
"canceledAt": "2026-01-24T12:34:56.789Z",
"refundAmount": "number | null"
}
}
delivery.request.accepted
{
"event": "delivery.request.accepted",
"data": {
"deliveryId": "uuid",
"trackingId": "string",
"type": "ORDER | P2P",
"status": "ACCEPTED",
"routeType": "string",
"courierProfileId": "uuid",
"origin": {},
"destination": {},
"storeProfileId": "uuid",
"storeLocation": {},
"orderId": "uuid",
"p2pDeliveryId": "uuid"
}
}
delivery.request.declined
{
"event": "delivery.request.declined",
"data": {
"deliveryId": "uuid",
"trackingId": "string",
"type": "ORDER | P2P",
"status": "DECLINED",
"routeType": "string",
"courierProfileId": "uuid",
"courierUserId": "uuid",
"origin": {},
"destination": {},
"storeProfileId": "uuid",
"storeLocation": {},
"orderId": "uuid",
"orderNumber": "string",
"p2pDeliveryId": "uuid",
"refundExpected": {
"amount": "number",
"currency": "string"
}
}
}
delivery.awaiting.collection
{
"event": "delivery.awaiting.collection",
"data": {
"deliveryId": "uuid",
"trackingId": "string",
"type": "ORDER | P2P",
"status": "AWAITING_COLLECTION",
"routeType": "string",
"courierProfileId": "uuid",
"origin": {},
"destination": {},
"proofCode": "string | null",
"orderId": "uuid",
"storeProfileId": "uuid",
"p2pDeliveryId": "uuid",
"profileId": "uuid",
"updatedAt": "2026-01-24T12:34:56.789Z"
}
}
delivery.collected
{
"event": "delivery.collected",
"data": {
"deliveryId": "uuid",
"trackingId": "string",
"type": "ORDER | P2P",
"status": "ORDER_COLLECTED | PACKAGE_COLLECTED",
"routeType": "string",
"collectedAt": "2026-01-24T12:34:56.789Z",
"courierProfileId": "uuid",
"courierUserId": "uuid",
"origin": {},
"destination": {},
"deliveryCode": "string | null",
"orderId": "uuid",
"storeProfileId": "uuid",
"p2pDeliveryId": "uuid"
}
}
delivery.in.transit
{
"event": "delivery.in.transit",
"data": {
"deliveryId": "uuid",
"trackingId": "string",
"type": "ORDER | P2P",
"status": "IN_TRANSIT",
"routeType": "string",
"origin": {},
"destination": {},
"inTransitAt": "2026-01-24T12:34:56.789Z"
}
}
delivery.delivered
{
"event": "delivery.delivered",
"data": {
"deliveryId": "uuid",
"trackingId": "string",
"type": "ORDER | P2P",
"status": "DELIVERED",
"routeType": "string",
"deliveredAt": "2026-01-24T12:34:56.789Z",
"courierProfileId": "uuid",
"courierUserId": "uuid",
"origin": {},
"destination": {},
"orderId": "uuid",
"storeProfileId": "uuid",
"p2pDeliveryId": "uuid"
}
}
delivery.reassignment.created
Emitted when a courier-to-system reassignment is created for one or more deliveries (grouped by apiKeyId).
{
"event": "delivery.reassignment.created",
"data": {
"reassignmentId": "uuid",
"type": "string",
"status": "string",
"fromCourierId": "uuid",
"handoverLocation": {},
"deliveryIds": ["uuid"],
"trackingIds": ["string"],
"createdAt": "2026-01-24T12:34:56.789Z"
}
}
delivery.reassignment.requested
Emitted when the system creates a reassignment request response for a candidate courier (grouped by apiKeyId).
{
"event": "delivery.reassignment.requested",
"data": {
"reassignmentId": "uuid",
"status": "string",
"type": "string",
"courierProfileId": "uuid",
"handoverLocation": {},
"dominantFleetTypeId": "uuid",
"deliveryIds": ["uuid"],
"trackingIds": ["string"],
"requestedAt": "2026-01-24T12:34:56.789Z"
}
}
delivery.reassignment.collected
Emitted after reassignment handover proof is validated (grouped by apiKeyId).
{
"event": "delivery.reassignment.collected",
"data": {
"reassignmentId": "uuid",
"type": "string",
"status": "string",
"handoverAt": "2026-01-24T12:34:56.789Z",
"handoverLocation": {},
"proofImage": "string | null",
"fromCourierId": "uuid | null",
"toCourierId": "uuid | null",
"deliveries": [
{
"deliveryId": "uuid",
"trackingId": "string",
"type": "ORDER | P2P",
"status": "string",
"routeType": "string",
"origin": {},
"destination": {}
}
]
}
}
delivery.reassignment.direct_assigned
Emitted when an employer directly reassigns deliveries to an employee (no request/proof flow).
{
"event": "delivery.reassignment.direct_assigned",
"data": {
"deliveryId": "uuid",
"trackingId": "string",
"type": "ORDER | P2P",
"status": "string",
"routeType": "string",
"reassignmentType": "string",
"fromCourierId": "uuid",
"toCourierId": "uuid",
"assignedAt": "2026-01-24T12:34:56.789Z"
}
}
order.requested
Emitted when a store receives a new order request.
{
"event": "order.requested",
"data": {
"order": {},
"storeProfileId": "uuid",
"storeUserId": "uuid"
}
}
order.created
{
"event": "order.created",
"data": {
"orderId": "uuid",
"orderNumber": "string",
"deliveryId": "uuid",
"trackingId": "string",
"userId": "uuid",
"profileId": "uuid",
"amount": "number",
"source": "string",
"status": "AWAITING_CONFIRMATION"
}
}
order.confirmed
{
"event": "order.confirmed",
"data": {
"orderId": "uuid",
"orderNumber": "string",
"deliveryId": "uuid",
"trackingId": "string | null",
"storeProfileId": "uuid",
"storeUserId": "uuid",
"storeLocation": {},
"status": "CONFIRMED",
"confirmedAt": "2026-01-24T12:34:56.789Z"
}
}
order.declined
{
"event": "order.declined",
"data": {
"orderId": "uuid",
"orderNumber": "string",
"deliveryId": "uuid",
"trackingId": "string | null",
"storeProfileId": "uuid",
"storeUserId": "uuid",
"storeLocation": {},
"status": "DECLINED",
"declinedAt": "2026-01-24T12:34:56.789Z",
"refundExpected": {
"amount": "number",
"currency": "string"
}
}
}
order.cancelled
{
"event": "order.cancelled",
"data": {
"orderId": "uuid",
"orderNumber": "string",
"trackingId": "string",
"deliveryId": "uuid",
"userId": "uuid",
"profileId": "uuid",
"refundAmount": "number | null",
"status": "CANCELLED",
"canceledAt": "2026-01-24T12:34:56.789Z"
}
}