Events you can subscribe to
Every subscription listens to one or more of the following events. Events correspond to Shopify order lifecycle transitions:| Event | Fires when |
|---|---|
order.created | A new order is placed. |
order.updated | Any order field changes after creation. |
order.paid | The order’s financial status moves to paid. |
order.fulfilled | The order (or a line item) is fulfilled. |
order.cancelled | The order is cancelled. |
order.paid and order.updated. Always make your handler idempotent (see Delivery guarantees).
Create a subscription
Enter your endpoint URL
Must be HTTPS. HTTP endpoints are rejected at save time. Plain IP addresses are allowed but not recommended — use a domain with a valid TLS certificate.
Accept the data-handling notice
Webhook payloads include order and (anonymized) customer data. Confirm you’re responsible for handling them securely before creating the subscription.
Payload shape
Every delivery is a POST request with a JSON body:Field notes
event— the specific event that matched this subscription (e.g. a single subscription listening to bothorder.paidandorder.updatedwill get two separate deliveries when both fire).trigger— the underlying order lifecycle change, mapped from Shopify’s topic. Useful when multiple events share a trigger.timestamp— ISO-8601 in UTC.data.order.id— Customei’s internal order ID (prefixedord_). Use this as your primary key when deduplicating.data.order.shopifyOrderId— Shopify’s numeric order ID. Handy for cross-referencing Shopify Admin.data.order.lineItems[].properties— the personalization payload, flattened to key-value pairs per line item. For richer data (uploaded image URLs, bound layer metadata), query the GraphQL API using theid.data.order.lineItems[].productionStatus— Customei’s internal print-file state:PENDING/GENERATING/READY/FAILED.
Verify the signature
Every request includes two headers:X-Pod-Timestamp— request timestamp in ISO-8601.X-Pod-Signature—sha256=<hex-digest>HMAC over${timestamp}.${rawBody}using your subscription secret.
Node.js example
401 — Customei will retry and log the failure.
Python example
Reject stale requests
Compare the timestamp against your server clock and reject anything more than 5 minutes off. This protects against replay attacks even if a signature is leaked.Verification challenge on create
When you create a new subscription, Customei immediately sends a verification request to your URL — aPOST with a special event: "_verification" payload. Your server must respond with 200 OK within 10 seconds. If it doesn’t, Customei refuses to activate the subscription and shows the error in the UI.
This is a light cost to set up but saves you from shipping a broken subscription to production.
Delivery guarantees
Webhooks are delivered at-least-once. Your handler must be idempotent — receiving the same event twice should not double-charge, double-fulfill, or double-anything.- Timeouts. Your endpoint has 10 seconds to respond. Beyond that, Customei treats the delivery as failed.
- Retries. Failed deliveries (non-2xx status, timeout, network error) are retried with exponential backoff starting at 30 seconds, for up to 5 attempts. After the fifth failure, the delivery is marked permanently failed and surfaced in the subscription’s delivery log.
- Ordering. Deliveries are not guaranteed to arrive in chronological order, especially across retries. Use the
timestampfield to reconstruct ordering yourself if you need it. - Deduplication. Use
data.order.id+eventas your idempotency key.
View delivery history
Each subscription has a Deliveries tab showing recent attempts, their status, response code, and response body (truncated). Click an individual delivery to replay the payload for debugging.- Succeeded — your endpoint returned 2xx.
- Failed — at least one attempt failed; check the last response body for the reason.
- Pending — queued for delivery but not sent yet.
Manually replay a delivery
From the delivery log, click Replay on any past delivery. Customei sends the exact same payload (including the original timestamp and a fresh signature) to your endpoint. Handy for reproducing bugs in staging.Edit or pause a subscription
- Edit — change the URL, events, or description. The secret stays the same unless you explicitly rotate it.
- Pause — temporarily stop deliveries without deleting the subscription. Incoming events during a pause are dropped; they’re not queued for later delivery.
- Delete — permanently removes the subscription and its delivery history.
Rotate the secret
From the subscription’s settings, click Rotate secret. Customei issues a new secret and shows it once — copy it and deploy it to your server before sending the next event. There’s no grace period — the old secret stops working immediately on rotation.Limits
- 10 active subscriptions per account. Contact Support if you need more.
- 10-second handler timeout.
- 5 retry attempts per delivery.
- Payloads are capped at 1 MB. Events that would exceed this are truncated; line-item properties are the most common culprit.
Troubleshooting
- I’m getting duplicate events. Normal under retry; dedupe on
data.order.id+event. - The signature doesn’t match. Make sure you’re signing
${timestamp}.${rawBody}, not the parsed JSON. The body must be the exact bytes received, before any framework parses it. - Timestamps feel wrong. They’re UTC ISO-8601. Your server might be comparing against local time.
- Verification challenge fails. Your endpoint needs to respond 2xx to the initial test POST with
event: "_verification"— many merchants forget their auth middleware blocks un-signed requests and reject the challenge.
Next
- API overview — for two-way integrations.
- Integrations overview
- Roles and permissions