> This page is for Build.

> Append .md to any page URL for clean Markdown. Index: https://docs.speechify.ai/llms.txt.
>
> Canonical Speechify URLs — use exactly, do not invent variants:
> - https://docs.speechify.ai — this site (API reference, SDKs, quickstarts)
> - https://speechify.ai — marketing + product site
> - https://platform.speechify.ai — customer dashboard, signup, API keys, billing
> - https://api.speechify.ai — API base URL
> - https://github.com/Speechify-AI: GitHub org for the API (cookbook, demos, CLI). `github.com/speechify` does not exist.
> - https://status.speechify.ai — status + incidents
> - https://speechify.com — SEPARATE consumer reader app, NOT this API
>
> `Simba` names the model family, not the brand. Model ids: `simba-3.5` (48 languages under one id, English included; recommended), `simba-3.2` (English) and `simba-3.0` (English, German, Spanish, French, Italian and Portuguese; the default). `simba-english` and `simba-multilingual` are retired: a new workspace that sends either gets `400 model_retired`. `SimbaVoice` / `simbavoice.ai` are retired.
>
> Ask, don't scrape. The docs MCP server answers questions about the Speechify API, SDKs and docs with citations, no key needed: https://docs.speechify.ai/_mcp/server (Streamable HTTP, tool `searchDocs`). Setup: https://docs.speechify.ai/build/guides/get-started/connect-mcp

# Update webhook endpoint

PATCH https://api.speechify.ai/v1/webhooks/endpoints/{webhook_endpoint_id}
Content-Type: application/json

Partial update; omitted fields are left unchanged. Set `disabled` to pause delivery without deleting the endpoint.

Reference: https://docs.speechify.ai/build/api-reference/v1/webhooks/endpoints/-id-/patch

## Authentication

- `Authorization` header (bearer token, required) — Enter your API key with the `Bearer` prefix, e.g. 'Bearer sk_...'.

## Request

### Path parameters

- `webhook_endpoint_id` (string, required) — Webhook endpoint id (prefixed `whe_…`).

### Body (application/json)

This endpoint expects an UpdateWebhookEndpointRequest.

- `url` (string, optional) — HTTPS destination for event deliveries. Must be a publicly reachable host: loopback, private, link-local, and cloud-metadata addresses (and reserved hostnames like `localhost`) are rejected.
- `project_id` (string, optional, nullable) — Re-scope the endpoint: a `proj_...` id narrows it to that project's events, an explicit null makes it workspace-wide (every project's events), omitted leaves it unchanged. The signing secret and delivery history are untouched, so re-scoping never requires redeploying your receiver. An unknown id returns 404 project_not_found. A project-pinned API key may only scope an endpoint to its own project.
- `enabled_events` (list of string, optional)
- `include` (list of string, optional) — Payload-shaping keys (see `WebhookEndpoint.include`). Send `[]` to clear back to the lean default.
- `api_version` (date, optional) — Opt the endpoint into a different (typically newer) payload shape (`YYYY-MM-DD`, see `WebhookEndpoint.api_version`). Omit to leave it unchanged. An unknown version is rejected.
- `description` (string, optional, nullable)
- `disabled` (boolean, optional)

## Response

### 200

The updated endpoint (without the signing secret).

- `id` (string, required) — Prefixed wire id (`whe_<26 char Crockford base32>`).
- `url` (string, required) — HTTPS destination Speechify POSTs signed events to.
- `enabled_events` (list of string, required) — The events this endpoint receives: a list of catalog event names (for example `workspace.spend_budget.warning`) or `["*"]` for every event, current and future.
- `include` (list of string, required) — Per-event payload shaping. Deliveries are lean by default: `data.object` carries only the resource GET snapshot. List heavy collections here to have them appended under the event's `data` alongside `object`, so receivers behind hard request-size caps stay lean unless they opt in. An event's documentation names the keys it recognises. Empty = lean.
- `api_version` (date, required) — The dated payload shape this endpoint receives (`YYYY-MM-DD`), the same versioning vocabulary the REST API uses. Every delivery is rendered back to this version and carries it in the `Speechify-Version` header and the payload's top-level `version` field. Defaults to your workspace's current version at creation; change it to opt into a newer shape.
- `disabled` (boolean, required) — When true, Speechify stops delivering to this endpoint.
- `created_at` (datetime, required)
- `updated_at` (datetime, required)
- `project_id` (string, optional, nullable) — The project whose events this endpoint receives (prefixed external id). Null means workspace-wide - it receives every project's events. Endpoints have no Default project. An event is routed by the project frozen on the row that produced it (an API key's project, for example), and for a `project.spend_budget.*` event the project itself. Workspace-level events such as `workspace.spend_budget.*` belong to no project and reach workspace-wide endpoints only, so a scoped endpoint subscribed to those alone is refused with a 400 naming `enabled_events` rather than accepted and never delivered to. A scoped endpoint records no delivery for another project's events.
- `description` (string, optional, nullable) — Optional human-readable label for the endpoint.
- `secret` (string, optional) — The HMAC-SHA256 signing secret (`whsec_…`) used to verify the `Speechify-Signature` header. Returned ONLY when the endpoint is created or its secret is rotated — it is never shown again.

