Configure webhook

Registers a new webhook subscription (POST) or creates/replaces the existing webhook subscription (PUT) for the authenticated user account. Each user account supports a single active webhook configuration.

POST /api/v2/webhook
PUT /api/v2/webhook

Table of contents

Endpoint summary

Property Value
HTTP methods POST, PUT
Endpoint path /api/v2/webhook
Authentication Authorization: Bearer <api_key> or Authorization: Basic <base64(username:password)>
Content-Type application/json
Success status codes 201 Created (POST or newly created via PUT), 200 OK (replaced via PUT)

POST vs. PUT behavior

Method When no webhook exists When a webhook already exists
POST /api/v2/webhook Creates the webhook subscription, generates a new signing secret, and returns 201 Created. Rejects the request with 409 Conflict.
PUT /api/v2/webhook Creates the webhook subscription, generates a new signing secret, and returns 201 Created. Replaces the existing webhook subscription, generates a new signing secret, and returns 200 OK.

Important: The shared signing secret (whsec_...) is returned only in the POST and PUT configuration responses. Store it securely upon registration to verify the X-Hub-Signature-256 HMAC-SHA256 header on incoming webhook deliveries.

Request

Request headers

Header Required Description
Authorization Yes Credentials identifying the user account context (Bearer <api_key> or Basic <credentials>).
Content-Type Yes Must be application/json.

Request body

The request body must be a JSON object with strictly case-sensitive camelCase property names.

Parameters (ConfigureWebhookRequest)

Field Type Required Description
url string Yes Target absolute http:// or https:// endpoint URL where webhook event batches will be delivered via HTTP POST.
events string[] Yes Non-empty array of event types to subscribe to ("message.received", "message.status.updated").

Supported webhook event types

Event type Trigger condition
"message.received" Triggered whenever a new inbound SMS arrives in the user's inbox folder.
"message.status.updated" Triggered whenever an outbound SMS transitions delivery status (into the sent or notsent folder).

Response

Response headers

Header Condition Description
Content-Type Always application/json
Location Returned on 201 Created Absolute path URI to the user account's webhook resource: /api/v2/webhook.

201 Created / 200 OK

Returns a WebhookResponse object containing the assigned webhookId, target url, subscribed events, and the newly generated shared signing secret.

Field Type Description
webhookId string (UUID) Unique internal identifier assigned to the webhook configuration.
url string Registered target HTTP or HTTPS notification URL.
events string[] Array of subscribed event types.
secret string Shared signing secret (prefixed with whsec_) used to compute the X-Hub-Signature-256 HMAC-SHA256 signature on webhook deliveries.

Error responses

When authentication fails, a webhook is already registered on a POST request, or the request body fails validation, the API returns a structured ApiErrorResponse object.

Common error status codes:

Status code Condition Description
401 Unauthorized Missing or invalid credentials Authentication credentials were not provided or could not be resolved to an active user.
409 Conflict Webhook already exists (POST only) A webhook subscription is already active for the user account. Use PUT /api/v2/webhook to replace it or DELETE /api/v2/webhook to remove it.
422 Unprocessable Entity Validation error url is missing or not a valid absolute HTTP/HTTPS URL, or events is missing, empty, or contains an unsupported event name.

Error schema (ApiErrorResponse):

Field Type Description
error.code integer HTTP status code (e.g., 401, 409, 422).
error.description string Explanation of the specific error condition.
error.action string Recommended action to resolve the error.
error.timestamp string (ISO 8601) Timestamp when the error occurred.

Examples

1. Register a new webhook (POST)

Registers a new webhook subscribed to both inbound messages and outbound delivery status updates.

Request:

POST /api/v2/webhook HTTP/1.1
Host: localhost:9509
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "url": "https://client.example.com/api/sms/inbound",
  "events": [
    "message.received",
    "message.status.updated"
  ]
}

Response (201 Created):

Response headers:

  • Location: /api/v2/webhook
  • Content-Type: application/json
{
  "webhookId": "7f8a9b0c-1d2e-3f4a-5b6c-7d8e9f0a1b2c",
  "url": "https://client.example.com/api/sms/inbound",
  "events": [
    "message.received",
    "message.status.updated"
  ],
  "secret": "whsec_9f83a04b12c845d09e3a7b6c5d4e1f2a"
}

2. Replace an existing webhook (PUT)

Replaces the currently active webhook configuration with a new URL or event list and rotates the signing secret.

Request:

PUT /api/v2/webhook HTTP/1.1
Host: localhost:9509
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "url": "https://client.example.com/api/sms/inbound",
  "events": [
    "message.received",
    "message.status.updated"
  ]
}

Response (200 OK):

Response headers:

  • Content-Type: application/json
{
  "webhookId": "7f8a9b0c-1d2e-3f4a-5b6c-7d8e9f0a1b2c",
  "url": "https://client.example.com/api/sms/inbound",
  "events": [
    "message.received",
    "message.status.updated"
  ],
  "secret": "whsec_8e72b15a23d956e10f4b8c7d6e5f2a3b"
}

3. Subscribe to inbound messages only (POST)

Registers a webhook subscribed exclusively to message.received events.

Request:

POST /api/v2/webhook HTTP/1.1
Host: localhost:9509
Authorization: Bearer <api_key>
Content-Type: application/json

{
  "url": "https://client.example.com/api/sms/inbound",
  "events": [
    "message.received"
  ]
}

Response (201 Created):

Response headers:

  • Location: /api/v2/webhook
  • Content-Type: application/json
{
  "webhookId": "7f8a9b0c-1d2e-3f4a-5b6c-7d8e9f0a1b2c",
  "url": "https://client.example.com/api/sms/inbound",
  "events": [
    "message.received"
  ],
  "secret": "whsec_9f83a04b12c845d09e3a7b6c5d4e1f2a"
}

4. Error: Webhook already exists on POST (409 Conflict)

Returned when attempting to register a webhook via POST when the authenticated user account already has an active subscription.

Response (409 Conflict):

{
  "error": {
    "code": 409,
    "description": "A webhook is already configured for this user account.",
    "action": "User 'http_user' already has an active webhook subscription. Use PUT to replace it or DELETE to remove it.",
    "timestamp": "2026-10-21T10:21:00+02:00"
  }
}

More information