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

# Webhook Retry Mechanism

> Singapay automatically retries failed webhook deliveries to ensure reliable communication between our system and your server.

When Singapay sends a webhook to your endpoint and does not receive a valid response, the system will automatically retry the delivery. Retries are designed to handle temporary disruptions such as timeouts, server downtime, or connection errors.

<Info>
  Each retry is performed with a **1-minute interval** between attempts. If all retries are exhausted, a failure notification will be sent to your registered merchant email.
</Info>

## Retry Rules by HTTP Status

The number of retry attempts depends on the HTTP response status returned by your endpoint.

| HTTP Status / Condition                      | Handler                      | Max Retries | Description                                                |
| -------------------------------------------- | ---------------------------- | ----------- | ---------------------------------------------------------- |
| `500` Internal Server Error                  | `handleFailedHttpResponse()` | 1           | Your server encountered an internal error.                 |
| `503` Service Unavailable                    | `handleFailedHttpResponse()` | 4           | Your server is temporarily unreachable.                    |
| `400` / `404` Bad Request / Not Found        | `handleFailedHttpResponse()` | 2           | Endpoint may be incorrect or temporarily unavailable.      |
| `307` / `308` Temporary / Permanent Redirect | `retryRedirect()`            | 5           | Redirects are followed up to 5 times.                      |
| `301` / `302` / `303` Redirect               | `handleFailedHttpResponse()` | 0           | Redirects are **not** followed — update your endpoint URL. |
| Exception (cURL error, timeout, DNS)         | `catch(Exception $e)`        | 1           | Connection-level failures.                                 |
| Other (default)                              | `handleFailedHttpResponse()` | 5           | All other status codes not listed above.                   |

<Warning>
  Redirects via `301`, `302`, or `303` will **not** be followed and receive **zero retries**. Make sure your webhook URL points directly to the correct endpoint.
</Warning>

## Retry Interval

<CardGroup cols={2}>
  <Card title="Interval Between Retries" icon="clock">
    Each retry attempt is made **1 minute** after the previous one. Retries stop once the maximum limit for that status code is reached.
  </Card>

  <Card title="Retry Cache TTL" icon="database">
    Retry counts are stored in cache with a **15-minute TTL**. All attempts are logged to our database for auditing.
  </Card>
</CardGroup>

## Example: HTTP 503 Retry Flow

Here's what happens when your endpoint consistently returns `503`:

<Steps>
  <Step title="Attempt #1">
    Singapay sends the webhook. Your server responds `503`. System schedules a retry in 1 minute.
  </Step>

  <Step title="Attempt #2">
    First retry. Still `503`. Another retry scheduled in 1 minute.
  </Step>

  <Step title="Attempt #3">
    Second retry. Still `503`. Another retry scheduled.
  </Step>

  <Step title="Attempt #4 (Final)">
    Third and final retry. Still `503`. No more retries. Failure logged and notification email sent.
  </Step>
</Steps>

<Note>
  Total maximum delivery time for a `503` scenario: approximately **4 minutes** across all attempts.
</Note>

## What Happens After All Retries Fail

If the webhook cannot be delivered after all retry attempts:

1. The failure is **logged in the database** and visible via the Callback menu on your merchant dashboard.
2. A **failure notification email** is sent to your registered merchant email address.

## Best Practices

<CardGroup cols={3}>
  <Card title="Return 2xx" icon="circle-check">
    Always respond with an HTTP status between `200–299` to acknowledge receipt.
  </Card>

  <Card title="Stay Available" icon="server">
    Keep your webhook endpoint stable and publicly accessible at all times.
  </Card>

  <Card title="Avoid Redirects" icon="ban">
    Do not use redirect URLs (`301–308`) as your webhook endpoint.
  </Card>
</CardGroup>

<Tip>
  Process webhooks asynchronously — return `200 OK` immediately and handle the payload in a background job to avoid timeouts.
</Tip>
