For wiring it up (dashboard setup, a runnable signature-verification handler, idempotency, and reconciliation), see the Receive Completion Events guide. For the inbound direction (you forward your own billing’s subscription events into Encore), see Webhook Ingestion: an unrelated flow with different headers and signing.
The request Encore sends
POSTed to the URL you configure at the moment a transaction is marked verified (driven by the advertiser’s conversion postback, not by the user tapping or claiming). It is the only event that credits a user. If you turn on payout updates, Encore can also send offer_payout_booked to the same URL, which never credits one.
Headers
Body
That’s the whole body. The body is exactly the top-level fields in the table, with no app id, creative id, or event id. Only
reward is an object; every other field is a plain value. actionId appears only when it has a value, so a handler must not require it. A handler written against a nested req.body.data won’t work; read the fields off the top level. The usr_... shape above is only a placeholder from the test-delivery sample; Encore mints no user ids and adds no prefix.Signature
The signature base string is the timestamp header and the raw request body, joined by a single dot:whsec_... signing secret and hex-encode it. The result must equal X-Webhook-Signature. Verify against the exact bytes Encore sent, not a re-serialization; a runnable handler is in the guide.
The response Encore expects
Return any2xx within 5 seconds. Anything else fails that attempt and Encore retries it.
Delivery is at-least-once
A conversion may arrive more than once, including a delivery your system already processed. A timeout or a missing response tells us nothing about whether your side completed the work, so we retry. Two things protect you, and they cover opposite failures:- Required: credit the user once per
transactionId. Take it from the signed request body. Every retry carries the same value, and so does every paid action of a multi-step offer. To record each payment rather than each credit, key ontransactionIdplusactionId, or ontransactionIdalone whenactionIdis absent; retries of one delivery repeat both. Do not key onX-Webhook-Delivery-IdorX-Webhook-Attempt. Both sit outside the signature base string and are not authenticated. - Recommended: return
2xxonly once everything the delivery records is durably committed, not on receipt. That is the user’s credit and, if you keep one, the payment record for itsactionId. On a later paid action the credit is already a no-op, so the payment record is the only work left to commit. If you acknowledge first and write asynchronously, a failure in that async step is invisible to us: we will not retry, because you already returned2xx, and the credit or the payment is silently lost.
URL requirements
Related
- Receive Completion Events guide: setup, verification handler, idempotency, reconciliation, local testing.
- offer_payout_booked webhook reference: a corrected payout for a completion already sent, never a reward.
- Webhook Ingestion: the inbound direction, for forwarding your own subscription events into Encore.