When to use this
Follow this guide if you bill subscriptions through Stripe (the approach generalizes to any self-managed biller) and want those events in Encore. If you use RevenueCat, Superwall, or store server notifications, point those at their dedicated receivers instead.How it fits together
Encore joins a subscription back to the user it showed an offer to using two values:- The app account id — read on the client with
Encore.getAppAccountId(). - Your biller’s subscription id — sent as
subscription.original_transaction_id.
client_reference_id, persist it keyed by
the subscription id, then send both values on every event you forward. Encore (re)writes
the link on every event, so user.app_account_id is required each time — see
How the join works in
the reference.
Walkthrough
Set a stable user id
Call
identify() once you know who the user is.
This makes the app account id your own stable id, so the same person resolves consistently
across devices and sessions.Read the app account id and start checkout
At checkout, read the app account id and pass it to your server so it can attach it to the
Stripe Checkout Session.
Attach client_reference_id on the server
Set the app account id as
client_reference_id so it round-trips back on the webhook. Also
stamp it into the Subscription’s metadata so later subscription events carry it too.Forward the subscribe event to Encore
In your Stripe webhook handler, read the app account id from
client_reference_id, persist
it keyed by the subscription id (you will need it for events that don’t carry it), then sign
and POST a did_subscribe event.The buildEncoreHeaders helper below is the
shared signing helper from the reference —
import it rather than reimplementing the HMAC. It signs the composite
<timestamp>.POST./webhooks/encore.<raw_body> string and returns the auth headers.Forward later lifecycle events — with app_account_id on every one
For renewals, cancellations, refunds, and the rest, map the Stripe event to the matching
Encore verb. Every event must include
user.app_account_id — omitting it fails
validation and the event is dropped. Resolve it from the Subscription’s metadata (set in
step 3) or from the mapping you persisted in step 4.If you cannot resolve an
app_account_id for an event, the join cannot be made — fix the
lookup rather than sending the event without it. An event missing user.app_account_id is
acknowledged with 200 { "message": "Received (processing deferred)" } but dropped. See
Responses.Event verbs
Map your billing events to Encore’s canonical verbs:did_subscribe, did_renew, did_cancel, did_resubscribe, did_expire,
did_enter_grace_period, did_enter_billing_retry, did_pause, did_change_product,
did_refund.
Next steps
- Webhook Ingestion reference — the full contract: headers, signing helper, payload schema, responses, idempotency.
- identify() — set a stable user id for a robust cross-device join.