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

# Get Webhook

> Read one webhook subscription — check whether it is ACTIVE or has been auto-disabled, and why.

Reads one webhook subscription. The most common use is health-checking: if your endpoint has stopped receiving events, read the subscription and check `status` — a `DISABLED` webhook receives no deliveries, and `disabledReason` explains why (typically repeated delivery failures; see the [delivery lifecycle](/docs/developers/api-reference/webhooks/create)).

The signing `secret` is **never** returned — it is shown only once at [creation](/docs/developers/api-reference/webhooks/create). If it is lost, [delete](/docs/developers/api-reference/webhooks/delete) the subscription and create a new one. Webhooks belonging to another account return `404`.

**Requirements:** `webhooks:manage` scope + the `public_api_webhooks` feature.

## Request

<ParamField path="webhookId" type="string" required>
  The webhook subscription ID.
</ParamField>

## Response

<ResponseField name="webhook" type="object">
  <Expandable title="webhook" defaultOpen>
    <ResponseField name="id" type="string">
      Webhook subscription ID.
    </ResponseField>

    <ResponseField name="url" type="string">
      The destination URL receiving deliveries.
    </ResponseField>

    <ResponseField name="eventTypes" type="string[]">
      Subscribed event types from the [event catalog](/docs/developers/api-reference/updates/poll).
    </ResponseField>

    <ResponseField name="status" type="string">
      `ACTIVE` or `DISABLED`.
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      ISO creation timestamp.
    </ResponseField>

    <ResponseField name="disabledAt" type="string | null">
      When the subscription was disabled; `null` while `ACTIVE`.
    </ResponseField>

    <ResponseField name="disabledReason" type="string | null">
      Why it was disabled. Recover by [deleting](/docs/developers/api-reference/webhooks/delete) and re-creating the subscription, then catch up on missed events with [`GET /updates`](/docs/developers/api-reference/updates/poll).
    </ResponseField>
  </Expandable>
</ResponseField>

## Errors

| Status | `code`         | Meaning                                                                                          |
| ------ | -------------- | ------------------------------------------------------------------------------------------------ |
| `401`  | `UNAUTHORIZED` | Missing or invalid token                                                                         |
| `403`  | `FORBIDDEN`    | Missing `webhooks:manage` scope, or `public_api_webhooks` disabled                               |
| `404`  | `NOT_FOUND`    | No such webhook, or it belongs to another account (`details: {resource: "webhooks", webhookId}`) |

<RequestExample>
  ```bash curl theme={null}
  curl -sS https://app.opentrain.ai/api/public/v1/webhooks/<WEBHOOK_ID> \
    -H "Authorization: Bearer $OT_API_TOKEN"
  ```

  ```bash CLI theme={null}
  opentrain webhooks get <WEBHOOK_ID> --json
  ```

  ```json MCP: opentrain_get_webhook theme={null}
  {
    "webhookId": "<WEBHOOK_ID>"
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 200 (active) theme={null}
  {
    "webhook": {
      "id": "<WEBHOOK_ID>",
      "url": "https://example.com/hooks/opentrain",
      "eventTypes": ["proposal.received", "message.received", "approval.confirmed"],
      "status": "ACTIVE",
      "createdAt": "2026-06-12T10:00:00.000Z",
      "disabledAt": null,
      "disabledReason": null
    }
  }
  ```

  ```json 200 (auto-disabled) theme={null}
  {
    "webhook": {
      "id": "<WEBHOOK_ID>",
      "url": "https://example.com/hooks/opentrain",
      "eventTypes": ["proposal.received"],
      "status": "DISABLED",
      "createdAt": "2026-05-30T08:00:00.000Z",
      "disabledAt": "2026-06-10T14:20:00.000Z",
      "disabledReason": "Disabled after repeated delivery failures"
    }
  }
  ```
</ResponseExample>
