API Reference

Webhook Endpoints

Create webhook endpoint

Creates a webhook receiver at an absolute HTTP(S) URL; HTTPS is recommended for production. status must be active or inactive. subscribed_events accepts public standard event names or ["*"]; signing_secret is optional, and retry_policy.max_attempts defaults to 3 and accepts 0..5. For account endpoints, creating active when another active endpoint exists for the same account returns 409 account_webhook_already_exists (40008). Call-event access is controlled by workspace is_beta. In beta workspaces, * and empty or omitted subscribed_events include call events; specific lists match only their listed events. Non-beta workspaces may use wildcard subscriptions but never receive call events; explicitly subscribing to call events returns 403 beta_feature_not_enabled. Eligibility is rechecked for every delivery, retry and dead-letter replay; lookup failures do not grant access. Ordinary message.* call records are independent.

POSThttps://api.unifyport.ai/v1/webhook-endpoints

Supported channels

all

Before you call

Use a server-side X-Api-Key for the workspace that owns the resource. Replace every placeholder before running a sample.

When creating or reactivating an account-scoped endpoint, each account_id may have only one active endpoint; a conflict returns 409 account_webhook_already_exists (40008). Multiple inactive account endpoints and workspace endpoints are allowed. An existing active endpoint can be updated while remaining active, including legacy configurations with multiple active endpoints.

Prepare your parameters
account_id
Use data.id from account creation or an account query. Account identifiers belong to the workspace selected by X-Api-Key. Get account

Request parameters

Headers

X-Api-Key
stringrequired

Workspace API key. The workspace is resolved from this header.

Content-Type
stringrequired

Use application/json when sending a JSON request body.

Request body

account_id
string

Optional public account ID in the body, e.g. acc_example. On create, binds the endpoint to the account; omission creates a workspace endpoint. On update, only validates the original binding; omission preserves ownership. Cannot switch accounts, convert a workspace endpoint to an account endpoint, or clear the binding. Query input, null, empty or whitespace-only strings, and duplicate fields are invalid. Use exactly account_id; case variants in body or query and ownership mismatches return 400 invalid_request. An explicit account outside the workspace or not found returns 404 account_not_found (20020). Account configuration overrides workspace configuration. Inactive endpoints or unmatched subscriptions do not fall back to the workspace; deleting the last independent endpoint restores inheritance for subsequent initial deliveries. The activation conflict check is limited to other active endpoints of the same account_id; workspace endpoints are exempt. See status for the conditions.

minLength: 1 · pattern: \S

url
stringrequired

Absolute HTTP(S) URL that receives webhook events. Use HTTPS in production.

format: uri

status
stringrequired

Endpoint status: active or inactive. Creating an active account endpoint or changing inactive→active returns 409 account_webhook_already_exists (40008) if the same account has another active endpoint. Multiple inactive account endpoints and multiple workspace endpoints are allowed. An existing active endpoint may remain active during updates, including historical configurations with multiple active endpoints; those endpoints are not automatically cleaned up.

enum: active, inactive

subscribed_events[]
string[]

Public standard event subscriptions. Omitted, empty, or containing * means all public events, including newly added contact.updated, but not provider.raw_event. Explicitly list event names to receive only selected events.

signing_secret
string

Optional webhook signing secret. Use placeholders in examples.

retry_policy
object

Optional retry settings. max_attempts is the number of retries after the initial request, defaults to 3, and accepts integers from 0 to 5; 0 means initial delivery only.

max_attempts
integer

Retries after the initial delivery, from 0 to 5; 0 means initial delivery only.

Understand the result

Check the returned configuration. To test delivery, the endpoint must be active and subscribed to the relevant event. Verify signatures only when signing_enabled is true; persist received events and acknowledge with 2xx.

Response 201 Created

{
  "request_id": "<REQUEST_ID>",
  "data": {
    "id": "we_example",
    "url": "https://example.com/webhook",
    "status": "active",
    "subscribed_events": [
      "*"
    ],
    "signing_enabled": true,
    "retry_policy": {
      "max_attempts": 3
    }
  }
}

Response body

id
string

Webhook endpoint identifier (we_...).

account_id
string

Public account ID for an independent account endpoint; omitted for workspace endpoints, never null.

minLength: 1

url
string

Absolute HTTP(S) URL that receives webhook deliveries; HTTPS is recommended for production.

format: uri

status
string

Endpoint status: active or inactive.

enum: active, inactive

subscribed_events[]
string[]

Public standard event types delivered to the endpoint; ["*"] means all public events and does not include provider.raw_event.

signing_enabled
boolean

true when a signing secret is set and deliveries are signed.

retry_policy
object

Retry settings returned by the API. max_attempts counts retries after the initial delivery, defaults to 3, and is limited to 0-5.

max_attempts
integer

Configured retries after the initial delivery, from 0 to 5.

Responses

201

201 Created

Request succeeded. See the example response body.

400

Bad Request

The request body, path, or parameters are invalid.

401

Unauthorized

The X-Api-Key header is missing or invalid.

403

Forbidden

The request is authenticated but is not allowed.

404

Not Found

The requested resource was not found. Check error.code and the current operation.

409

Conflict

The requested operation conflicts with an existing provider account or resource.

500

Internal Server Error

The service encountered an unexpected error.

If the request fails

Inspect HTTP status and error.code/numeric_code, and keep request_id for diagnosis. Correct invalid parameters, complete required authorization or check runtime state as appropriate. Confirm the outcome before retrying a send or another write. Error reference

