> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encorekit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# offer_payout_booked webhook

> Payload contract for the offer_payout_booked webhook: the USD payout Encore booked for a paying action it already reported, usually one that verified at $0; never a new completion or a reward.

When the conversion that verifies a transaction is priced in a currency other than USD, Encore does not convert it automatically: the [`offer_completed`](https://docs.encorekit.com/publishers/offers-api/reference/offer-completed-webhook) it sends carries `payout: 0`. When Encore later books the conversion at a USD figure, it can send you `offer_payout_booked`: that figure, for the same `transactionId` and paying action. The same event reports a booking for any other paying action Encore already sent an `offer_completed` for. A paying action Encore never sent an `offer_completed` for gets no `offer_payout_booked`: its first `offer_completed` carries the booked figure instead.

> [!WARNING]
>
> **Never credit a reward on this event.** Credit only on `offer_completed`, once per `transactionId`. This event only corrects a payout figure. A handler that credits on every request without reading `event` would pay the user twice, which is why this event is off until you ask for it.

## Turning it on

Encore sends it only to a webhook subscribed to it. Every webhook starts subscribed to `offer_completed` only. To subscribe, confirm to Encore support that your handler switches on `event` and never credits on `offer_payout_booked`, and ask for payout updates on your app. Without the subscription, Encore still books the figure; only the notice to your server is skipped.

To unsubscribe, ask Encore support. Payout updates still waiting for a retry are then dropped. An `offer_completed` is never dropped this way.

Deleting and re-creating your webhook also unsubscribes it: the new webhook starts at `offer_completed` only, and queued payout updates are dropped until you ask to subscribe again.

## When Encore sends it

When Encore books a USD figure for a conversion priced in another currency, what your webhook receives depends on which conversion it is:

| Conversion booked | Subscribed webhook | Webhook not subscribed |
| - | - | - |
| The one the transaction verified on at `payout: 0`, or any other paying action Encore already sent an `offer_completed` for | `offer_payout_booked` | Nothing |
| A paying action Encore never sent an `offer_completed` for | `offer_completed` with the booked figure, its first notice | `offer_completed` with the booked figure, its first notice |

The conversion the transaction verified on always counts as already sent, so Encore never sends a late first `offer_completed` for it, even if your webhook did not exist or was turned off when it verified. If your app has no webhook, or it is turned off, when the figure is booked, Encore sends nothing.

## The request Encore sends

Same URL, headers, signature and delivery guarantees as [`offer_completed`](https://docs.encorekit.com/publishers/offers-api/reference/offer-completed-webhook#the-request-encore-sends): an HMAC-SHA256 signature over `<X-Webhook-Timestamp>.<raw_body>`, and the same `2xx` deadline and retry schedule.

```json theme={null}
{
  "event": "offer_payout_booked",
  "timestamp": "2026-10-20T14:03:11.000Z",
  "transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "userId": "usr_9f8e7d6c-5b4a-3210-fedc-ba0987654321",
  "campaignId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "campaignName": "Audible Premium Plus",
  "actionId": "3f2b8c1e-9d4a-4e7b-8a6f-1c2d3e4f5a6b",
  "payout": 32.55,
  "payoutCurrency": "USD",
  "previousPayout": 0,
  "bookedAt": "2026-10-20T14:03:10.412Z"
}
```

| Field | Type | Description |
| - | - | - |
| `event` | string | Always `"offer_payout_booked"`. |
| `timestamp` | ISO 8601 string | UTC, milliseconds, trailing `Z`: when Encore generated this delivery, as on `offer_completed`. |
| `transactionId` | string (UUID) | The transaction whose payout changed. |
| `userId` | string | The end-user identifier your app supplied, verbatim, as on `offer_completed`. |
| `campaignId` | string (UUID) | The offer, as on `offer_completed`. |
| `campaignName` | string | Display name of the campaign; not a stable identifier. |
| `actionId` | string (UUID) | The paying action whose payout changed. Always present on this event. If the earlier `offer_completed` for it carried an `actionId`, this is the same value; an `offer_completed` sent without one was for this action. |
| `payout` | number | The booked payout, in USD. |
| `payoutCurrency` | string | Always `"USD"`. |
| `previousPayout` | number | The payout the earlier `offer_completed` for this action carried: `0` when the transaction verified on a conversion priced in another currency (the usual case). Also `0` when that delivery carried `null`, or when Encore never sent one for the action the transaction verified on. |
| `bookedAt` | ISO 8601 string | When Encore booked the figure. |

There is no `reward` field: this event never carries one.

## What to do with it

1. **Switch on `event`.** Route `offer_payout_booked` to your payout records, never to your credit logic.
2. **Update the payout for `transactionId` plus `actionId`.** If you hold no `offer_completed` with this `actionId`, but hold one for this `transactionId` without an `actionId`, update that one. Use `(transactionId, actionId, event)` from the signed body to deduplicate. Do not key on `X-Webhook-Delivery-Id`, which sits outside the signature.
3. **The booked payout wins.** Ordering is not guaranteed: the earlier `offer_completed` for the same action can still be retrying when this arrives. For one `transactionId` plus `actionId`, keep this event's `payout` whichever arrives first, and never overwrite it with the `payout` of an `offer_completed` that arrives later. This event only reaches you for an action Encore already sent an `offer_completed` for, or the one the transaction verified on. For any other paying action, the booked figure arrives as that action's first `offer_completed`, so do not wait for an `offer_payout_booked` there.
4. **A transaction you have no completion for:** this happens when the `offer_completed` never reached you, for example because your webhook did not exist or was turned off when the transaction verified, or your endpoint was down for the whole retry window. Record the payout and reconcile from your dashboard. Still never credit a reward.

## Related

* [offer\_completed webhook reference](https://docs.encorekit.com/publishers/offers-api/reference/offer-completed-webhook.md): the completion event, its signature, and its guarantees.
* [Receive Completion Events guide](https://docs.encorekit.com/publishers/offers-api/guides/receive-completion-events.md): verification handler, idempotency, reconciliation.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.