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

# Delivery and reliability

> Understand retry behavior, delivery guarantees, timeout requirements, and best practices for consuming webhooks.

Anchorage Digital webhooks use at-least-once delivery. Every event notification is retried until your endpoint confirms receipt with a successful response, or until the retry limit is reached. Because webhooks carry money-movement events, we recommend designing your consumer for reliability from the start.

## Delivery guarantees

Anchorage Digital guarantees **at-least-once delivery** for every webhook event. This means:

* Every event fires at least one delivery attempt to each subscribed endpoint.
* The same event may be delivered more than once. Use the `message_id` field to deduplicate.
* Events are not guaranteed to arrive in the order they occurred. Your consumer should handle out-of-order delivery gracefully.

## Retry behavior

We redeliver on any non-2xx response, including 5xx errors, connection failures, and timeouts. Successful delivery requires an HTTP 2xx response from your endpoint.

| Parameter          | Value                                                 |
| :----------------- | :---------------------------------------------------- |
| Retry attempts     | Up to 50 per event                                    |
| Backoff strategy   | Exponential, starting at 1 second                     |
| Maximum interval   | 2 hours between attempts                              |
| Total retry window | 75+ hours                                             |
| Final status       | Permanently canceled after all attempts are exhausted |

After all retry attempts are exhausted, the notification is permanently canceled and won't be redelivered. The endpoint registration stays active and continues to receive future events.

<Note>
  We don't auto-disable endpoints after consecutive failures. Failed notifications are canceled individually after retry exhaustion, but your endpoint configuration and subscriptions remain unchanged.
</Note>

## Consumer endpoint requirements

Your endpoint must meet these requirements to receive webhook notifications reliably.

| Requirement      | Detail                              |
| :--------------- | :---------------------------------- |
| Response timeout | Respond within **5 seconds**        |
| Success response | Return any HTTP **2xx** status code |
| HTTPS            | Endpoint URL must use HTTPS         |

<Tip>
  Acknowledge the webhook immediately and process the event asynchronously. This keeps your response time well within the 5-second window and prevents retries caused by slow processing.
</Tip>

## Idempotency and deduplication

Each webhook message includes a unique `message_id`. Because at-least-once delivery means duplicates are possible, treat `message_id` as an idempotent key:

1. Store each `message_id` you process.
2. Before processing a new message, check whether you've already handled that `message_id`.
3. Skip duplicate messages to avoid double-processing.

The `message_id` is a UUID assigned when the event is created. It stays the same across all delivery attempts for that event — if the same message is retried, you'll see the same `message_id`. Each distinct event produces exactly one `message_id`, so you won't receive the same event under different IDs.

<Note>
  The `timestamp` field reflects when each delivery attempt is made, not when the event originally occurred. This means the `timestamp` may differ between retries of the same `message_id`. Use `timestamp` to validate event freshness, but use `message_id` for deduplication.
</Note>

## Handling out-of-order events

Webhook events may arrive out of order. For example, a `withdrawal.completed` event could arrive before the corresponding `withdrawal.initiated` event if delivery of the first event was delayed by retries.

To handle this:

* Use the `timestamp` field to determine the actual sequence of events.
* Design your state machine to accept transitions from any prior state, not just the immediately preceding one.
* When correlating events to transactions, fetch the current transaction status from the API as the source of truth rather than relying solely on webhook event order.

For details on correlating webhook events to transactions, see [Track transaction status](/knowledge-base/platform/developers/move-money/operate/track-status).

## Monitoring and failure notifications

We don't send automatic alerts when individual notifications exhaust their retries. Delivery status is tracked internally for incident investigation.

To monitor webhook health on your side:

* Log every incoming webhook and its `message_id`.
* Track the gap between the event `timestamp` and your receipt time to detect delivery delays.
* Periodically reconcile webhook events against API transaction data to catch any missed notifications. Use [List transactions](/knowledge-base/api-reference/v2/transactions/list-transactions) to fetch the latest state.

## Validation key

The webhook validation key is a hex-encoded Ed25519 public key used to verify the `Api-Signature` header. You can retrieve it at any time via the [Get webhook validation key](/knowledge-base/api-reference/v2/webhook-notifications/get-webhook-validation-key) endpoint.

There is no automatic key rotation. If a key change is required, Anchorage Digital will coordinate directly with affected clients. There is no `key-id` header — the current validation key is always the correct one to use for signature verification.

<Note>
  The validation key (hex-encoded Ed25519) is a different key from the optional endpoint encryption key (PEM-encoded secp256k1). For details on payload encryption, see [Payload encryption](/knowledge-base/platform/developers/webhooks/webhooks-configure#payload-encryption-optional).
</Note>

## Best practices

* **Respond fast, process later.** Return a 2xx response as soon as you receive the webhook, then process the payload asynchronously. This avoids unnecessary retries.
* **Deduplicate with `message_id`.** At-least-once delivery means you may receive the same event more than once.
* **Validate signatures first.** Always [verify the `Api-Signature` header](/knowledge-base/platform/developers/webhooks/webhooks-configure#validate-the-signature-and-decode-the-payload) before processing any webhook payload.
* **Handle unknown event types gracefully.** New event types may be added over time. Your consumer should ignore unrecognized `event_type` values rather than failing.
* **Reconcile periodically.** Don't rely on webhooks as your only data source for critical flows. Use the API to periodically verify transaction states, especially for money-movement operations.
