> ## 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.

# Create Webhook Endpoint

> Register an HTTPS endpoint for platform lifecycle events. The HMAC signing secret is returned once, only in this response.

Registers a [webhook endpoint](/docs/developers/annotation-platforms/webhooks) to receive [lifecycle events](/docs/developers/annotation-platforms/lifecycle-events). The response includes the HMAC signing `secret` **once** — store it immediately; no later call returns it. If you lose it, delete the endpoint and create a new one.

Delivery starts with events created **after** the endpoint is registered — there is no backfill of earlier events. Link projects and subscribe before contracts you care about begin.

**Requirements:** `webhooks:manage` scope.

## Request

<ParamField body="url" type="string" required>
  Delivery URL. Must be HTTPS (`http` is allowed for localhost only). Redirects are not followed.
</ParamField>

<ParamField body="eventTypes" type="string[]" required>
  At least one of: `contract.started`, `contract.ended`, `project_link.created`, `project_link.removed`, `install.revoked`, `milestone.funded`, `milestone.budget_low`, `milestone.budget_depleted`.
</ParamField>

## Response

<ResponseField name="webhookEndpoint" type="object">
  The created endpoint: `{id, url, eventTypes, status, createdAt, consecutiveFailures, disabledAt, disabledReason}` — same shape as [`GET /webhook-endpoints/{endpointId}`](/docs/developers/annotation-platforms/api-reference/webhook-endpoints/get).
</ResponseField>

<ResponseField name="secret" type="string">
  HMAC-SHA256 signing secret for [verifying deliveries](/docs/developers/guides/verify-webhook-signatures). **Shown only in this response.**
</ResponseField>

<ResponseField name="message" type="string">
  Reminder that the secret will not be shown again.
</ResponseField>

## Errors

| Status | `code`         | Meaning                                                                                      |
| ------ | -------------- | -------------------------------------------------------------------------------------------- |
| `400`  | `BAD_REQUEST`  | Body not valid JSON, `url` missing/not HTTPS, or `eventTypes` empty/contains an unknown type |
| `401`  | `UNAUTHORIZED` | Missing, invalid, or revoked token                                                           |
| `403`  | `FORBIDDEN`    | Token lacks `webhooks:manage`                                                                |
| `409`  | `CONFLICT`     | Endpoint limit reached for this install                                                      |

<RequestExample>
  ```bash curl theme={null}
  curl -sS -X POST https://app.opentrain.ai/api/partner/v1/webhook-endpoints \
    -H "Authorization: Bearer $OT_PARTNER_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://your-platform.example.com/webhooks/opentrain",
      "eventTypes": ["contract.started", "contract.ended", "install.revoked"]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "webhookEndpoint": {
      "id": "<ENDPOINT_ID>",
      "url": "https://your-platform.example.com/webhooks/opentrain",
      "eventTypes": ["contract.started", "contract.ended", "install.revoked"],
      "status": "ACTIVE",
      "createdAt": "2026-06-12T10:00:00.000Z",
      "consecutiveFailures": 0,
      "disabledAt": null,
      "disabledReason": null
    },
    "secret": "whsec_<SECRET>",
    "message": "Store the secret now — it is only returned once. Use it to verify the X-OpenTrain-Signature header on deliveries."
  }
  ```
</ResponseExample>
