Skip to main content
CHIP Collect sends two kinds of asynchronous notification to your server — Purchase success callbacks and Webhook callbacks (see Callbacks). Both follow the same delivery and retry rules described on this page.

What counts as a failed delivery

A delivery attempt succeeds only when your server responds with an HTTP 2xx status code. The attempt is treated as failed when:
  • your server responds with a non-2xx status code (eg. 403, 404, 500);
  • the connection could not be established (DNS failure, TLS error, connection refused);
  • no response was received in time.
A failed attempt is retried automatically with the same payload and event. Every attempt, including a retry, must be verified with the X-Signature header exactly as described in Webhook signatures — verification is per request, not per event.

Retry schedule

Retries follow an exponential schedule with base 3. The delay before an attempt is
where attempt 1 is the initial delivery. Delays are counted from the moment the callback was first scheduled, not from the previous attempt, so a slow or hanging attempt does not push the following attempts back. Delivery stops after the 8th attempt — 36 hours 26 minutes after the first one. The callback is not re-sent beyond that point, so a late recovery on your side does not receive the missed events. Reconcile against the API instead of waiting: GET /purchases/{id}/ always returns the current state of the Purchase.
A retry can occasionally arrive more than once, or arrive after a previous attempt was in fact received. This is unavoidable with asynchronous network requests — see Duplicate deliveries.

Duplicate deliveries

Due to the asynchronous nature of network requests, it is possible for a delivery confirmation (an HTTP response with a 200 series status code) to not properly arrive from your callback’s target server. In that case your server can receive a callback, respond to it with a 200 series status code — for example on the first attempt — and then receive the same callback again on a later attempt. Callbacks are therefore at least once, not exactly once. Handle a callback idempotently: key your processing on the payload’s id (the Purchase id) together with event_type, and treat a repeat of the same pair as already processed rather than as a new event.

Ordering

Callback deliveries are guaranteed to be sequential to events triggered on their source objects. For example, when registering webhooks for both the purchase.created and purchase.paid events, there will be no purchase.paid callbacks for this Purchase until all purchase.created callbacks for this Purchase are successfully delivered. A purchase that is stuck on a failing purchase.created callback therefore also delays the later events of that same purchase — for up to the 8 attempts described above.