## Create a new webhook subscription

**post** `/v3/webhook-subscriptions`

Create a new webhook subscription to receive events at a target URL.
Upon creation, a signing secret is generated for verifying webhook
authenticity. **Store this secret securely — it cannot be retrieved later.**

**Phone Number Filtering:**

- Optionally specify `phone_numbers` to only receive events for specific lines
- If omitted, events from all phone numbers are delivered (default behavior)
- Use multiple subscriptions with different `phone_numbers` to route different lines to different endpoints
- Each `target_url` can only be used once per account. To route different
  lines to different destinations, use a unique URL per subscription
  (e.g., append a query parameter: `https://example.com/webhook?line=1`)

**Webhook Delivery:**

- Events are sent via HTTP POST to the target URL
- Each request includes [Standard Webhooks](https://github.com/standard-webhooks/standard-webhooks) headers (`webhook-id`, `webhook-timestamp`, `webhook-signature`) for signature verification
- Legacy `X-Webhook-*` headers are also sent for backwards compatibility (deprecated)
- See [Verifying Webhook Signatures](https://docs.linqapp.com/channel/imessage/guides/webhooks#verifying-webhook-signatures) for verification details
- Failed deliveries (5xx, 429, network errors) are retried with exponential backoff for up to 30 minutes
- Client errors (4xx except 429) are not retried

### Body Parameters

- `subscribed_events: array of WebhookEventType`

  List of event types to subscribe to

  - `"message.sent"`

  - `"message.received"`

  - `"message.read"`

  - `"message.delivered"`

  - `"message.failed"`

  - `"message.edited"`

  - `"reaction.added"`

  - `"reaction.removed"`

  - `"poll.received"`

  - `"poll.failed"`

  - `"poll.sent"`

  - `"poll.delivered"`

  - `"poll.read"`

  - `"poll.updated"`

  - `"poll.vote.added"`

  - `"poll.vote.removed"`

  - `"poll.reaction.added"`

  - `"participant.added"`

  - `"participant.removed"`

  - `"chat.created"`

  - `"chat.group_name_updated"`

  - `"chat.group_icon_updated"`

  - `"chat.group_name_update_failed"`

  - `"chat.group_icon_update_failed"`

  - `"chat.background_updated"`

  - `"chat.background_update_failed"`

  - `"chat.typing_indicator.started"`

  - `"chat.typing_indicator.stopped"`

  - `"phone_number.status_updated"`

  - `"phone_number.assigned"`

  - `"phone_number.released"`

  - `"phone_number.line_type_updated"`

  - `"contact_card.received"`

  - `"call.initiated"`

  - `"call.ringing"`

  - `"call.answered"`

  - `"call.ended"`

  - `"call.failed"`

  - `"call.declined"`

  - `"call.no_answer"`

  - `"location.sharing.started"`

  - `"location.sharing.stopped"`

  - `"payment.succeeded"`

  - `"payment.canceled"`

  - `"payment.expired"`

  - `"payment.declined"`

  - `"payment.authorized"`

  - `"connection.created"`

  - `"connection.revoked"`

  - `"zero_day_retention.updated"`

  - `"phone_number.forwarding_updated"`

  - `"environment.line_moved"`

  - `"contact_card.created"`

  - `"contact_card.updated"`

  - `"contact_card.deleted"`

  - `"api_token.created"`

  - `"api_token.renamed"`

  - `"api_token.expiry_scheduled"`

  - `"api_token.expired"`

  - `"api_token.activated"`

  - `"api_token.deleted"`

  - `"environment.created"`

  - `"environment.renamed"`

  - `"environment.deleted"`

  - `"webhook_subscription.created"`

  - `"webhook_subscription.deleted"`

  - `"webhook_subscription.target_url_changed"`

  - `"webhook_subscription.enabled"`

  - `"webhook_subscription.disabled"`

  - `"webhook_subscription.events.updated"`

  - `"webhook_subscription.phone_numbers.updated"`

  - `"webhook_subscription.routing_headers_set"`

  - `"webhook_subscription.routing_headers_cleared"`

  - `"team_member.added"`

  - `"team_member.signed_in"`

  - `"team_member.signed_out"`

- `target_url: string`

  URL where webhook events will be sent. Must be HTTPS.

- `phone_numbers: optional array of string`

  Optional list of phone numbers to filter events for. Only events originating from these phone numbers will be delivered to this subscription. If omitted or empty, events from all phone numbers are delivered. Phone numbers must be in E.164 format.

- `routing_id_header: optional string`

  Name of the header carrying the chat id, used to hash-route before a token is learned. Defaults to `Linq-Chat-Id`. Ignored without `routing_key_header`.

- `routing_key_header: optional string`

  Enables delivery affinity. Name of the header carrying an opaque routing token: we send it on each webhook for a chat and read it back from your 2xx response, so your edge can route to the cluster holding that chat. Omit to disable.

### Returns

- `id: string`

  Unique identifier for the webhook subscription

- `created_at: string`

  When the subscription was created

- `is_active: boolean`

  Whether this subscription is currently active

- `signing_secret: string`

  Secret for verifying webhook signatures. Store this securely - it cannot be retrieved again.

- `subscribed_events: array of WebhookEventType`

  List of event types this subscription receives

  - `"message.sent"`

  - `"message.received"`

  - `"message.read"`

  - `"message.delivered"`

  - `"message.failed"`

  - `"message.edited"`

  - `"reaction.added"`

  - `"reaction.removed"`

  - `"poll.received"`

  - `"poll.failed"`

  - `"poll.sent"`

  - `"poll.delivered"`

  - `"poll.read"`

  - `"poll.updated"`

  - `"poll.vote.added"`

  - `"poll.vote.removed"`

  - `"poll.reaction.added"`

  - `"participant.added"`

  - `"participant.removed"`

  - `"chat.created"`

  - `"chat.group_name_updated"`

  - `"chat.group_icon_updated"`

  - `"chat.group_name_update_failed"`

  - `"chat.group_icon_update_failed"`

  - `"chat.background_updated"`

  - `"chat.background_update_failed"`

  - `"chat.typing_indicator.started"`

  - `"chat.typing_indicator.stopped"`

  - `"phone_number.status_updated"`

  - `"phone_number.assigned"`

  - `"phone_number.released"`

  - `"phone_number.line_type_updated"`

  - `"contact_card.received"`

  - `"call.initiated"`

  - `"call.ringing"`

  - `"call.answered"`

  - `"call.ended"`

  - `"call.failed"`

  - `"call.declined"`

  - `"call.no_answer"`

  - `"location.sharing.started"`

  - `"location.sharing.stopped"`

  - `"payment.succeeded"`

  - `"payment.canceled"`

  - `"payment.expired"`

  - `"payment.declined"`

  - `"payment.authorized"`

  - `"connection.created"`

  - `"connection.revoked"`

  - `"zero_day_retention.updated"`

  - `"phone_number.forwarding_updated"`

  - `"environment.line_moved"`

  - `"contact_card.created"`

  - `"contact_card.updated"`

  - `"contact_card.deleted"`

  - `"api_token.created"`

  - `"api_token.renamed"`

  - `"api_token.expiry_scheduled"`

  - `"api_token.expired"`

  - `"api_token.activated"`

  - `"api_token.deleted"`

  - `"environment.created"`

  - `"environment.renamed"`

  - `"environment.deleted"`

  - `"webhook_subscription.created"`

  - `"webhook_subscription.deleted"`

  - `"webhook_subscription.target_url_changed"`

  - `"webhook_subscription.enabled"`

  - `"webhook_subscription.disabled"`

  - `"webhook_subscription.events.updated"`

  - `"webhook_subscription.phone_numbers.updated"`

  - `"webhook_subscription.routing_headers_set"`

  - `"webhook_subscription.routing_headers_cleared"`

  - `"team_member.added"`

  - `"team_member.signed_in"`

  - `"team_member.signed_out"`

- `target_url: string`

  URL where webhook events will be sent

- `updated_at: string`

  When the subscription was last updated

- `phone_numbers: optional array of string`

  Phone numbers this subscription filters for. If null or empty, events from all phone numbers are delivered.

- `routing_id_header: optional string`

  Header carrying the chat id. Defaults to `Linq-Chat-Id` when affinity is on.

- `routing_key_header: optional string`

  Header carrying the routing token. Null disables delivery affinity.

### Example

```http
curl https://api.linqapp.com/api/partner/v3/webhook-subscriptions \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $LINQ_API_V3_API_KEY" \
    -d '{
          "subscribed_events": [
            "message.sent",
            "message.delivered",
            "message.read"
          ],
          "target_url": "https://webhooks.example.com/linq/events",
          "phone_numbers": [
            "+12025551234",
            "+12025559876"
          ],
          "routing_id_header": "X-Chat-Id",
          "routing_key_header": "X-Route-Token"
        }'
```

#### Response

```json
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
  "created_at": "2024-01-15T10:30:00Z",
  "is_active": true,
  "signing_secret": "whsec_abc123def456",
  "subscribed_events": [
    "message.sent",
    "message.delivered",
    "message.read"
  ],
  "target_url": "https://webhooks.example.com/linq/events",
  "updated_at": "2024-01-15T10:30:00Z",
  "phone_numbers": [
    "string"
  ],
  "routing_id_header": "X-Chat-Id",
  "routing_key_header": "X-Route-Token"
}
```
