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

# Webhook

> A `Webhook` represents an outbound HTTP subscription registered by a workspace

A `Webhook` represents an outbound HTTP subscription registered by a workspace. When a watched event fires (e.g. `document.processed`, `document.uploaded`), the platform enqueues a Cloud Tasks HTTP POST to `target_url` carrying the event payload and any caller-supplied custom `headers`. One workspace may register multiple webhooks; parent-workspace webhooks also fire for child workspaces. Webhooks are soft-deleted and workspace-scoped.

| Naming                          | Value                             |
| ------------------------------- | --------------------------------- |
| Object                          | Webhook                           |
| Resource type (JSON:API `type`) | `webhook`                         |
| Collection / records root       | — <sub>(not a records root)</sub> |
| REST base                       | `/v1/subscriptions/webhooks`      |
| Entity class                    | `Webhook`                         |

<Note>
  **Internal object.** Not currently exposed on the public REST API. The operations below describe the intended contract.
</Note>

## API operations

| Operation | Method & path                            | Status     |
| --------- | ---------------------------------------- | ---------- |
| List      | `GET /v1/subscriptions/webhooks`         | 🟡 Planned |
| Retrieve  | `GET /v1/subscriptions/webhooks/{id}`    | 🟡 Planned |
| Create    | `POST /v1/subscriptions/webhooks`        | 🟡 Planned |
| Update    | `PATCH /v1/subscriptions/webhooks/{id}`  | 🟡 Planned |
| Delete    | `DELETE /v1/subscriptions/webhooks/{id}` | 🟡 Planned |

## Data model

### Attributes

| Field       | Type                    | Required | Constraints                                                    | Allowed values                          | Description                                                                                                                               |
| ----------- | ----------------------- | -------- | -------------------------------------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| webhook\_id | string (UUID) 🔒 system | ✅ Yes    | UNIQUE; default gen\_random\_uuid()                            | —                                       | Public stable identifier for the webhook. Generated at creation; never changes.                                                           |
| target\_url | string                  | ✅ Yes    | varchar(255); must be a valid URL (Zod .url() at API boundary) | —                                       | The HTTPS endpoint to which the platform delivers event payloads via Cloud Tasks HTTP POST.                                               |
| event       | string (enum)           | ✅ Yes    | varchar(255); allowed values enforced by Zod schema            | document.processed \| document.uploaded | The workspace event type that triggers delivery. Only one event type per webhook registration.                                            |
| headers     | object (JSONB) \| null  | ⚪ No     | jsonb; nullable; key-value map of strings                      | —                                       | Optional custom HTTP headers merged into the delivery request (e.g. Authorization, X-Source). Sent as-is by the platform.                 |
| active      | boolean 🔒 system       | ✅ Yes    | default true                                                   | —                                       | Whether the webhook is currently enabled. Defaults to true on creation. Not exposed in the update schema — cannot be toggled via the API. |
| created\_at | datetime 🔒 system      | ✅ Yes    | timestamptz; set by onCreate hook                              | —                                       | ISO 8601 timestamp of when the webhook was created.                                                                                       |
| updated\_at | datetime 🔒 system      | ⚪ No     | timestamptz; nullable; set by onCreate and onUpdate hooks      | —                                       | ISO 8601 timestamp of the last update. Null until first modification.                                                                     |
| deleted\_at | datetime 🔒 system      | ⚪ No     | timestamptz; nullable                                          | —                                       | Soft-delete timestamp. When set, the webhook is excluded from all queries and no longer delivers events. Set by the DELETE endpoint.      |

### Relationships

| Name      | Type               | Required | Description                                                                                                                                                                |
| --------- | ------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| workspace | to-one (ManyToOne) | ✅ Yes    | The workspace that owns this webhook. All queries filter by workspace\_pk. Parent-workspace webhooks also fire for child workspaces during delivery. References Workspace. |

### System-computed

* webhook\_id — gen\_random\_uuid() at insertion; also written by WebhookService.createWebhook via crypto.randomUUID() (redundant but consistent)
* created\_at — set by onCreate hook (new Date())
* updated\_at — set by onCreate and onUpdate hooks; null until first update
* deleted\_at — set to new Date() by WebhookService.deleteWebhook on soft-delete; not a MikroORM hook, explicit assignment
* active — defaults to true at ORM level; no toggle exposed via API
* Deduplication guard — WebhookService.createWebhook checks for an existing non-deleted webhook with the same (target\_url, event, workspace) triple before inserting; raises WEBHOOK\_ALREADY\_EXISTS on collision
* Delivery via Cloud Tasks — sendWebhookRequest dispatches through CloudTasksService.createHttpPostTask with taskId webhook-trigger-{webhook_id}-{timestamp}-{random}; the actual HTTP call is async and not reflected back on the entity
* idx\_webhooks\_workspace\_deleted — composite partial index on (workspace\_pk, deleted\_at) added by Migration20260416000000 for hot-path list queries

## Example

```json theme={null}
{
  "data": {
    "type": "webhook",
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "attributes": {
      "event": "document.processed",
      "target_url": "https://api.example.com/well-events",
      "headers": {
        "Authorization": "Bearer secret-token",
        "X-Source": "well"
      },
      "active": true,
      "created_at": "2026-03-15T10:30:00.000Z",
      "updated_at": "2026-04-01T08:00:00.000Z"
    }
  }
}
```

<sub>Source: `apps/api/src/database/entities/Webhook.ts` · domain: platform · tier: Platform</sub>
