Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.getsmartalex.com/llms.txt

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

Overview

Webhooks let you receive real-time notifications when events occur in your SmartAlex account. Configure webhook endpoints to integrate SmartAlex with your CRM, analytics tools, or custom applications.

Setting Up Webhooks

Create a Webhook Endpoint

curl -X POST "https://api.getsmartalex.com/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/smartalex",
    "event_types": ["call.completed", "campaign.completed"],
    "description": "Production CRM sync"
  }'

Parameters

ParameterTypeRequiredDescription
urlstringYesHTTPS endpoint to receive webhooks
event_typesarray of stringsYesEvent types to subscribe to (at least 1)
descriptionstringNoOptional label for your reference

Response (201 Created)

{
  "id": "webhook_abc123",
  "url": "https://your-server.com/webhooks/smartalex",
  "description": "Production CRM sync",
  "event_types": ["call.completed", "campaign.completed"],
  "is_active": true,
  "created_at": "2026-04-28T10:00:00Z",
  "signing_secret": "a3f1...long-hex-string..."
}
The signing_secret is returned only once at creation. Store it securely — you’ll need it to verify webhook signatures, and it cannot be retrieved later.

List Webhooks

curl -X GET "https://api.getsmartalex.com/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY"

Delete Webhook

curl -X DELETE "https://api.getsmartalex.com/v1/webhooks/webhook_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"
To change a webhook’s URL or event subscriptions, delete it and create a new one.

Event Types

Call Events

EventDescription
call.startedCall has been initiated
call.connectedCall was answered
call.completedCall has ended
call.failedCall could not be completed

Campaign Events

EventDescription
campaign.startedCampaign has begun calling
campaign.pausedCampaign was paused
campaign.resumedCampaign was resumed
campaign.completedCampaign finished all contacts

Contact Events

EventDescription
contact.createdNew contact was added
contact.updatedContact was modified
contact.deletedContact was removed
contact.dncContact marked Do Not Call

Callback Events

EventDescription
callback.scheduledNew callback was scheduled
callback.completedCallback was made
callback.cancelledCallback was cancelled

Webhook Payload

All webhook payloads follow this structure:
{
  "event": "call.completed",
  "tenant_id": "YOUR_WORKSPACE_ID",
  "timestamp": "2026-04-28T14:30:00Z",
  "data": {
    // Event-specific data
  }
}

Call Completed Payload

{
  "event": "call.completed",
  "tenant_id": "YOUR_WORKSPACE_ID",
  "timestamp": "2026-04-28T14:30:00Z",
  "data": {
    "id": "call_abc123",
    "direction": "inbound",
    "agent_id": "agent_def456",
    "contact_id": "contact_xyz789",
    "call_status": "completed",
    "duration_seconds": 245,
    "sentiment": "positive",
    "cost": 0.45,
    "summary": "Customer scheduled appointment for next Tuesday.",
    "start_timestamp": "2026-04-28T14:26:00Z",
    "end_timestamp": "2026-04-28T14:30:05Z"
  }
}

Campaign Completed Payload

{
  "event": "campaign.completed",
  "tenant_id": "YOUR_WORKSPACE_ID",
  "timestamp": "2026-04-28T18:00:00Z",
  "data": {
    "id": "campaign_abc123",
    "name": "January Outreach",
    "started_at": "2026-04-27T09:00:00Z",
    "completed_at": "2026-04-28T18:00:00Z"
  }
}

Contact Created Payload

{
  "event": "contact.created",
  "tenant_id": "YOUR_WORKSPACE_ID",
  "timestamp": "2026-04-28T10:00:00Z",
  "data": {
    "id": "contact_new123",
    "phone": "+15551234567",
    "first_name": "John",
    "last_name": "Smith",
    "email": "john@example.com",
    "created_at": "2026-04-28T10:00:00Z"
  }
}
The tenant_id field in every payload is your workspace identifier — useful if you operate multiple SmartAlex workspaces and want to route deliveries to different handlers.

Signature Verification

Every webhook delivery is signed with the signing_secret returned when you created the webhook. Verify the signature on every request to ensure it actually came from SmartAlex.

Headers

HeaderDescription
X-SmartAlex-SignatureHMAC-SHA256 hex digest of the raw request body, computed with your signing_secret
X-SmartAlex-EventThe event type (e.g. call.completed)

Verification Example

const crypto = require('crypto');

function verifyWebhook(rawBody, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler — make sure to pass the raw request body, not the
// parsed JSON, so the signature matches byte-for-byte.
app.post('/webhooks/smartalex', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-smartalex-signature'];

  if (!verifyWebhook(req.body, signature, 'YOUR_SIGNING_SECRET')) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body.toString());
  console.log('Received event:', event.event);

  res.status(200).send('OK');
});

Retry Policy

If your endpoint returns an error (4xx or 5xx) or times out, SmartAlex will retry delivery with exponential backoff over several attempts. After repeated failures, the webhook delivery is marked failed — failed deliveries are visible from your dashboard.

Best Practices

Return a 200 response as soon as you receive the webhook. Process the data asynchronously to avoid timeouts (we time out after 10 seconds).
app.post('/webhooks/smartalex', (req, res) => {
  res.status(200).send('OK');

  processWebhook(req.body).catch(console.error);
});
Webhooks may be delivered more than once. Use a stable identifier from the payload (e.g. data.id for call/campaign/contact events) to deduplicate:
const processedEvents = new Set();

async function processWebhook(event) {
  const dedupeKey = `${event.event}:${event.data.id}:${event.timestamp}`;
  if (processedEvents.has(dedupeKey)) {
    return; // Already processed
  }
  processedEvents.add(dedupeKey);

  // Process the event
}
Webhook endpoints must use HTTPS. HTTP endpoints will be rejected.
Always verify the webhook signature to ensure requests are from SmartAlex.