---
title: "Add a webhook endpoint"
description: "Trillet OEM API: Registers a URL to receive signed events from all of your tenants."
openapi: /public/openapi/trillet-oem.yaml POST /partner/v1/webhook-endpoints
lastUpdated: "2026-10-28"
---

> **For AI agents:** the complete documentation index is at [llms.txt](https://docs.trillet.ai/llms.txt). Append `.md` to any page URL for its markdown version.

`POST https://api.trillet.ai/partner/v1/webhook-endpoints`

Registers a URL to receive signed events from all of your tenants. The signing `secret` is
returned only here and on rotation. Up to 10 endpoints per account. Needs `webhooks:write`
and a key that is not restricted to some tenants.

## Authentication

- `partnerKey` — http bearer (tpk_live_...)

## Request body

- Content type: `application/json`
  - request body
    - (allOf)
      - value (object)
        - `url` (string) — A public `https` URL on port 443, with no credentials or fragment.
        - `description` (string)
        - `enabledEvents` (array, default: ["*"])
          - `items` (string, one of: *, call.started, call.ended, call.analyzed, call.no_answer, call.failed, call.blocked, call.transferred, call.transfer_failed, tool.failed, booking.created, booking.cancelled, booking.rescheduled, recording.available, sms.received, sms.sent, sms.failed, workflow_run.completed, workflow_run.failed, number.provisioned, number.released, number.renewal_failed, tenant.created, tenant.updated, tenant.suspended, tenant.resumed, tenant.deleted, tenant.restored, usage.threshold_reached, endpoint.test) — An event type, or `*` for all.
        - `includeConversationData` (boolean | null) — Include summary, extracted data, variables, booking and transcript in call payloads. `null` uses your account setting.
        - `redactPII` (boolean, default: false) — Mask emails, phone numbers and card-like numbers in conversation data.
      - value (object)

## Response 201

The endpoint, with its signing secret.
  - response
    - (allOf)
      - value (object)
        - `object` (string, required)
        - `id` (string, required)
        - `url` (string, required)
        - `description` (string | null)
        - `enabledEvents` (array, required)
          - `items` (string, one of: *, call.started, call.ended, call.analyzed, call.no_answer, call.failed, call.blocked, call.transferred, call.transfer_failed, tool.failed, booking.created, booking.cancelled, booking.rescheduled, recording.available, sms.received, sms.sent, sms.failed, workflow_run.completed, workflow_run.failed, number.provisioned, number.released, number.renewal_failed, tenant.created, tenant.updated, tenant.suspended, tenant.resumed, tenant.deleted, tenant.restored, usage.threshold_reached, endpoint.test) — An event type, or `*` for all.
        - `status` (string, required, one of: enabled, disabled)
        - `disabledReason` (string | null)
        - `failingSince` (string | null, date-time)
        - `includeConversationData` (boolean | null)
        - `redactPII` (boolean)
        - `createdAt` (string | null, date-time)
      - value (object)
        - `secret` (string, required) — The signing secret (`whsec_...`). Returned only on create and rotation.

## Response 400

`invalid_request`, `invalid_url` or `invalid_events`.
  - response (object)
    - `error` (object, required)
      - `type` (string, required, one of: invalid_request_error, authentication_error, permission_error, conflict_error, rate_limit_error, api_error, idempotency_error)
      - `code` (string, required) — A stable code. Handle errors by `code`, not by `message`.
      - `message` (string, required)
      - `param` (string) — The request field the error is about, when there is one.
      - `requestId` (string | null) — Include it when you contact support. Not present on idempotency errors.

## Response 401

The partner key is missing, malformed, unknown or revoked (`partner_key_required`, `invalid_api_key`, `partner_not_enabled`).
  - response (object)
    - `error` (object, required)
      - `type` (string, required, one of: invalid_request_error, authentication_error, permission_error, conflict_error, rate_limit_error, api_error, idempotency_error)
      - `code` (string, required) — A stable code. Handle errors by `code`, not by `message`.
      - `message` (string, required)
      - `param` (string) — The request field the error is about, when there is one.
      - `requestId` (string | null) — Include it when you contact support. Not present on idempotency errors.

## Response 403

`missing_scope`, or `key_restricted` on webhook endpoint routes.
  - response (object)
    - `error` (object, required)
      - `type` (string, required, one of: invalid_request_error, authentication_error, permission_error, conflict_error, rate_limit_error, api_error, idempotency_error)
      - `code` (string, required) — A stable code. Handle errors by `code`, not by `message`.
      - `message` (string, required)
      - `param` (string) — The request field the error is about, when there is one.
      - `requestId` (string | null) — Include it when you contact support. Not present on idempotency errors.

## Response 409

`too_many_endpoints`.
  - response (object)
    - `error` (object, required)
      - `type` (string, required, one of: invalid_request_error, authentication_error, permission_error, conflict_error, rate_limit_error, api_error, idempotency_error)
      - `code` (string, required) — A stable code. Handle errors by `code`, not by `message`.
      - `message` (string, required)
      - `param` (string) — The request field the error is about, when there is one.
      - `requestId` (string | null) — Include it when you contact support. Not present on idempotency errors.


---

📦 **OpenAPI specs:** Every OpenAPI specification referenced by this documentation is available as a single download — https://docs.trillet.ai/api-specs.zip
