Events & webhooks
Every change produces an event. Receive them as signed webhooks, or poll the event log.
Event types
| Type | When |
|---|---|
order.created | A checkout completed (payment may still be pending for bank methods). |
order.paid | Payment confirmed. Stock is committed. Ready to ship. |
order.shipment_created | A package shipped (one per print-on-demand provider or label). |
order.fulfilled | The whole order shipped. |
order.updated | Tracking or other details changed after fulfillment. |
order.cancelled | A delayed payment failed. Stock was released. |
order.refunded | A full or partial refund, from the API or the Stripe Dashboard. |
checkout.expired | A checkout wasn't paid in time. Stock was released. |
inventory.updated | Stock was adjusted or set. |
product.created / product.updated | Catalog changes. |
label.created | A shipping label was bought. |
fulfillment.submitted / failed / canceled / on_hold | Print-on-demand order status. |
return.requested / approved / rejected / completed | Return lifecycle. |
Webhooks
const { data } = await commerce.webhooks.create({
url: "https://example.com/api/commerce-webhook",
events: ["order.*", "return.*"], // or ["*"]
});
// data.secret is shown once — store it.Deliveries are signed with the Standard Webhooks scheme (webhook-id, webhook-timestamp, webhook-signature headers) and retried with backoff for about a day. Delivery is at-least-once, so dedupe on webhook-id.
import { verifyWebhook } from "commerceforai";
const event = await verifyWebhook({
payload: rawBody, // the raw string, not parsed JSON
headers: request.headers,
secret: process.env.COMMERCEFORAI_WEBHOOK_SECRET!,
});Polling
No public endpoint? Poll the ordered event log with a cursor. This is also how agents catch up.
let after: string | undefined;
const { data } = await commerce.events.list({ after, type: "order.*" });
for (const e of data.data) { /* handle */ after = e.id; }