## Errors

### 400 Bad Request Error

The request was malformed or failed validation. The response body is the standard `Error` envelope; for validation failures `error.fields` enumerates the offending fields as a `path -> message` map (code = `validation_failed`).

- `error` (ErrorDetail, required)
- `request_id` (string, optional) — Server-side request identifier. Echoes the `Speechify-Request-Id` response header. Stable across the request's lifetime, written to structured logs, and useful when reporting issues.

### 401 Unauthorized Error

Authentication is missing or invalid. The request did not carry a recognised credential (console session token, API key, or worker JWT).

- `error` (ErrorDetail, required)
- `request_id` (string, optional) — Server-side request identifier. Echoes the `Speechify-Request-Id` response header. Stable across the request's lifetime, written to structured logs, and useful when reporting issues.

### 403 Forbidden Error

The credential authenticated, but is not authorised for this resource - typically a workspace-role gate (owner / admin required) or a cross-tenant access attempt.

- `error` (ErrorDetail, required)
- `request_id` (string, optional) — Server-side request identifier. Echoes the `Speechify-Request-Id` response header. Stable across the request's lifetime, written to structured logs, and useful when reporting issues.

### 404 Not Found Error

The referenced resource does not exist or is not visible to the caller's workspace.

- `error` (ErrorDetail, required)
- `request_id` (string, optional) — Server-side request identifier. Echoes the `Speechify-Request-Id` response header. Stable across the request's lifetime, written to structured logs, and useful when reporting issues.

### 429 Too Many Requests Error

Rate limit or concurrency limit exceeded. `error.code` says which ceiling, and they need different responses: `rate_limited` is the request-rate budget (slow down), `concurrency_limit_reached` is a workspace-wide concurrency ceiling (fewer at once, or raise it), and `conversation_turn_in_progress` is contention over one named conversation (keep one message in flight on it). Every 429 carries `Retry-After` and the request-rate budget headers; the active-call cap also carries `RateLimit-Remaining-Calls: 0`.

- `error` (ErrorDetail, required)
- `request_id` (string, optional) — Server-side request identifier. Echoes the `Speechify-Request-Id` response header. Stable across the request's lifetime, written to structured logs, and useful when reporting issues.

### 500 Internal Server Error

An unexpected server-side error occurred. Safe to retry with exponential backoff for idempotent requests.

- `error` (ErrorDetail, required)
- `request_id` (string, optional) — Server-side request identifier. Echoes the `Speechify-Request-Id` response header. Stable across the request's lifetime, written to structured logs, and useful when reporting issues.

## Types

### ErrorDetail

