Skip to main content

Configuration

Meridian configures webhook endpoints during provisioning.
You can register separate URLs for Sandbox and production. Meridian registers endpoints per event name, so you need an endpoint for each event you want to receive. Meridian does not deliver an event that has no endpoint. You can register the same URL for several events. If you do, your handler must route them based on the event headers. To receive the payment_link_transaction_* events, ask Meridian to register an endpoint for each of the four event names.

Event routing

Before you parse the body, use the X-Meridian-Resource-Type and X-Meridian-Event-Type headers to identify which resource the event belongs to and which specific event occurred. The three payment_link events carry the same Payment Link payload, so read the headers first to tell them apart, then deserialize the body with the webhook schema. Other payment link status transitions, including PROCESSING, FAILED, EXPIRED, LOCKED, and INACTIVE, do not emit a payment_link webhook. The four payment_link_transaction events carry the same Payment Link Transaction payload: the payment link and the transaction. The body has no envelope, so the event name is only in the X-Meridian-Event-Type header. Meridian sends a payment_link_transaction webhook every time a payment link transaction changes status, for single and recurring links.
  • Each status change sends exactly one event. If Meridian writes the same status twice, you receive one webhook.
  • A reversal sends payment_link_transaction_status_updated at REVERSAL_IN_PROGRESS, and payment_link_transaction_failed only when it reaches REVERSED.
  • One transaction can send payment_link_transaction_failed more than once, because each failure status is its own change. For example, FAILED then DEBIT_FAILED, or COMPLETED then RETURNED after an ACH return. Handle repeated failed events for the same transaction.id, and treat transaction.status and transaction.previousStatus as the source of truth.
  • The paymentLink object is a snapshot from when Meridian sent the webhook. Meridian updates the link and the transaction separately, so the link’s status can lag the transaction. Use transaction.status for the payment outcome, and fetch the link through the API if you need its final state.
Payment link transactions no longer send the generic transaction_created, transaction_succeeded, and transaction_failed events. They send the payment_link_transaction_* events instead. REVERSAL_IN_PROGRESS used to be reported as a failure and is now a payment_link_transaction_status_updated event. Statuses such as PROCESSING and USER_DEDUCTED were not reported before. The transaction_* events are unchanged for Meridian Accounts.
For a walkthrough of the status flow, see Tracking a payment link payment with webhooks.

Security

Webhook requests, including the payment_link_transaction events, 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: Validate the signature on every inbound request before processing the payload. Use the same canonical string construction described in Authentication, 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. Choose a tolerance that suits your infrastructure. Meridian rejects inbound API requests more than 10 seconds old, which is a reasonable reference point. However, retries mean a redelivered webhook can legitimately arrive much later than its original timestamp.
Do not reject a webhook solely because its timestamp is old. For payment_link events, Meridian retries for up to 10 attempts with doubling intervals, so a valid retry can arrive minutes after the event.

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. Delivery of payment_link_transaction events is best effort. If your endpoint does not return a 2xx response, Meridian retries up to 3 times, a few hundred milliseconds apart. Meridian then raises an internal alert for undelivered payment_link_transaction_succeeded and payment_link_transaction_failed events. It is not a guaranteed, replayable queue, so reconcile through the API. Meridian does not guarantee delivery order. Use transaction.updatedAt to order events for the same transaction. Key your idempotency check on transaction.id plus transaction.status.

Duplicates

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.