# Webhook Retry Policy

When Pay.io delivers a webhook to your configured endpoint, it expects a **`2xx` response** within **5 seconds**. If no valid response is received within that window, the delivery is considered failed and Pay.io will **automatically** **attempt** **redelivery** according to the [retry schedule below](#automatic-retries).

### Delivery Lifecycle

Every webhook delivery follows the same progression from initial attempt through to escalation:

{% stepper %}
{% step %}

#### Initial delivery

`POST` sent instantly to your configured endpoint. A `2xx` response is expected within 5 seconds.
{% endstep %}

{% step %}

#### Automatic retries (if initial delivery fails)

Up to 50 attempts

Linear back off kicks in when the initial delivery fails. Each attempt waits longer before retrying. See the [table of attempts and delays below](#automatic-retries).
{% endstep %}

{% step %}

#### Manual retries (if webhook status is `CALLBACK_FAILED`)

Up to 3 merchant-initiated attempts via the Merchant Console. When status is `CALLBACK_FAILED`, the Merchant can re-trigger delivery from the Merchant Console at any time. Tracked independently of automatic retries.

Available for Deposits and Payouts.
{% endstep %}

{% step %}

#### Support escalation

If all automatic and manual attempts exhausted. Contact Pay.io support to manually re-trigger delivery.
{% endstep %}
{% endstepper %}

### Automatic Retries

Failed webhook deliveries are retried automatically using a **linear backoff** strategy. The delay between each attempt is calculated as:

```
delay = attempt number × 10 minutes
```

| Attempt | Delay After Previous Failure |
| ------- | ---------------------------- |
| 1       | 10 minutes                   |
| 2       | 20 minutes                   |
| 3       | 30 minutes                   |
| 4       | 40 minutes                   |
| …       | …                            |
| 50      | 500 minutes (\~8.3 hours)    |

A maximum of **50 retry attempts** are made. Once all attempts are exhausted, the webhook is marked as **permanently failed** and no further automatic deliveries will be attempted.

### Manual Retries

In addition to automatic retries, merchants can manually re-trigger webhook delivery from the **Merchant Console** at **any time** whilst the callback status is `CALLBACK_FAILED`.

#### **Manual retry rules**

* Manual retries are available for both **Deposits** and **Payouts** with a status of `CALLBACK_FAILED`.
* A maximum of **3 manual retry attempts** are permitted **per transaction**.
* Manual retries are tracked independently of automatic retries — exhausting automatic attempts does not consume your manual retry allowance, and vice versa.
* Once all 3 manual retry attempts have been used, contact Pay.io support to request further assistance with redelivery.

***

### Best Practices

**Respond immediately, process asynchronously**

Your endpoint should return a `2xx` status code as soon as the webhook payload is received — even if you have not yet finished processing it. Queue the payload for processing in the background. Delaying your response to complete processing first risks exceeding the 5-second response window and triggering the retry cycle unnecessarily.

**Set up internal alerts for early-stage failures**

Automatic retries are designed to handle transient endpoint issues. However, as the attempt number increases, so does the delay before the next retry — reaching over 8 hours by attempt 50. Waiting for the automatic retry schedule to resolve a failure is rarely the right approach for time-sensitive transactions such as deposits or withdrawal confirmations.

{% hint style="success" %}
**We strongly recommend** configuring your own internal monitoring to alert your team when a webhook enters `CALLBACK_FAILED` status. This allows you to assess and resolve the underlying issue promptly, and to use your **manual retry allowance** to redeliver the webhook as soon as your endpoint is healthy — rather than waiting hours for the next automatic attempt.
{% endhint %}

A practical alerting threshold to consider:

| Automatic Attempt Reached | Cumulative Delay          | Recommended Action                              |
| ------------------------- | ------------------------- | ----------------------------------------------- |
| 3                         | \~60 minutes              | Investigate endpoint health                     |
| 5                         | \~150 minutes             | Trigger internal alert to your engineering team |
| 10                        | \~550 minutes (\~9 hours) | Escalate and initiate manual retry immediately  |

**Use manual retries before automatic attempts are exhausted**

Your 3 manual retry attempts are a valuable tool for recovering from delivery failures quickly — particularly when the automatic retry schedule has reached a long delay window. Do not wait until automatic retries are fully exhausted before intervening. If your endpoint is healthy and a webhook has been waiting for hours, trigger a manual retry from the Merchant Console to resolve the delivery immediately.

{% hint style="info" %}
Manual and automatic retry attempts are tracked independently. However, once both are exhausted for a given transaction, Pay.io will not attempt further automatic redelivery. If you reach this state, contact Pay.io support as soon as possible.
{% endhint %}

**Ensure your endpoint is idempotent**

Because the same webhook event may be delivered more than once — across both automatic and manual retry attempts — **your endpoint must be built to handle duplicate deliveries safely**. Use the **transaction ID** included in the webhook payload as an idempotency key to ensure that processing the same event multiple times does not result in duplicate operations on your platform.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.pay.io/api-reference/core-concepts/webhook-retry-policy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
