# Webhooks & Events API

> Outbound event subscriptions — Reply pushes every reply, open, click, bounce, and LinkedIn event to your endpoint instead of making you poll.

- **Category:** Automation
- **Base URL:** `https://api.reply.io/v3`
- **Official reference:** https://docs.reply.io/api-reference/webhooks/list-webhook-subscriptions
- **OpenAPI:** https://headless-jason-ai-sdr-7ajjk.ondigitalocean.app/apis/webhooks-events.openapi.yaml
- **HTML version:** https://headless-jason-ai-sdr-7ajjk.ondigitalocean.app/apis/webhooks-events

## What it does

The Webhooks & Events API is the push side of the platform: it manages subscriptions that make Reply POST a JSON payload to your URL every time an event fires. The management surface is ten operations — list, create, get, update (PUT), and delete subscriptions; enable and disable them without losing configuration; list the supported event types; send a test payload to a subscription's URL; and read its delivery failure log. A subscription binds one `eventType` to one receiver URL, with a `scope` of `personal` (owner's activity) or `team` (any team member), plus optional payload enrichment flags (email URL, email text, contact custom fields).

The event catalog covers the whole outreach loop: email engagement (`email_sent`, `email_opened`, `email_link_clicked`, `email_replied`, `reply_categorized`, `email_bounced`, `email_auto_reply`), email account health (`email_account_connection_lost`, `email_account_error`), LinkedIn (`linkedin_connection_request_sent`, `linkedin_connection_request_accepted`, `linkedin_message_sent`, `linkedin_message_replied`, `linkedin_reply_categorized`, `linkedin_account_alerts`), calls (`contact_called`), contact lifecycle (`contact_finished`, `contact_opted_out`), and sequence automation (`autopilot_stopped`).

Direction matters: the endpoints above are ordinary REST calls you make to Reply, but the deliveries are OUTBOUND — Reply POSTs to your endpoint. You need a publicly reachable https URL to receive them.

## The problem it solves

A polling agent is always late and always wasteful. Checking the inbox every minute burns rate limit on empty responses and still reacts minutes after a prospect replies — which is exactly when interest is highest. Webhooks invert the flow: subscribe once, then react. A reply arrives, `email_replied` fires, the agent classifies the intent, drafts a response, and books the meeting — an event-driven pipeline instead of a polling loop. The same nervous system carries operational signals an agent should act on immediately: a bounce or opt-out prunes the contact list, `email_account_connection_lost` pauses sending before deliverability suffers, `linkedin_account_alerts` flags a channel that needs human attention, and `autopilot_stopped` tells the agent its evergreen sequence went quiet. If you cannot host an endpoint — a static agent with no server — the honest fallback is polling the Conversations & Inbox API; webhooks are strictly better only once you have somewhere for Reply to POST.

## How an agent starts using it

Call `GET /v3/webhooks/events` to get the exact event type names, then `POST /v3/webhooks` with an `eventType` and your receiver `url` (scope `webhooks:write`). Verify the wiring with `POST /v3/webhooks/{id}/test` before relying on it, then handle the POSTs Reply sends to your endpoint. Use `POST /v3/webhooks/{id}/enable` and `/disable` (scope `webhooks:operate`) to pause during maintenance, and `GET /v3/webhooks/{id}/logs` (scope `webhooks:read`) when events stop arriving — it lists failed delivery attempts with event id, HTTP status, and timestamp. One subscription carries one event type, so an agent that needs replies, bounces, and opt-outs creates three subscriptions pointing at the same receiver.

## Typical agent tasks

- Subscribe to email_replied so every prospect reply triggers classify-and-respond within seconds
- Send a test payload to verify the receiver endpoint parses events before going live
- Subscribe to email_bounced and contact_opted_out to keep the contact list clean automatically
- Disable a subscription during receiver maintenance and re-enable it without losing configuration
- Read the delivery failure log to diagnose why events stopped arriving

