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

# Webhooks

> Set up Webhooks from Shift to receive real-time notifications from Paylead on Program events, verify their authenticity, and audit the delivery history.

export const RequiredRoles = ({roles}) => <Note>
    <strong>Required Shift role:</strong> {roles}. See <a href="/program/shift/access-and-roles">Users management</a> for the full role matrix.
  </Note>;

<RequiredRoles roles="Technical" />

[Webhooks](/glossary#webhooks) let Paylead push notifications to your back-office the moment something happens on your [Program](/glossary#program): a [Reward](/glossary#reward) is created, a [Consumer](/glossary#consumer)'s bank synchronization fails, an [Offer](/glossary#offer) is about to expire. From [Shift](/glossary#shift), you declare which URL receives each event type, verify that deliveries genuinely come from Paylead, and inspect the dispatch history.

Subscribe to an event when your back-office has to act on it: notify a Consumer, release a payout file, open a support ticket. Polling the API answers "what is true now"; a Webhook answers "something just changed" within seconds. For read-only screens and dashboards, query the API when the user opens them.

This page covers the Shift screens. For the technical contract your endpoint implements (payload shape, retry policy, idempotency), see the [Webhooks concept](/program/user-journey/concepts/webhooks). Your system also needs an [API key](/program/shift/api-keys) to call back into the Platform.

## Set up a Webhook

Each event type is configured independently and points at a single callback URL on your side. In Shift, go to **My account** > **Developers** > **Hooks**. The left side lists every event type Paylead supports.

<Steps>
  <Step title="Pick the event you want to subscribe to">
    Click the **+** next to the event. Its configuration panel opens on the right. Each event carries one callback URL at a time, so an event you already subscribed to is greyed out. To fan an event out to several internal systems, point it at one endpoint of yours and dispatch from there.
  </Step>

  <Step title="Enter the callback URL">
    In the **Callback URL** field, enter the HTTPS endpoint that will receive the event. The endpoint must accept `POST` with a JSON body and respond `2xx` quickly.
  </Step>

  <Step title="Validate with a test delivery">
    Click **Send test**. Paylead immediately posts a payload to the URL with mock data: non-nullable fields carry sample values, nullable fields are left blank.
  </Step>

  <Step title="Save your changes">
    Click **Save**. The Webhook is live and Paylead dispatches real events to it from this moment forward.
  </Step>
</Steps>

Nothing is written until you click **Save**: adding an event, editing a URL, and removing a card all stay local until then. To remove a Webhook, click the bin icon in the header of its card, confirm the dialog, then click **Save**. The Webhook keeps receiving events until you do.

A subscription covers what happens after you save it. When you add one to a live Program, backfill the gap by querying the API for the objects you missed.

## Authenticate deliveries

Anyone who discovers your callback URL can post a fake payload to it. Verify each delivery before you act on it.

Credentials are set once for the whole Program. On the Hooks page, click **Settings** in the top right to open the credentials dialog. It offers three independent mechanisms, each enabled by its own checkbox:

| Mechanism | Fields |
| - | - |
| **Basic authentication** | **Username** and **Password**. |
| **HMAC authentication** | **Secret**, 32 characters minimum, alphanumeric only. |
| **Header authentication** | **Key** (appended to a fixed prefix that Shift displays before the field) and **Value**. |

Tick as many as you need, fill in their fields, then click **Confirm**. Clearing a checkbox deletes that credential.

<Note>
  The **Settings** button is hidden when your Program signs in through SSO.
</Note>

Paylead signs every request with HMAC-SHA256 over the raw request body, using the secret from the **HMAC authentication** block. The signature travels in the `X-paylead-signature-256` header as a hex digest, and an optional `X-paylead-timestamp` header protects against replay. Paylead can also set up mutual TLS on request: see [Securing your endpoint](/program/user-journey/concepts/webhooks#securing-your-endpoint).

<Warning>
  Verify against the raw request body, not the parsed JSON. Re-serializing the payload changes the bytes and breaks the signature.
</Warning>

## Available events

Paylead groups events the same way Shift does, under Cashbacks, Payments, Consumers, and Offers. Subscribe only to the events your back-office reacts to: every extra subscription is traffic your endpoint has to accept, authenticate, and acknowledge in time.

### Cashbacks

| Event key | Description |
| - | - |
| `REWARD_CREATED` | A transaction is eligible for a [Cashback](/glossary#cashback). The Reward is visible to the Consumer in your app. |
| `REWARD_VALIDATED` | The Reward has not been cancelled by the merchant. It will be invoiced to the merchant at the end of the month. |
| `REWARD_PAID_IN` | The Reward amount has left the merchant's wallet for the [Program Manager](/glossary#program-manager)'s. Shift prints this moment as the `Pool` status. |

### Payments

| Event key | Description |
| - | - |
| `REWARD_PAID_OUT` | The Consumer pool has been triggered and the Reward transferred to the payment account. Shift prints this moment as the `Paid` status. |
| `PAYOUT_SUCCESS` | Two wire transfers have been sent to the Program account: one for the sum of the Rewards, one for the associated fees. |
| `PAYOUT_ERROR` | A transfer error occurred, preventing the Reward from being paid to the Consumer account. |
| `VENTILATION_FILE_AVAILABLE` | A [Ventilation](/glossary#ventilation) file is available for download. |

`PAID_IN` and `PAID_OUT` name a movement of money, and Shift prints the matching Reward statuses as `Pool` and `Paid`. Check the [Status reference](/program/shift/status-reference#pool) before you wire an event to something a support agent will be asked about.

### Consumers

| Event key | Description |
| - | - |
| `SCRAPPING_ERROR` | Deprecated. A bank synchronization failure has blocked the Consumer's transaction feed. |
| `CONSUMER_REWARD_POOLED` | The Consumer can be notified that a Reward has been deposited in their pool. |
| `CONSUMER_REWARD_PAID` | The Reward has been paid to the Consumer's account. |
| `CONSUMER_REWARD_CANCELLED` | The Reward was cancelled before being paid (refund, dispute, or expiry). |
| `CONSUMER_REWARD_VALIDATION` | A Reward has been created and is in `Pending validation` status. |

`SCRAPPING_ERROR` is deprecated: do not subscribe to it for a new integration. On a Program that still receives it, it tells you a Consumer stopped feeding transactions to Paylead, so they also stopped earning Cashback without necessarily noticing. Only the Consumer can unblock it.

Read the Consumer's bank synchronization status in Shift to know what to ask for. `SCA_REQUIRED` and `WEBAUTH_REQUIRED` need the Consumer to redo an authentication flow, `ACTION_NEEDED` sends them to their bank's website, and `WRONG_PASS` means their stored credentials are stale. See the [Status reference](/program/shift/status-reference#bank-synchronization) for the full list.

### Offers

| Event key | Description |
| - | - |
| `NEW_OFFER_AVAILABLE` | A new Offer has been published and is available to Consumers. |
| `OFFER_ENDING_SOON_DATE` | An Offer is about to expire. The Webhook is sent when the end date is less than 3 days away. |
| `OFFER_ENDING_SOON_BUDGET` | The Offer budget is close to depletion. The Webhook is sent once the Campaign has consumed 90% of its [budget](/glossary#budget). |
| `OFFER_CASHBACK_RATE_INCREASE` | The Cashback rate of an Offer has been increased. |

Use the two `OFFER_ENDING_SOON_*` events to warn Consumers while an Offer is still redeemable. The subscription tooltip in Shift announces the budget event at 80% of the budget, while the threshold applied server side is 90%: reconcile on the event, not on the tooltip.

## Event logs

**Event logs** is the landing entry of the **Developers** menu, reached from **My account** > **Developers**. It lists every Webhook delivery attempted on your Program, so it shows exactly what Paylead sent you. Go there when your back-office looks out of sync with the platform, or right after you put a new endpoint live.

| Column | Description |
| - | - |
| **Date** | When the event was dispatched. |
| **Consumer** | The Consumer ID the event relates to, when applicable. |
| **Type** | The Webhook event type. |
| **URL** | The callback URL that received the event. |
| **Status** | The HTTP status code returned by your endpoint. Shift marks any code below `300` as a success. |
| **Next Try** | When the delivery will be retried. Reads `Max retries reached` once Paylead stops retrying, and `-` when the status code is never retried. |

Four filters scope the history: a keyword search, **Filter by type** (one event type), **Filter by status** (a status family, from `1xx` to `5xx`, plus **Others**), and the **Date From** / **Date to** range. Without filters, every event since the Program launched is shown.

### When a delivery fails

Paylead drives the retries on its own, and what happens next depends only on the status code your endpoint returned.

| What you see in **Next Try** | What it means | What to do |
| - | - | - |
| A date | Paylead will try again on its own. Server errors qualify, and so do `408`, `425`, and `429`. | Fix the endpoint before that date and the retry lands. |
| `Max retries reached` | The delivery was retryable, and Paylead has stopped trying. | Re-fetch the affected objects from the API to catch up. |
| `-` | The code is never retried, which covers most client errors. A `404` or a `403` is a configuration problem on your side, not a transient one. | Fix the URL or the authentication, then use the API to catch up on what you missed. |

Each delivery carries a unique `event_id`. Persist it on your side and dedupe on it, since Paylead may redeliver the same event after retries. See [Re-fetch before acting](/program/user-journey/concepts/webhooks#re-fetch-before-acting) for the recommended pattern.

<Warning>
  A day of downtime on your endpoint is a day of events you will not receive twice. Webhooks are a trigger, not a ledger: keep a path that reconciles your data from the API, and use Event logs to scope how far back to reconcile.
</Warning>

## What's next

<CardGroup cols={2}>
  <Card title="Webhooks reference" icon="zap" href="/program/user-journey/concepts/webhooks">
    Payload shape, retry policy, and reliability guidance for your endpoint.
  </Card>

  <Card title="API reference" icon="code" href="/program/api/releases">
    Browse and download the current Platform API specification.
  </Card>
</CardGroup>