Read HTTP status, error.code and error.numeric_code together in the context of the current operation. Numeric codes are strings. Keep request_id for diagnosis; it is not an idempotency key or a task identifier.

invalid_request · 10000 · 400

Check the JSON body and required fields.

What to do: Correct the parameters for this operation and channel before requesting again. Repeating an unchanged invalid request will not resolve the error.

Illustrative JSON; message varies with the actual cause · 400 · 10000
{
  "request_id": "req_example",
  "error": {
    "code": "invalid_request",
    "numeric_code": "10000",
    "message": "Invalid request parameters"
  }
}
invalid_target_workspace · 11003 · 400

The workspace override target is empty or malformed. Remove the override header and use the API key belonging to the intended workspace.

When it occurs: Applies when the request includes the X-Workspace-Id workspace override header.

What to do: Correct the parameters for this operation and channel before requesting again. Repeating an unchanged invalid request will not resolve the error.

Illustrative JSON; message varies with the actual cause · 400 · 11003
{
  "request_id": "req_example",
  "error": {
    "code": "invalid_target_workspace",
    "numeric_code": "11003",
    "message": "Invalid target workspace"
  }
}
invalid_api_key · 11001 · 401

Check whether the API key is correct and enabled.

What to do: Keep request_id and the structured codes, and investigate the current operation before taking another action.

Illustrative JSON; message varies with the actual cause · 401 · 11001
{
  "request_id": "req_example",
  "error": {
    "code": "invalid_api_key",
    "numeric_code": "11001",
    "message": "Invalid API key"
  }
}
missing_api_key · 11000 · 401

Add the X-Api-Key header.

What to do: Keep request_id and the structured codes, and investigate the current operation before taking another action.

Example · 401 · 11000
{
  "request_id": "req_xxx",
  "error": {
    "code": "missing_api_key",
    "numeric_code": "11000",
    "message": "Missing X-Api-Key header"
  }
}
beta_feature_not_enabled · 41002 · 403

The workspace needs private-beta access for calling APIs and explicit call-event subscriptions.

What to do: Keep request_id and the structured codes, and investigate the current operation before taking another action.

Example · 403 · 41002
{
  "request_id": "req_example",
  "error": {
    "code": "beta_feature_not_enabled",
    "numeric_code": "41002",
    "message": "Beta feature not enabled"
  }
}
workspace_override_forbidden · 11002 · 403

The request attempts a workspace override that this API key is not allowed to use. Remove the override header and use the API key belonging to the intended workspace.

When it occurs: Applies when the request includes the X-Workspace-Id workspace override header.

What to do: Keep request_id and the structured codes, and investigate the current operation before taking another action.

Illustrative JSON; message varies with the actual cause · 403 · 11002
{
  "request_id": "req_example",
  "error": {
    "code": "workspace_override_forbidden",
    "numeric_code": "11002",
    "message": "Workspace override is not allowed"
  }
}
account_not_found · 20020 · 404

Check account_id and use an X-Api-Key for the workspace that owns the account. An account not found in this workspace cannot be accessed with this key.

What to do: Check the target identifier, resource ownership and current workspace. Do not treat a confirmed missing or inaccessible target as a temporary service failure to retry automatically.

Illustrative JSON; message varies with the actual cause · 404 · 20020
{
  "request_id": "req_example",
  "error": {
    "code": "account_not_found",
    "numeric_code": "20020",
    "message": "Account not found"
  }
}
target_workspace_not_found · 11004 · 404

The overridden workspace was not found or is unavailable. Verify workspace ownership, remove the override header and use the intended workspace’s API key; repeated requests do not grant access.

When it occurs: Applies when the request includes the X-Workspace-Id workspace override header.

What to do: Check the target identifier, resource ownership and current workspace. Do not treat a confirmed missing or inaccessible target as a temporary service failure to retry automatically.

Illustrative JSON; message varies with the actual cause · 404 · 11004
{
  "request_id": "req_example",
  "error": {
    "code": "target_workspace_not_found",
    "numeric_code": "11004",
    "message": "Target workspace not found"
  }
}
account_webhook_already_exists · 40008 · 409

List the account’s independent endpoints using account_id and update the existing active endpoint. To switch, deactivate the old active endpoint before activating another. Do not automatically retry creation or reactivation.

What to do: Read the endpoint configuration and account scope before resubmitting. PATCH replaces settings; retain the intended subscriptions, signing configuration and retry policy. For an active-endpoint conflict, update the existing endpoint or deactivate it before enabling another.

Example · 409 · 40008
{
  "request_id": "req_example_webhook_conflict",
  "error": {
    "code": "account_webhook_already_exists",
    "numeric_code": "40008",
    "message": "Account already has an active webhook endpoint"
  }
}
create_webhook_endpoint_failed · 40001 · 500

Create webhook endpoint: an unclassified error interrupted this change; the resulting resource state needs confirmation.

What to do: Read the endpoint configuration and account scope before resubmitting. PATCH replaces settings; retain the intended subscriptions, signing configuration and retry policy. For an active-endpoint conflict, update the existing endpoint or deactivate it before enabling another.

Illustrative JSON; message varies with the actual cause · 500 · 40001
{
  "request_id": "req_example",
  "error": {
    "code": "create_webhook_endpoint_failed",
    "numeric_code": "40001",
    "message": "Failed to create webhook endpoint"
  }
}