> 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

# List webhook endpoint deliveries

GET https://api.speechify.ai/v1/webhooks/endpoints/{webhook_endpoint_id}/deliveries

Delivery attempts for one webhook endpoint, newest first. One row per
(endpoint, event, resource), updated in place across retries. Each row
includes the exact request payload and signed headers Speechify sent
(`request_body`, `request_headers`) and the response your server returned
(`last_status_code`, `last_response_body`, `last_response_headers`), so
you can verify the signature and debug failures. Cursor-paginated: omit
`cursor` for the first page; walk pages while `has_more` is true (default
page size 50, max 200).

An endpoint that was not a target of an event has no row for it: a
project-scoped endpoint records nothing for another project's events.
An empty list therefore means either nothing matched or nothing
happened. To tell them apart, check the project's own activity first:
activity there with no delivery here is a defect to report; none there
means there was nothing to deliver.

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

## 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_…`).

### Query parameters

- `cursor` (string, optional) — Opaque pagination cursor from a previous response.
- `limit` (integer, optional, default: 50) — Max items per page (default 50, max 200).

## Response

### 200

The endpoint's delivery attempts.

- `next_cursor` (string, required, nullable) — Opaque keyset cursor for the next page. Pass back as the `cursor` request parameter. `null` when the caller has reached the end of the list (`has_more` is also `false` in that case).
- `has_more` (boolean, required) — True when more rows exist beyond this page.
- `deliveries` (list of WebhookEndpointDelivery, required)

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

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

### WebhookEndpointDelivery

One row of an endpoint's delivery log. One row per (endpoint, event, resource); updated in place across retry attempts. Each row records the exact request payload + signed headers Speechify sent and the response your server returned, so you can verify the signature and debug failures.

- `id` (string, required) — Prefixed delivery id (`whd_<26 char Crockford base32>`).
- `webhook_endpoint_id` (string, required) — The endpoint this delivery targeted (`whe_…`).
- `event` (string, required) — The event type delivered (see `WebhookEventType`).
- `url` (string, required) — The destination URL at delivery time.
- `status` (enum, required) — Lifecycle of a webhook delivery row. The sender updates the same row across retries, so a read always sees the latest outcome.
  - Allowed values: `pending`, `delivered`, `failed`
- `attempt_count` (integer, required)
- `created_at` (datetime, required)
- `last_attempt_at` (datetime, optional)
- `last_status_code` (integer, optional)
- `last_error` (string, optional)
- `request_body` (string, optional) — The verbatim payload the `Speechify-Signature` HMAC was computed over (as `<t>.<raw_body>`).
- `request_headers` (map from string to string, optional) — Headers sent, including `Speechify-Signature` / `Speechify-Event` / `Speechify-Delivery-Id`.
- `last_response_body` (string, optional) — Your server's response body on the most recent attempt (truncated to 8 KiB).
- `last_response_headers` (map from string to string, optional)

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

**Response**

```json
{
  "next_cursor": "string",
  "has_more": true,
  "deliveries": [
    {
      "id": "whd_01krzmwm42h2hpk18sxc1hf937",
      "webhook_endpoint_id": "whe_01kwxwcbyb6wk952swa0432cf1",
      "event": "project.spend_budget.warning",
      "url": "string",
      "status": "pending",
      "attempt_count": 1,
      "created_at": "2024-01-15T09:30:00Z",
      "last_attempt_at": "2024-01-15T09:30:00Z",
      "last_status_code": 1,
      "last_error": "string",
      "request_body": "string",
      "request_headers": {},
      "last_response_body": "string",
      "last_response_headers": {}
    }
  ]
}
```