The short version
Your endpoint has one job: confirm that you received the event. Return a2xx as soon as you
have durably stored the request, then run your business logic separately.
Imprint is the sender — we have no visibility into your business rules, so we cannot act on them.
We treat every non-2xx response the same way: as “you did not receive this event,” and we retry.
Your HTTP status code is a transport-level receipt, not a place to express whether you liked the
event.
Why we retry a 4xx at all
This runs against the usual HTTP convention, where a 4xx means “the request was wrong, don’t
bother sending it again,” so it is worth stating plainly rather than leaving you to discover it.
From the sender’s position, two situations are indistinguishable: an endpoint that has genuinely
looked at an event and rejected it, and an endpoint that returned an error by mistake — mid-deploy,
a dependency that was briefly down, a validation rule firing on a field it should have ignored.
Both answer 422. A retry is cheap and recovers the second case, so Imprint retries and leaves the
business decision to you. The cost is that a deliberate rejection also gets retried nine more
times, which is why the guidance is to acknowledge first and reject inside your own system instead.
What Imprint sends
Each event is delivered as a single HTTPPOST to the URL registered for that event type.
The envelope and the
data fields of every event type are specified on the
Event notifications reference page. This page covers only how the request
gets to you.
Worth noting is what the request does not carry: no per-delivery sequence number, no
retry-attempt counter, and no delivery ID header. Nothing in the request tells you whether you are
looking at a first attempt or a ninth — see Idempotency and ordering.
What counts as a successful delivery
A delivery succeeds when your endpoint returns one of these status codes:200, 201, 202, 203, 204, 205, 206, 207, 208, 226
That is every assigned 2xx code, so in practice: acknowledge with a 2xx. The response body is
recorded for support purposes but is never parsed or acted on.
Anything else is a failed delivery and is retried:
- any
3xx,4xx, or5xxstatus — and any non-standard code outside the list above - a connection failure, TLS failure, or DNS failure
- no response at all — the attempt timed out
Retry schedule
Failed deliveries are retried with exponential backoff, up to 10 total attempts (the first delivery plus 9 retries). Backoff doubles after each failure, starting at 5 seconds in production.These figures are nominal and individual delays can vary. Backoff is measured from the end of the
previous attempt, so an endpoint that hangs instead of answering stretches the total window well
past what the table shows. Use the table for the shape and the order of magnitude, not as a
contract to build timing dependencies on.
422 is retried on exactly the same schedule
as a 503.
After the final attempt
Once the 10th attempt fails, Imprint stops. The event is not redelivered later, and there is currently no self-serve way for you to replay it. Imprint Portal shows a graph of webhook delivery, so you can see delivery volume and failures for your own endpoints there. Treat it as a way to confirm or investigate a problem rather than as the thing that tells you a problem started — it will not page you. Your own alerting on your own processing remains the reliable signal. If you know or suspect you dropped events — a bad deploy, an expired certificate, a firewall change — contact your Imprint team so we can arrange a backfill. Include the event type, the approximate time window, and any customer or transaction identifiers you have.How your endpoint should be built
1
Read the raw body into memory
Buffer the exact bytes you received, with a size limit. Do not persist anything yet, and do not
parse and re-serialize — the signature is computed over the bytes as sent, so any reformatting
breaks verification.
2
Verify the signature
Verify over those exact bytes, before you store anything and before you trust the payload.
Storing first would let anyone who knows your URL fill your database by posting unsigned
requests. If verification fails, reject the request — a request that is not from Imprint should
not be acknowledged. A genuine Imprint event rejected this way will be retried on the schedule
above, so a signature bug surfaces as repeated delivery rather than silent loss. See
Verify event signature.
3
Store the verified body
Now persist the raw bytes, along with the
X-IMPRINT-HMAC-SIGNATURE header. Keeping the
unmodified body is what lets you reprocess later without asking Imprint to resend.4
Acknowledge
Return
200 or 202 as soon as the event is durably stored, and before any business logic
runs. Do not wait on downstream systems, database writes to other services, queue publishes
that can block, or any validation of the event’s contents.5
Process asynchronously
Run your business logic from the stored record — a queue, a job runner, or a worker loop.
Retry inside your own system, on your own schedule, with your own alerting. This is the part
Imprint’s retries cannot help with, because from our side the delivery already succeeded.
6
Alert on your own failures
If your async processing rejects an event, that is your incident to see, not something to
signal by way of an HTTP status. Log it, alert on it, and tell Imprint if the payload itself
looks wrong.
Status code reference
The rule is the one already stated: anything that is not a2xx is retried on the same schedule,
then dropped. There is no per-code retry behavior to look up. What this table covers is the
handful of codes where that rule has a consequence worth knowing about.
Idempotency and ordering
Delivery is retried, not guaranteed. An event you accept may still be delivered again, and an event can be dropped entirely once the retry budget is exhausted. So plan for duplicates, plan for events arriving out of order, and do not treat “we would have received it” as a safe assumption when reconciling. Duplicates. A retry sends the same body, and since no delivery ID header exists, deduplication has to key off the payload itself. Which fields to use is covered in Handle duplicate events. Two things that section does not tell you, and that follow from how retries work. Duplicates can arrive with no failure on your side at all: if your2xx is lost in transit after you already
committed the event, we retry something you processed perfectly well. And not every event type
carries updated_at, so confirm on the reference page that the events you
subscribe to actually have one before you rely on it as a tiebreaker.
Ordering. Each event is delivered on its own, in parallel with the others. A retrying event
does not block newer events, so while attempt 6 of one event is still backing off, later events
for the same customer will already have been delivered. Do not infer sequence from arrival order.
Drive your state from the identifiers and timestamps in the payload, and make transitions
order-independent — ignore an update that would move a record backwards relative to what you have
already stored.
Signature freshness. The signature and its timestamp are recomputed on every attempt, so a
retry carries a current timestamp rather than the timestamp of the first attempt. That is the one
retry behavior that changes how you verify a request — Verify event signature
covers what it means for freshness windows and why the signature is not a deduplication key.
Checklist
- Endpoint is HTTPS and accepts
POST - Signature verified against the raw, unmodified body before any parsing
- Multiple
s=values in the signature header handled (rotation-safe) - Raw body persisted before acknowledging
-
2xxreturned before business logic runs, never gated on it - Business logic runs asynchronously with its own retries and alerts
- No business condition can produce a non-
2xxresponse - Deduplication keyed on
object+ the event’s identifier (+updated_atwhere present) - State transitions are order-independent
- No redirects on the webhook URL
- Alerting on your own processing-failure rate, not on Imprint’s retries
- A contact path to your Imprint team for endpoint changes and backfills