Skip to main content

Webhooks

Webhooks allow your applications to receive real-time notifications when events occur in Crew. Use them to sync data, trigger workflows, and build integrations.

How Webhooks Work

Event occurs in Crew (e.g., call ends)

Crew sends HTTP POST to your endpoint

Your server processes the event

Your server responds with 2xx status

Setting Up Webhooks

Via Dashboard

1

Navigate to Webhooks

Go to SettingsWebhooks
2

Add Endpoint

Click Add Webhook and enter your URL
3

Select Events

Choose which events to receive
4

Save and Test

Save the webhook and send a test event

Via API

curl -X POST https://api.usecrew.ai/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/crew",
    "events": ["call.ended", "sms.received", "appointment.booked"],
    "secret": "your_webhook_secret"
  }'

Event Types

Call Events

EventDescription
call.startedCall initiated
call.answeredCall connected
call.endedCall terminated
call.transferredCall transferred
call.recording.readyRecording available
call.transcription.readyTranscript available

SMS Events

EventDescription
sms.receivedInbound SMS received
sms.sentOutbound SMS delivered
sms.failedSMS delivery failed

Agent Events

EventDescription
agent.intent_detectedIntent identified
agent.action_triggeredAction executed
agent.escalationEscalation triggered

Appointment Events

EventDescription
appointment.bookedNew appointment created
appointment.cancelledAppointment cancelled
appointment.confirmedAppointment confirmed
appointment.rescheduledAppointment moved

Campaign Events

EventDescription
campaign.startedCampaign began
campaign.completedCampaign finished
campaign.call_completedIndividual call completed

Payload Format

Standard Structure

{
  "id": "evt_abc123",
  "type": "call.ended",
  "created_at": "2024-01-15T10:30:00Z",
  "crew_id": "crew_xyz789",
  "data": {
    // Event-specific data
  }
}

Call Ended Example

{
  "id": "evt_abc123",
  "type": "call.ended",
  "created_at": "2024-01-15T10:30:00Z",
  "crew_id": "crew_xyz789",
  "data": {
    "call_id": "call_def456",
    "direction": "inbound",
    "from": "+14155551234",
    "to": "+14155559999",
    "agent_id": "agent_sarah",
    "duration": 127,
    "disposition": "completed",
    "intent": "schedule_appointment",
    "outcome": {
      "appointment_booked": true,
      "appointment_date": "2024-01-20",
      "appointment_time": "14:00"
    },
    "transcript_url": "https://api.usecrew.ai/v1/calls/call_def456/transcript",
    "recording_url": "https://api.usecrew.ai/v1/calls/call_def456/recording"
  }
}

SMS Received Example

{
  "id": "evt_ghi789",
  "type": "sms.received",
  "created_at": "2024-01-15T10:35:00Z",
  "crew_id": "crew_xyz789",
  "data": {
    "message_id": "msg_jkl012",
    "from": "+14155551234",
    "to": "+14155559999",
    "body": "Can I reschedule my appointment?",
    "media": []
  }
}

Webhook Security

Signature Verification

Every webhook includes a signature header for verification:
X-Crew-Signature: sha256=abc123...
Verify using your webhook secret:
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return `sha256=${expected}` === signature;
}

// In your webhook handler
app.post('/webhooks/crew', (req, res) => {
  const signature = req.headers['x-crew-signature'];
  const isValid = verifyWebhook(
    JSON.stringify(req.body),
    signature,
    process.env.CREW_WEBHOOK_SECRET
  );
  
  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process the webhook
  handleWebhook(req.body);
  res.status(200).send('OK');
});

Timestamp Validation

Reject old events to prevent replay attacks:
const MAX_AGE_SECONDS = 300; // 5 minutes

function isTimestampValid(createdAt) {
  const eventTime = new Date(createdAt).getTime();
  const now = Date.now();
  return (now - eventTime) < (MAX_AGE_SECONDS * 1000);
}

Retry Logic

Crew retries failed webhook deliveries:
AttemptDelay
1Immediate
230 seconds
32 minutes
410 minutes
51 hour
After 5 failed attempts, the event is marked as failed.

Failure Conditions

Webhooks are retried if:
  • Your endpoint returns a 5xx status
  • Your endpoint times out (>30 seconds)
  • Connection cannot be established
Webhooks are not retried if:
  • Your endpoint returns 2xx (success)
  • Your endpoint returns 4xx (client error)

Best Practices

Return 200 immediately, process asynchronously. Long processing causes timeouts.
Use the event id for idempotency. You may receive the same event twice.
Always validate the X-Crew-Signature header before processing.
Log all received webhooks for debugging and audit purposes.
Only use HTTPS endpoints. HTTP endpoints are rejected.

Testing Webhooks

Test Events

Send a test event to verify your endpoint:
curl -X POST https://api.usecrew.ai/v1/webhooks/{webhook_id}/test \
  -H "Authorization: Bearer YOUR_API_KEY"

Local Development

Use tools like ngrok for local testing:
ngrok http 3000
# Use the ngrok URL as your webhook endpoint

Webhook Logs

View delivery history in the dashboard:
  1. Go to SettingsWebhooks
  2. Click on a webhook endpoint
  3. View Delivery Logs

Managing Webhooks

List Webhooks

curl https://api.usecrew.ai/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY"

Update Webhook

curl -X PATCH https://api.usecrew.ai/v1/webhooks/{webhook_id} \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "events": ["call.ended", "sms.received"]
  }'

Delete Webhook

curl -X DELETE https://api.usecrew.ai/v1/webhooks/{webhook_id} \
  -H "Authorization: Bearer YOUR_API_KEY"

Pause/Resume Webhook

# Pause
curl -X POST https://api.usecrew.ai/v1/webhooks/{webhook_id}/pause \
  -H "Authorization: Bearer YOUR_API_KEY"

# Resume
curl -X POST https://api.usecrew.ai/v1/webhooks/{webhook_id}/resume \
  -H "Authorization: Bearer YOUR_API_KEY"

Next Steps