# Webhooks

> Webhooks are notifications of events that occur in the Shuttle system.

Webhooks are notifications of events that occur in the Shuttle system.

## Webhook destinations

Webhook targets are set at two levels:

| Level | Field | Scope |
|---|---|---|
| Application | `webhook_target` on the application | Default destination for every instance in the application |
| Instance | `webhook_target` on the instance | That instance only |

**An instance target replaces the application target — events are not sent to both.** Where an instance has its own `webhook_target`, events for that instance are delivered only to the instance target, and the application destination receives nothing for that instance. Instances with no `webhook_target` of their own fall back to the application destination.

To deliver an instance's events to both, set the instance `webhook_target` to a fan-out target listing both URLs — see [Webhook configuration](#webhook-configuration).

## Handling webhooks

- Webhooks are sent to a HTTPS endpoint on your server
- Webhook body is a JSON object
- The endpoint must return a 2xx status code. Any other status is treated as a failure.
- Respond within 60 seconds (10 seconds in sandbox). A request that takes longer is treated as a failure.
- Each webhook contains a `key` field that you can use to deduplicate webhooks. An event has one `key`: it is the same at every URL the event is sent to and on every retry.
- Webhooks will typically arrive within a few seconds of the event. Delivery timing is not guaranteed — if the user is waiting on a result, poll the API every 2-3 seconds rather than relying on webhook timing.
- Webhooks may arrive out of order.
- If you run batches of payments, ensure your endpoint can handle high volumes of simultaneous events.

## Webhook security

- Webhooks do not contain any sensitive information, just object references. Fetch the full object via the API using your credentials.
- Webhooks must target a HTTPS endpoint on port 443.
- All webhooks originate from one of the following IP addresses:
    - 52.51.86.26
    - 54.229.12.118
    - 54.76.31.104
    - 34.252.246.134

## Webhook retry policy

By default, each webhook is sent once and not retried. Any 2xx response is a success; any other status is a failure.

To activate retries, configure a retry policy in the webhook target URL. When retries are configured, each attempt occurs approximately 1 minute after the previous failure.

**Note:** Retries are disabled in the sandbox environment.

## Webhook configuration

Webhook targets are stored as a URL string. The string supports a simple syntax for configuring retries, failover, and multiple destinations. See the `webhook_target` field on the [instance](/platforms/reference/platform/operations/updateinstance/) or the [attach webhook](/platforms/reference/instance-webhooks/operations/attachwebhook/) endpoint.

### Operators

| Operator | Description |
|---|---|
| `\|N` | Make up to N attempts in total (the first plus N-1 retries), approximately 1 minute apart |
| `>` | Failover: if the current URL fails, try the next |
| `,` | Fan-out: deliver to multiple destinations simultaneously |

### Examples

- `https://targetA/url`: send to targetA once, no retries
- `https://targetA/url|2`: send to targetA, and retry once on failure (two attempts in total)
- `https://targetA/url|120`: up to 120 attempts, about a minute apart: roughly 2 hours of retries
- `https://targetA/url>https://targetB/url`: send to targetA; on failure, try targetB
- `https://targetA/url>https://targetB/url>https://targetC/url`: targetA, then targetB, then targetC
- `https://targetA/url|60>https://targetB/url|5`: retry targetA for up to 1 hour, then fail over to targetB for up to 5 minutes
- `https://targetA/url,https://targetB/url`: send to both targetA and targetB
- `https://targetA/url|60,https://targetB/url|60`: send to both, each with up to 1 hour of retries