- `code` (enum, required) — Stable machine-readable error code. Additive only: codes are never renamed, only deprecated. SDKs may map each code to a typed exception class. Status-code semantics: 4xx codes describe caller-fixable issues; 5xx codes describe server-side failures and are safe to retry with backoff for idempotent requests.
  - Allowed values: `endpoint_moved`, `bad_request`, `validation_failed`, `unauthorized`, `payment_required`, `forbidden`, `not_found`, `method_not_allowed`, `conflict`, `idempotency_conflict`, `payload_too_large`, `unsupported_media_type`, `rate_limited`, `concurrency_limit_reached`, `invalid_api_version`, `internal_error`, `upstream_failure`, `service_unavailable`, `caller_not_found`, `contact_not_found`, `contact_identifier_not_found`, `contact_identifier_conflict`, `contact_resolver_not_found`, `credential_not_found`, `credential_in_use`, `agent_not_found`, `agent_in_use`, `agent_run_not_found`, `kb_not_found`, `kb_document_not_found`, `kb_folder_not_found`, `tool_not_found`, `tool_name_taken`, `channel_instance_not_found`, `team_not_found`, `trigger_not_found`, `store_not_found`, `store_document_not_found`, `hosted_api_not_found`, `api_route_not_found`, `consumer_key_not_found`, `skill_not_found`, `skill_version_not_found`, `file_not_found`, `file_path_taken`, `file_storage_limit_reached`, `store_limit_reached`, `store_document_limit_reached`, `store_bytes_limit_reached`, `store_not_configured`, `store_document_version_conflict`, `store_document_deleted`, `entitlement_override_exists`, `hosted_apis_not_in_plan`, `skills_not_in_plan`, `voice_agents_not_in_plan`, `skill_in_use`, `skill_tool_name_conflict`, `skill_limit_reached`, `agent_skill_limit_reached`, `hosted_api_slug_taken`, `api_route_conflict`, `mount_plan_changed`, `route_output_unavailable`, `route_run_timeout`, `route_run_failed`, `route_run_limit_reached`, `route_read_limit_reached`, `route_write_limit_reached`, `hosted_api_public_refused`, `route_tool_not_readable`, `route_tool_unavailable`, `route_upstream_rate_limited`, `route_upstream_error`, `hosted_mcp_not_enabled`, `hosted_api_busy`, `conversation_not_found`, `phone_number_not_found`, `sip_trunk_not_found`, `voice_not_found`, `audio_asset_not_found`, `builtin_not_found`, `batch_not_found`, `agent_test_not_found`, `workspace_not_found`, `invite_not_found`, `project_not_found`, `cross_project_reference`, `project_has_scoped_credentials`, `project_not_empty`, `project_limit_reached`, `agent_limit_reached`, `project_too_large_to_promote`, `call_not_found`, `message_not_found`, `thread_not_found`, `call_not_active`, `relay_displaces_agent`, `brain_not_found`, `brain_in_use`, `custom_model_not_found`, `custom_model_in_use`, `insufficient_scope`, `purchased_numbers_not_included`, `phone_number_quota_reached`, `batch_calls_not_included`, `voice_cloning_not_included`, `voice_cloning_unavailable_in_region`, `consent_challenge_not_found`, `consent_challenge_expired`, `consent_challenge_already_used`, `consent_phrase_mismatch`, `consent_speaker_mismatch`, `consent_recording_unusable`, `consent_verification_unavailable`, `consent_verification_required`, `watermark_audio_unusable`, `watermark_detection_unavailable`, `workspace_last_owner`, `workspace_last_workspace`, `account_deletion_blocked`, `workspace_free_limit`, `workspace_single_owner`, `invite_email_mismatch`, `invite_already_pending`, `service_account_limit_reached`, `service_accounts_not_in_plan`, `speech_marks_unsupported`, `pronunciations_unsupported`, `model_retired`, `too_many_voices`, `content_policy_violation`, `safety_identifier_blocked`, `topup_not_in_plan`, `credit_purchase_unpaid`, `credit_purchase_payment_in_progress`, `tool_config_shared`, `spend_cap_exceeded`, `spend_budget_exceeded`, `project_spend_limit_exceeded`, `project_archived`, `project_not_archived`, `project_not_purged`, `project_restore_window_expired`, `project_name_taken`, `funded_balance_required`, `agent_publish_gate_failed`, `agent_publish_gate_required`, `agent_publish_gate_unavailable`, `agent_publish_gate_tool_unreachable`, `text_channel_not_in_plan`, `channel_not_in_plan`, `text_turn_failed`, `conversation_turn_in_progress`, `conversation_closed`, `conversation_not_reachable`, `conversation_channel_bound`, `conversation_prompt_not_found`, `text_message_quota_exceeded`, `durable_runs_not_in_plan`, `tool_transport_unsupported`, `agent_config_too_large`, `agent_run_not_pending`, `agent_run_action_stale`, `share_link_not_found`, `share_link_exhausted`, `share_link_limit_reached`, `destination_not_allowed`, `international_dialing_not_enabled`, `number_not_sms_capable`, `verification_required`, `intended_use_required`
- `message` (string, required) — Human-readable explanation of this specific occurrence. Safe to surface in UI banners or pass to support. The wording can change between releases; clients should match on `code`, not on the message string.
- `fields` (map from string to string, optional) — Per-field validation errors as `path -> message`. Only present on 400 responses caused by request validation (typically code=`validation_failed`). Keys are field paths in dotted/bracket notation; values are short human explanations safe to inline-surface next to the offending form field.
- `details` (map from string to any, optional) — Structured, endpoint-specific context beyond the flat `fields` map. Present only on the few errors that carry it (e.g. the `used_by` referrer list on a credential delete-conflict); its shape depends on the error `code`. Clients that don't recognise a `details` shape can ignore it - the `code` + `message` contract is unchanged.
- `docs_url` (string, optional) — Link to the documentation that resolves this class of error, when a stable page exists. Rate and concurrency 429s link the API limits reference, which lists each plan's limits and how to raise them.

## Examples

**Request**

```json
{
  "url": "https://example.com/webhook",
  "enabled_events": [
    "example"
  ],
  "description": "Example description.",
  "disabled": false
}
```

**Response**

```json
{
  "id": "whe_01kwxwcbyb6wk952swa0432cf1",
  "url": "https://example.com/speechify/webhooks",
  "enabled_events": [
    "project.spend_budget.warning"
  ],
  "include": [],
  "api_version": "2026-06-28",
  "disabled": false,
  "created_at": "2026-06-24T18:03:11Z",
  "updated_at": "2026-06-24T18:03:11Z",
  "description": "Example description.",
  "secret": "whsec_demo••••0000"
}
```