CommerceForAI

Events & webhooks

Every change produces an event. Receive them as signed webhooks, or poll the event log.

Event types

TypeWhen
order.createdA checkout completed (payment may still be pending for bank methods).
order.paidPayment confirmed. Stock is committed. Ready to ship.
order.shipment_createdA package shipped (one per print-on-demand provider or label).
order.fulfilledThe whole order shipped.
order.updatedTracking or other details changed after fulfillment.
order.cancelledA delayed payment failed. Stock was released.
order.refundedA full or partial refund, from the API or the Stripe Dashboard.
checkout.expiredA checkout wasn't paid in time. Stock was released.
inventory.updatedStock was adjusted or set.
product.created / product.updatedCatalog changes.
label.createdA shipping label was bought.
fulfillment.submitted / failed / canceled / on_holdPrint-on-demand order status.
return.requested / approved / rejected / completedReturn 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; }