Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.usetitan.app/llms.txt

Use this file to discover all available pages before exploring further.

Webhooks let you receive real-time WhatsApp events — incoming messages, session status changes, group updates, presence updates, and more — as HTTP POST requests to a URL you control. Titan signs every delivery with an HMAC-SHA256 signature so you can verify the payload is genuine. Every webhook delivery includes an X-Webhook-Signature header containing the HMAC-SHA256 signature computed from the raw request body using your hmacKey. You set the hmacKey at creation time and it is shown only once.
The hmacKey is only returned in the creation response. Store it securely — you cannot retrieve it after creation. If you lose it, update the webhook with a new key.
Titan supports 30 event types across messages, sessions, groups, presence, calls, contacts, chats, labels, newsletters, blocklists, and history sync. Pass an empty events array to subscribe to all events.

Webhook object

id
integer
Unique webhook identifier.
url
string
Target URL for webhook delivery.
events
string[]
Subscribed event types. Empty array means all events.
session
string
Session name filter. null means events from all sessions are delivered.
enabled
boolean
Whether the webhook is currently active.
headers
object[]
Custom HTTP headers included with each delivery.
retries
object
Retry configuration for failed deliveries.
createdAt
string
ISO 8601 timestamp when the webhook was created.

Create a webhook

curl -X POST https://api.example.com/api/webhooks \
  -H "Authorization: Bearer titan_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhook",
    "events": ["message.received", "session.status"],
    "session": "default",
    "hmacKey": "your-secret-signing-key",
    "retries": {
      "attempts": 3,
      "delaySeconds": 5,
      "policy": "exponential"
    },
    "headers": [
      { "name": "X-App-ID", "value": "my-app" }
    ]
  }'
POST /api/webhooks Creates a new webhook subscription. The hmacKey you supply is used to sign every delivery — store it as you would a password.
url
string
required
Target HTTPS URL for webhook delivery. Must be publicly reachable. Private IPs and localhost are rejected.
events
string[]
Event types to subscribe to. Pass an empty array or omit to receive all events. Available events: message.received, message.sent, message.ack, message.revoked, message.reaction, message.edited, message.update, message.delete, message.vote, session.status, session.qr, session.connected, session.logged_out, group.update, group.participant, presence.update, call.received, call.missed, call.accepted, call.rejected, contact.update, chat.archive, chat.mute, chat.read, chat.clear, chat.delete, labels.update, newsletter.update, blocklist.update, history.sync, command.result.
session
string
Filter deliveries to events from this session only. Omit to receive events from all sessions.
hmacKey
string
Secret key for HMAC-SHA256 signature verification. Titan computes HMAC-SHA256(rawBody, hmacKey) and includes the hex digest in the X-Webhook-Signature header.
headers
object[]
Custom HTTP headers to include with each delivery. Maximum 10 headers.
retries
object
Retry configuration for failed deliveries (non-2xx responses or timeouts).
id
integer
Unique webhook ID. Use this to update or delete the webhook.
hmacKey
string
The HMAC signing key. Only returned in this response — store it now.
{
  "data": {
    "id": 42,
    "url": "https://your-server.com/webhook",
    "events": ["message.received", "session.status"],
    "session": "default",
    "enabled": true,
    "hmacKey": "your-secret-signing-key",
    "headers": [
      { "name": "X-App-ID", "value": "my-app" }
    ],
    "retries": {
      "attempts": 3,
      "delaySeconds": 5,
      "policy": "exponential"
    },
    "createdAt": "2026-01-15T10:00:00Z"
  }
}

List webhooks

curl https://api.example.com/api/webhooks \
  -H "Authorization: Bearer titan_..."
GET /api/webhooks Returns all webhooks for your account. The hmacKey is not included in list or get responses.
{
  "data": [
    {
      "id": 42,
      "url": "https://your-server.com/webhook",
      "events": ["message.received"],
      "session": "default",
      "enabled": true,
      "createdAt": "2026-01-15T10:00:00Z"
    }
  ]
}

Get a webhook

curl https://api.example.com/api/webhooks/42 \
  -H "Authorization: Bearer titan_..."
GET /api/webhooks/{id} Returns details for a specific webhook. The hmacKey is not returned.
id
integer
required
Webhook ID.

Update a webhook

curl -X PUT https://api.example.com/api/webhooks/42 \
  -H "Authorization: Bearer titan_..." \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["message.received", "message.sent", "session.status"],
    "enabled": true
  }'
PUT /api/webhooks/{id} Updates a webhook. All fields are optional — only the fields you include are changed.
id
integer
required
Webhook ID.
url
string
New target URL.
events
string[]
New list of subscribed event types.
session
string
New session filter.
hmacKey
string
New HMAC signing key. The new key takes effect immediately.
enabled
boolean
Enable or disable the webhook.
headers
object[]
Replacement list of custom headers (replaces existing headers entirely).
retries
object
Updated retry configuration.

Delete a webhook

curl -X DELETE https://api.example.com/api/webhooks/42 \
  -H "Authorization: Bearer titan_..."
DELETE /api/webhooks/{id} Permanently deletes a webhook. Deliveries in flight will still complete.
id
integer
required
Webhook ID.
{
  "data": { "success": true, "message": "webhook deleted" }
}

Verifying webhook signatures

When you set an hmacKey, Titan includes an X-Webhook-Signature header with every delivery. Verify it by computing your own HMAC and comparing:
const crypto = require('crypto');

function verifyWebhook(rawBody, signature, hmacKey) {
  const expected = crypto
    .createHmac('sha256', hmacKey)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}
Always use a timing-safe comparison to prevent timing attacks.