Saltar al contenido
SendIt está en desarrollo y todavía no opera comercialmente · SendIt is in development and not yet commercially available.
SendItdocs
English
Esc
navigateopen⌘Jpreview
En esta página

Webhooks

Receive events on your server: endpoint registration, HMAC signature verification, and the retry policy.

Webhooks notify your server when a resource changes, such as a label purchase, tracking update, or wallet movement. Register an HTTPS endpoint and verify each delivery’s signature.

Register an endpoint

Body parameters

PropType
urlstring

HTTPS with a direct response. Redirects are not followed, and a 3xx counts as a failure.

Typestring
eventsstring[]

The event types this endpoint subscribes to (see the table below).

Typestring[]
description?string

Optional name that identifies the destination.

Typestring
curl -X POST https://api.sendit.mx/v1/webhook-endpoints \
  -H "X-API-Key: sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://mitienda.mx/webhooks/sendit",
    "description": "Production receiver",
    "events": ["shipment.label.created", "shipment.tracking.updated"]
  }'
{
  "success": true,
  "data": {
    "id": "whe_a1b2c3d4e5f6",
    "url": "https://mitienda.mx/webhooks/sendit",
    "description": "Production receiver",
    "events": ["shipment.label.created", "shipment.tracking.updated"],
    "status": "ACTIVE",
    "failureCount": 0,
    "disabledAt": null,
    "createdAt": "2026-07-18T10:00:00.000Z",
    "signingSecret": "whsec_9f8e7d6c5b4a"
  }
}

The field is named signingSecret. SendIt generates it and returns it only when you create or rotate the endpoint. Store it in a secrets manager because you cannot retrieve it again. The endpoint list never includes it.

Each plan caps how many active endpoints you can have. Registering one more returns 403 PLAN_LIMIT_REACHED. See plans and quotas.

Manage your endpoints

Method Path Description
GET /v1/webhook-endpoints List your endpoints
GET/PATCH/DELETE /v1/webhook-endpoints/:id Read, update, or delete one
POST /v1/webhook-endpoints/:id/rotate-secret Issue a new secret (returned once)
POST /v1/webhook-endpoints/:id/test Send a webhook.test event immediately
GET /v1/webhook-endpoints/:id/events Delivery history for that endpoint
POST /v1/webhook-endpoints/:id/events/:eventId/redeliver Retry one delivery

Any authenticated member can read. Writes require the ADMIN role and the webhooks:write scope.

Event types

You can subscribe to these documented events:

Event When it fires
shipment.created A shipment was created
shipment.updated A DRAFT shipment was updated
shipment.label.created A label was purchased
label.purchase.completed A durable purchase finished: success, compensated failure, or action_required
shipment.label.voided A label was voided and the wallet refunded
shipment.tracking.updated Carrier tracking caused a status transition
wallet.credited A wallet credit was confirmed
wallet.debited A label-purchase debit was confirmed
wallet.low_balance A LIVE debit crossed the configured threshold
tracker.created An external tracker was registered
tracker.updated An external tracker changed status
tracker.expired An external tracker hit its TTL without a terminal status

Subscribe each endpoint only to the events it cares about. Your handler must ignore types it does not recognize.

The payload

{
  "id": "evt_1a2b3c4d5e",
  "type": "shipment.tracking.updated",
  "created": "2026-07-17T12:00:00.000Z",
  "livemode": true,
  "data": {
    "object": {
      "id": "clxq1w2e3r4t5y6u7i8o9p0a",
      "status": "IN_TRANSIT",
      "trackingNumber": "1234567890",
      "carrierCode": "DHL",
      "organizationId": "clxorg123"
    }
  }
}
  • created is an ISO-8601 timestamp, not epoch seconds.
  • data.object is the full resource projection, not a flat subset. Shipment events embed their fromAddress, toAddress, and label projections.
  • There is no top-level apiVersion or organizationId. A shipment’s data.object does carry its organizationId; a tracker’s does not.
  • livemode: false marks test-mode events. Route them to your staging.
  • id is unique per event. Use it to deduplicate if you receive a repeated delivery.

Verify the signature

Every delivery arrives signed with HMAC-SHA256 in the X-SendIt-Signature header, formatted t=<timestamp>,v1=<signature>:

POST /webhooks/sendit HTTP/1.1
X-SendIt-Signature: t=1752750000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
Content-Type: application/json

Always verify before processing. The signature is the only proof the event came from SendIt:

import crypto from "node:crypto";

function verifySenditSignature(rawBody, signatureHeader, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    signatureHeader.split(",").map((kv) => kv.split("="))
  );
  const { t, v1 } = parts;

  // 1. Reject stale timestamps (replay protection)
  if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSeconds) return false;

  // 2. Recompute the signature over `${t}.${rawBody}`
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");

  // 3. Constant-time compare
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Respond fast, process later

Return 2xx as soon as you have persisted the event, ideally under a second. Process in the background. Anything other than 2xx counts as a failure, including redirects.

Retry policy

Attempt Wait
1 Immediate
2 2 min
3 4 min
4 8 min
5 16 min

After the fifth attempt the event becomes EXHAUSTED and is not retried again.

An endpoint that keeps failing for 24 hours is automatically disabled. When that happens, we email your organization’s admins. To re-enable it, fix your server and send a test delivery with POST /v1/webhook-endpoints/:id/test. A successful test re-enables the endpoint.

Since deliveries can repeat, make your processing idempotent using the event id.

Try it risk-free

In test mode, every status advance fires real webhooks with livemode: false. Buy a test label, advance its status, and watch the deliveries arrive at your endpoint.

Handle errors

Code When it happens How to resolve it
400 INVALID_INPUT The URL or an event type is invalid Use HTTPS and a documented event
403 INSUFFICIENT_SCOPE The key lacks webhooks:write for a write Issue a key with the required scope
403 PLAN_LIMIT_REACHED The organization reached its endpoint limit Delete an unused endpoint or change plans
404 RESOURCE_NOT_FOUND The endpoint or event does not exist Check the identifiers

¿Te ha resultado útil esta página?