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

# Webhooks

> Learn how Meridian delivers real-time event notifications to your system via HTTP POST webhooks, including configuration, security, and retry behavior.

## Configuration

<Info>
  Meridian configures webhook endpoints during provisioning.
</Info>

You can register separate URLs for Sandbox and production — Meridian delivers all events for a given environment to a single endpoint. If you need to route events differently, your handler must direct them based on the event headers.

## Event routing

Use the `X-Meridian-Resource-Type` and `X-Meridian-Event-Type` headers to identify the webhook before you parse the body. These headers tell you which resource the event belongs to and which specific event occurred.

| Header                     | Example values                  | Use                                                |
| :------------------------- | :------------------------------ | :------------------------------------------------- |
| `X-Meridian-Resource-Type` | `payment_link`                  | Routes the payload to the correct resource handler |
| `X-Meridian-Event-Type`    | See the event types table below | Identifies the specific event for that resource    |

| Resource       | Event types                                                               |
| :------------- | :------------------------------------------------------------------------ |
| `payment_link` | `payment_link_created`, `payment_link_completed`, `payment_link_archived` |

All three events carry the same [Payment Link](/products/realtime-collections/api-reference/webhooks/webhooks-payment-link) payload, so read the headers first to tell them apart, then deserialize the body with the webhook schema. Other status transitions, including `PROCESSING`, `FAILED`, `EXPIRED`, `LOCKED`, and `INACTIVE`, do not emit a webhook.

## Security

Webhook requests use the same HMAC SHA-256 scheme as the REST API, but with a **dedicated Webhook API Key and Secret** issued separately from your REST API credentials. Each request includes the following headers:

| Header                 | Description                                                |
| :--------------------- | :--------------------------------------------------------- |
| `X-Meridian-Api-Key`   | Issued by Meridian, specifically for Webhooks              |
| `X-Meridian-Timestamp` | Epoch milliseconds at the moment Meridian sent the request |
| `X-Meridian-Signature` | HMAC SHA-256 signature                                     |

Validate the signature on every inbound request before processing the payload. Use the same canonical string construction described in [Authentication](/products/realtime-collections/authentication#constructing-the-signature), with one difference: the signature covers the **path only** of your webhook URL, not its query string. If your endpoint URL includes query parameters, exclude them when rebuilding the canonical string, or the signature will not match.

**You decide the acceptable timestamp age.** Meridian stamps `X-Meridian-Timestamp` when it sends the webhook and does not enforce a window on its own deliveries, so choose a tolerance that suits your infrastructure. Meridian rejects inbound API requests more than 10 seconds old, which is a reasonable reference point, but retries mean a redelivered webhook can legitimately arrive much later than its original timestamp.

<Warning>
  Do not reject a webhook solely because its timestamp is old. Meridian retries for up to 10 attempts with doubling intervals, so a valid retry can arrive minutes after the event.
</Warning>

## Delivery and retries

Meridian considers a webhook delivered when your endpoint returns an HTTP `2xx` response. If the request times out or returns a non-`2xx` status, Meridian retries using exponential backoff — the first retry is after 2 seconds and the interval doubles each time, up to **10 attempts**.

Because retries can result in duplicate deliveries, your webhook handler should be **idempotent** — processing the same event more than once should produce the same outcome.
