CartistoDocs

Webhooks

Subscribe to store events, verify the signature, and handle retries.

Webhooks push store events to your endpoint so you don’t poll. Manage them under /api/v1/webhooks (create, update, delete, rotate secret).

Events

Subscribe to any subset of:

Event Fires when
order_created A new order is placed
order_updated An order changes
order_cancelled An order is cancelled
order_shipped An order ships
order_delivered An order is delivered
payment_received A payment is captured
product_created / product_updated Catalog changes
customer_created / customer_updated Customer changes
refund_created A refund is created
Note

Event names are underscore-cased Use order_created, not order.created. Dot-cased names are rejected — the value must match the platform’s event enum exactly.

Delivery format

Each delivery is an HTTP POST with a JSON body:

{
  "event": "order_created",
  "payload": { /* the resource */ },
  "timestamp": "2026-08-06T10:20:30.000Z"
}

Redirects are not followed and the request times out at 10s.

Verifying the signature

Every delivery carries an HMAC signature header:

X-Webhook-Signature: sha256=<hex>

The signature is HMAC-SHA256(secret, JSON.stringify(payload)) — computed over the payload object, using the secret shown once when you created the webhook (rotate it anytime; the old secret stops verifying immediately).

import crypto from "crypto";

function verify(req) {
  const expected =
    "sha256=" +
    crypto
      .createHmac("sha256", process.env.WEBHOOK_SECRET)
      .update(JSON.stringify(req.body.payload))
      .digest("hex");
  const got = req.headers["x-webhook-signature"];
  return got && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
}

Reject any request whose signature doesn’t match.

Retries & auto-disable

  • Deliveries retry with exponential backoff (≈ 1 min, then 5 min) on failure.
  • Only 5xx responses (and network/timeouts) are retried — a 4xx is treated as “you received it, you rejected it,” so return 2xx to acknowledge.
  • After a streak of consecutive terminal failures the webhook is auto-disabled to stop hammering a dead endpoint; a successful delivery resets the streak.

Building a good receiver

  • Respond fast (2xx) then process async. Acknowledge within the timeout; enqueue the work.
  • Be idempotent. A retry can deliver the same event twice — dedupe on the resource id + event.
  • Verify first. Check the signature before trusting the body.
Tip

Rotate on leak If a secret leaks, rotate it from /api/v1/webhooks — the old secret stops verifying at once. Update your receiver with the new secret shown at rotation.