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

# Webhook endpoints

> Subscribe a URL to events, such as a task being assigned or a review finishing, and receive a signed POST each time one happens.

> [!NOTE]
>
> Webhook endpoints are rolling out. If the routes answer `404`, ask your Wordsmith contact to turn them on for your organisation.

A [callback](https://wordsmithai.mintlify.site/webhooks.md) tells you when work **you started** finishes. A webhook endpoint tells you about everything else you can see: a task assigned to you in the app, a review someone ran in Word, an agent waiting for your approval, documents added to a repository. You register a URL once, choose the event types it receives, and Wordsmith sends it a signed `POST` for each event.

## Callbacks and webhook endpoints

| | Callback | Webhook endpoint |
| - | - | - |
| Set up | `callback_url` on each request | Once, with [Create webhook endpoint](https://wordsmithai.mintlify.site/api-reference/webhooks/create-webhook-endpoint.md) |
| Events | The one operation you started | Every event of the chosen types that you can read |
| Signed with | The API key's webhook secret | The endpoint's own secret |
| Who can use it | API keys | API keys, OAuth apps, and people in **Settings → Configurations → Webhooks** |

Both use the same signature scheme and the same back-off, so one receiver can handle both.

## Create an endpoint

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://api.wordsmith.ai/api/v1/webhook_endpoints \
  -H "Authorization: Bearer sk-ws-api1-your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/wordsmith",
    "event_types": ["task.assigned", "task.status_changed", "review.completed"],
    "description": "Matter management sync"
  }'
```

The response is the endpoint, as [Create webhook endpoint](https://wordsmithai.mintlify.site/api-reference/webhooks/create-webhook-endpoint.md) shows it, plus its `secret`. The secret is returned only in this response. Store it now: you need it to [verify signatures](#verify-the-signature), and it cannot be read again. If you lose it, [rotate it](#rotate-the-secret).

* `url` must be a public `https` URL. Private, loopback and link-local addresses are refused with `400 invalid_webhook_url`.
* `event_types` takes names from [Event types](#event-types). A wildcard such as `task.*` covers every event of that resource, including ones added later.
* Wordsmith sends a `webhook_endpoint.test` event to the new endpoint straight away, so you can check your receiver.

Managing endpoints needs the `webhooks:write` scope, and reading them needs `webhooks:read`. Neither is a default scope: an app asks for them by name. A user can have up to 10 endpoints, and an organisation up to 50.

## What an endpoint receives

An endpoint acts as the user who created it, with the credential that created it. Each event is checked when it is sent, not when it happened. An event reaches the endpoint only if:

1. The event type is one the endpoint subscribes to.
2. The credential still grants `webhooks:read` and the event type's scope. An API key with full access grants every scope.
3. The user can still read the resource. A task you lose access to stops sending events.
4. The user's role still allows the API and webhook endpoints.

If the API key is deleted or the app is disconnected, the endpoint is disabled with `disabled_reason` `credential_revoked`, and sends nothing more. Create a new one with a working credential. An endpoint created in **Settings → Configurations → Webhooks** has no API key or app behind it, so it acts with your own access.

If the user who owns an endpoint is deleted or suspended, Wordsmith stops sending to it from that moment, and events raised after it are never delivered. A deleted owner's endpoint is also disabled with `disabled_reason` `owner_inactive` the next time an event is sent to it. A suspended owner's endpoint stays on and receives new events once their access comes back. When the owner is back, set `enabled` to `true` if the endpoint was disabled, and read what you missed from [List events](#catch-up-after-an-outage).

To receive events for work across a whole team, create the endpoint as a user who can read that work, such as a service account. To receive every event about work shared with the whole organisation, use an [organisation endpoint](#organisation-endpoints).

## Event types

| Event | Sent when | Scope |
| - | - | - |
| `operation.succeeded`, `operation.failed`, `operation.cancelled` | Any operation you started finishes, whether or not it had a `callback_url` | The read scope of the operation's type |
| `task.created` | A task is created, or a draft task is committed | `tasks:read` |
| `task.assigned` | A task gets a new assignee, team or agent | `tasks:read` |
| `task.status_changed` | A task's status changes, including to `completed` | `tasks:read` |
| `task.comment_added` | Someone comments on a task | `tasks:read` |
| `review.completed` | A review finishes, wherever it was started | `reviews:read` |
| `input_request.created` | An agent stops to wait for a person, such as an approval | `sessions:read` |
| `input_request.resolved` | That person answers, or the request is cancelled or expires | `sessions:read` |
| `repository.documents_added` | Documents are added to a repository | `repositories:read` |
| `repository.indexing_completed` | A repository has no documents left to index | `repositories:read` |
| `report.run_completed` | A report run finishes | `reports:read` |
| `webhook_endpoint.test` | The endpoint is created, or you call [Send test event](https://wordsmithai.mintlify.site/api-reference/webhooks/send-test-event.md) | None |

[List event types](https://wordsmithai.mintlify.site/api-reference/events/list-event-types.md) returns this list with each type's scope. New event types are added over time. Only events you subscribe to are sent, so a new type never reaches an endpoint that did not ask for it, unless the endpoint uses a wildcard.

## Payload

Every event uses the same envelope. [Get event](https://wordsmithai.mintlify.site/api-reference/events/get-event.md) shows a full example.

**id** `string`

The event's ID. Every delivery attempt of one event sends the same ID, so drop duplicates by it.

**type** `string`

The event type, from [Event types](#event-types).

**api\_version** `string`

The version of the payload shape. It is the endpoint's `api_version`, fixed when the endpoint was created, so a later change to a payload never breaks your receiver.

**created\_at** `string`

When the event happened. Events can arrive out of order, so compare this before applying an update.

**resource** `object`

The object the event is about, by `type` and `id`.

**actor** `object`

Who caused the event. `kind` is `user`, `agent` or `system`. `id` is `null` for `system`.

**data** `object`

IDs and status for the event. Its shape depends on `type`.

### Events carry IDs, not content

`data` holds IDs, statuses, counts and links. It never holds titles, document text, comments or answers. Read those with the API, using the IDs in the event:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://api.wordsmith.ai/api/v1/tasks/5f0c9a12-8e3b-4d71-a6c4-0b2e9f7d3c58 \
  -H "Authorization: Bearer sk-ws-api1-your_api_key_here"
```

This keeps confidential content inside Wordsmith's access checks. You always read the current state, and an event delayed by retries never overwrites newer data. Operation events are the exception: they carry the whole [operation](https://wordsmithai.mintlify.site/api-reference/operations/get-operation.md), as callbacks do.

### `data` by event type

| Event | `data` fields |
| - | - |
| `operation.*` | The [operation](https://wordsmithai.mintlify.site/api-reference/operations/get-operation.md) |
| `task.created`, `task.assigned` | `task_id`, `status`, `assignee_id`, `team_id`, `agent_id`, `url` |
| `task.status_changed` | `task_id`, `previous_status`, `status`, `url` |
| `task.comment_added` | `task_id`, `comment_id`, `url` |
| `review.completed` | `review_id`, `status`, `type`, `findings` (counts by result and severity), `redline_file_id`, `url` |
| `input_request.created`, `input_request.resolved` | `input_request_id`, `session_id`, `task_id`, `kind`, `status`, `url` |
| `repository.documents_added` | `repository_id`, `document_ids`, `count`, `url` |
| `repository.indexing_completed` | `repository_id`, `indexed`, `failed`, `url` |
| `report.run_completed` | `report_id`, `run_id`, `status`, `url` |
| `webhook_endpoint.test` | `webhook_endpoint_id` |

## Verify the signature

Every event carries the same `Wordsmith-Signature: t=…,v1=…` header as callbacks, signed with the endpoint's secret. Verify it as described in [Validating webhook signatures](https://wordsmithai.mintlify.site/webhooks.md#validating-webhook-signatures). A retry is signed again with a fresh timestamp.

Each request also carries these headers:

| Header | Value |
| - | - |
| `Wordsmith-Event-Id` | The event's `id` |
| `Wordsmith-Event-Type` | The event's `type` |
| `Wordsmith-Webhook-Id` | The endpoint's `id`, to tell endpoints apart on one URL |
| `Wordsmith-Signature-Timestamp` | The `t` value of the signature |

### Rotate the secret

[Rotate webhook secret](https://wordsmithai.mintlify.site/api-reference/webhooks/rotate-webhook-secret.md) returns a new `secret`. For 24 hours, each event is signed with both secrets, so the header carries two `v1` values: `t=…,v1=<new>,v1=<old>`. Accept the request if any `v1` matches. Deploy the new secret within those 24 hours; after that only the new one signs.

## Delivery

* **At least once.** The same event can arrive more than once. Drop duplicates by `id`.
* **No order.** Events are sent as they happen and retried on their own, so a later event can arrive first. Use `created_at`, or read the resource.
* **Respond fast.** Return any `2xx` within 10 seconds, then do the work. Redirects are not followed and count as a failure.
* **Retries.** A non-`2xx` response or a timeout is retried after 1 minute, 5 minutes, 15 minutes, 1 hour, 3 hours, then every 6 hours, for 3 days. Then the delivery is marked failed.
* **Failing endpoints.** If every attempt to an endpoint has failed for 2 days, its `status` becomes `failing` and its owner gets a notification. Each event is retried for 3 days, so one event that never gets through is enough. The endpoint's pending deliveries stop with it. Wordsmith stops sending until you fix the receiver and set `enabled` back to `true`. Events from that time can be read from [List events](#catch-up-after-an-outage).

Each endpoint's `last_delivery` shows the time, response status and error of its latest attempt, in the API and in **Settings → Configurations → Webhooks**. [List webhook deliveries](https://wordsmithai.mintlify.site/api-reference/webhooks/list-webhook-deliveries.md) shows each event's attempts, and [Retry webhook delivery](https://wordsmithai.mintlify.site/api-reference/webhooks/retry-webhook-delivery.md) sends one again with the same event `id`, a fresh signature, and access checked again.

### Catch up after an outage

Events stay readable for 30 days. [List events](https://wordsmithai.mintlify.site/api-reference/events/list-events.md) returns them oldest first, with the same access checks an endpoint uses. Page through with `cursor`:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl "https://api.wordsmith.ai/api/v1/events?types=task.*,review.completed&created_after=2026-11-08T00:00:00Z" \
  -H "Authorization: Bearer sk-ws-api1-your_api_key_here"
```

The API is the source of truth. If your receiver was down for longer than the retries cover, list the events you missed, or read the resources directly. Wordsmith records an event right after the change it reports. In the rare case that recording fails, the change is still made but no event is sent, so an integration that must not miss a change should also reconcile against the resources now and then.

## Organisation endpoints

A user's endpoint sees what that user can see. An **organisation endpoint** receives every event of its types about work shared with the whole organisation, such as every `task.created` on an organisation-wide task, so a matter management system or a data warehouse can mirror shared legal work.

| | User endpoint | Organisation endpoint |
| - | - | - |
| Created by | Any user whose role allows the API and webhook endpoints | An admin who may manage organisation webhooks |
| Receives | Events about resources its user can read | Events about resources shared with the whole organisation |
| Belongs to | Its user and credential | Your organisation. It keeps working when its creator leaves or their key is deleted. |
| Managed by | Its user | Any admin who may manage organisation webhooks |
| Scope | `webhooks:write` | `webhooks:write` and `webhooks:admin` |

Create one with the same request and `"audience": "customer"`.

* **Private work stays private.** A private task, review, repository or report sends nothing to an organisation endpoint, even when it is shared with a few people. Only work shared with the whole organisation reaches it.
* **Personal events are excluded.** Operation and input request events are about one person's work, so an organisation endpoint cannot subscribe to them.
* **Payloads are the same.** Events carry IDs and status, as for a user endpoint. To read the content, the receiving system calls the API with a credential that can read it.
* **Changes are audited.** Creating, changing and deleting an endpoint, rotating its secret, sending a test and retrying a delivery are recorded in the [audit log](https://wordsmithai.mintlify.site/api-reference/audit/list-audit-events.md) as `webhook_endpoint.*` events, for both kinds of endpoint.
* **Your plan must include it.** Where it does not, `"audience": "customer"` is refused with `403 customer_webhooks_unavailable`.

[List events](https://wordsmithai.mintlify.site/api-reference/events/list-events.md) with `audience=customer` lists the same events for catch-up, and needs `webhooks:admin`.

## Not covered

* **Full objects in events.** Events carry IDs; read the content with the API.
* **Ordering.** Events are not delivered in order, and there is no per-resource sequence.


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