Skip to main content
An outbound webhook is an endpoint you implement: this page is the contract of the request Encore sends when one of your users’ offer completions is verified, the response Encore expects back, and the delivery semantics.
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

One event type, 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).

Headers

Body

That’s the whole body. There is no app id, creative id, or event id, and no nesting: the payload is flat, exactly the seven fields above. 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:
HMAC-SHA256 that string with your 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 any 2xx 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:
  1. Required: deduplicate on transactionId. Take it from the signed request body. Every retry of a conversion carries the same value. Do not key on X-Webhook-Delivery-Id or X-Webhook-Attempt. Both sit outside the signature base string and are not authenticated.
  2. Recommended: return 2xx only once the credit is durably committed, not on receipt. If you acknowledge first and credit asynchronously, a failure in that async step is invisible to us: we will not retry, because you already returned 2xx, and the user is silently uncredited.

URL requirements