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

# Trigger Deliveries

> How trigger events reach your endpoint, and how to recover when they fail

When a [trigger](https://docs.beta.adapter.com/triggers/overview.md) matches an event, Adapter POSTs the event to your webhook URL. Each event becomes one **delivery**, recorded with its outcome so you can see what reached your endpoint and what didn't.

## What your endpoint receives

Every delivery is a JSON `POST` with these headers:

| Header | Value |
| - | - |
| `Content-Type` | `application/json` |
| `Adapter-Timestamp` | Unix seconds when the request was signed |
| `Adapter-Signature` | `v1=<hex>`: HMAC-SHA256 of `<Adapter-Timestamp>.<raw body>` using your trigger's `secret` |
| `User-Agent` | `adapter-triggers/1.0` |

Authenticate deliveries by verifying `Adapter-Signature` with the `secret` returned when you created the trigger. Requests carry no bearer token or API key, so an endpoint that expects one will reject every delivery with `401`.

```python theme={null}
import hashlib, hmac

def verify(secret: str, timestamp: str, raw_body: bytes, signature: str) -> bool:
    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"v1={expected}", signature)
```

Delivery is at-least-once. The same event can arrive more than once with the same `id`, so dedupe on it.

## Success, retries and failure

Respond with any `2xx` status within 6 seconds to mark the delivery `delivered`.

| Your endpoint returns | What happens |
| - | - |
| `2xx` | `delivered` |
| `4xx` | `failed` right away, no retry |
| `5xx`, timeout, connection error | Retried once after a short backoff, then `failed` if the retry also fails |
| Nothing (URL invalid or host resolves to a private address) | `failed` with `attempts: 0` |

Return `4xx` only when retrying wouldn't help. For a temporary problem on your side, return `5xx` so the delivery gets its retry.

## Checking delivery health

Each trigger carries a rollup of its recent deliveries:

| Field | Meaning |
| - | - |
| `last_fired_at` | When the trigger last attempted a delivery |
| `last_status` | `delivered` or `failed` |
| `consecutive_failures` | Events in a row that failed to deliver. Resets to 0 on any success |
| `auto_disabled_at` | Set when Adapter turned the trigger off for repeated failures |

[Get trigger details](https://docs.beta.adapter.com/api-reference/Triggers/get-trigger.md):

```bash theme={null}
curl "https://api.adapter.com/v1/triggers/$TRIGGER_ID" \
  -H "Authorization: Bearer $PK_LIVE_KEY"
```

For individual deliveries, [list deliveries](https://docs.beta.adapter.com/api-reference/Triggers/list-trigger-deliveries.md). Each record has the `status`, the `status_code` your endpoint returned, `attempts`, `duration_ms`, and an `error` message for failures. History is kept for 30 days.

```bash theme={null}
curl "https://api.adapter.com/v1/triggers/$TRIGGER_ID/deliveries?limit=20" \
  -H "Authorization: Bearer $PK_LIVE_KEY"
```

[Delivery counts](https://docs.beta.adapter.com/api-reference/Triggers/get-trigger-delivery-summary.md) gives daily `delivered` and `failed` totals across all your triggers for the last 7 days.

The **Triggers** page in the [Console](https://mind.adapter.com) shows the same status and history.

## Automatic disabling

After **50 consecutive events** fail to deliver, Adapter disables the trigger: `enabled` becomes `false` and `auto_disabled_at` is set. A disabled trigger matches nothing, so events that happen while it is off are not delivered and are not queued for later.

## Recovering a failing trigger

**1. Find the cause**

List the trigger's deliveries and read `status_code` and `error` on the failed ones.

| `status_code` | Usual cause |
| - | - |
| `401` / `403` | Your endpoint expects auth Adapter doesn't send, or it checks the signature with a different secret |
| `404` / `410` | The webhook URL moved or was removed |
| `400` / `422` | Your endpoint rejects the event body |
| `5xx` or none | Your endpoint is down, slow (over 6s), or unreachable |

**2. Fix your endpoint**

Make it accept a signed `POST` and return `2xx`. If the URL changed, update the trigger's `delivery.url`.

**3. Re-enable the trigger**

[Update the trigger](https://docs.beta.adapter.com/api-reference/Triggers/update-trigger.md) with `enabled: true`:

```bash theme={null}
curl -X PATCH "https://api.adapter.com/v1/triggers/$TRIGGER_ID" \
  -H "Authorization: Bearer $PK_LIVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'
```

This resets `consecutive_failures` to 0 and clears `auto_disabled_at`. Deliveries resume from the next matching event.

**4. Backfill what you missed**

Events that failed or happened while the trigger was off are not redelivered. Use the delivery history to find the window (from the first failure to the moment you re-enabled), then fetch that data through the API. A failed delivery's `kind`, `action` and `key` identify the record it was about.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.