## Inputs

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `eventType` | string | yes | Event to fire on — one name from GET /v3/webhooks/events (e.g. email_replied). |
| `url` | string | yes | Absolute, publicly reachable https receiver URL (max 1,024 chars) that Reply will POST event payloads to. |
| `scope` | string | no | personal (default) fires only on the owner's activity; team fires for any team member. organization is reserved and currently rejected. |
| `enabled` | boolean | no | Create in a firing state (default true). After creation, toggle only via the enable/disable endpoints — PUT cannot change it. |
| `payloadConfig` | WebhookPayloadConfig | no | Enrichment flags — includeEmailUrl, includeEmailText, includeProspectCustomFields. |

## Outputs

| Name | Type | Description |
|------|------|-------------|
| `id` | integer | Subscription identifier used by every other webhook endpoint. |
| `enabled` | boolean | Whether the subscription currently fires. |
| `events` | string[] | Supported event type names from GET /v3/webhooks/events — the valid eventType values. |
| `logs` | WebhookDeliveryLog[] | Per-subscription failure log — triggering event id, HTTP status (null if the request never completed), and UTC attempt timestamp. Successful deliveries are not logged. |

## Authentication

API key as Bearer token. Send `Authorization: Bearer <API_KEY>` on every request. Required scopes: `webhooks:read`, `webhooks:write`, `webhooks:operate`. Get an API key in the Reply.io app under **Settings → API Key** (https://docs.reply.io/api-reference/authentication).

## Rate limits

100 requests/minute and 3,000 requests/hour per user (shared across all of the user's API clients). On 429, honor the Retry-After header.

## Example

### Request — `POST /v3/webhooks`

```bash
curl -X POST https://api.reply.io/v3/webhooks \
  -H "Authorization: Bearer $REPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "eventType": "email_replied", "url": "https://agent.example.com/hooks/reply", "scope": "personal" }'
```

### Response — `201`

```json
{
  "id": 1823,
  "eventType": "email_replied",
  "url": "https://agent.example.com/hooks/reply",
  "scope": "personal",
  "enabled": true,
  "createdAt": "2026-07-04T09:15:00Z"
}
```

### Error — `403`

```json
{
  "type": "https://docs.reply.io/api-reference/authentication",
  "title": "Forbidden",
  "status": 403,
  "detail": "This API key does not have the required scope: webhooks:write."
}
```

## Related APIs

- [Conversations & Inbox API](https://headless-jason-ai-sdr-7ajjk.ondigitalocean.app/apis/conversations-inbox.md) — The unified inbox as an API — read threads across email and LinkedIn, classify replies with categories, detect meeting intent, and respond.
- [Sequence API](https://headless-jason-ai-sdr-7ajjk.ondigitalocean.app/apis/sequences.md) — Create, populate, and control multichannel outreach sequences — email, LinkedIn, and calls in one campaign object.
- [Contact Data API](https://headless-jason-ai-sdr-7ajjk.ondigitalocean.app/apis/contact-data.md) — The CRM-grade contact and account store — create, import, filter, and organize the people and companies your agent works.
- [Platform Utilities API](https://docs.reply.io/api-reference/background-jobs/get-a-background-job) — Attachments (including LinkedIn voice), and background-job tracking for bulk and import operations.

## FAQ

**Should an agent use webhooks or poll the Inbox API?**

Webhooks are outbound: Reply POSTs each event to a public https URL you host, so you react in seconds without spending rate limit on polling. An agent with no server gets the same signals by polling the Conversations & Inbox API — webhooks just remove the latency and the wasted requests.

**How do I test a subscription before real traffic hits it?**

POST /v3/webhooks/{id}/test (scope webhooks:operate) sends a test payload to the subscription's URL, so you can verify parsing and response handling before enabling it in production.

**How do I debug missing events?**

GET /v3/webhooks/{id}/logs returns the subscription's delivery failure log — each entry has the triggering event id, the HTTP status (null when the request never completed), and the UTC attempt timestamp. It records failures only; successful deliveries are not listed. Also check that the subscription is enabled.
