Webhooks & Events

Receive real-time notifications when events occur across all do.dev services

The do.dev event system records every significant API action and can deliver them to your webhook endpoints in real-time. This is a unified system — one set of endpoints serves all services (Send, Telco, Talk, VoIP, Transcribe).

How It Works

Your API call → do.dev service → Event recorded → Webhook delivered
  1. You make an API call (e.g., send an email, look up a phone number)
  2. The service publishes an event (e.g., send.email.sent, telco.lookup.completed)
  3. The event is stored in your event log (queryable for 30 days)
  4. If you have webhook endpoints configured, the event is delivered via HTTP POST with HMAC-SHA256 signature

Key Features

FeatureDetails
UnifiedOne webhook endpoint receives events from all services
SignedEvery delivery is HMAC-SHA256 signed with your endpoint's secret
ReliableFailed deliveries are retried up to 5 times with exponential backoff
FilterableSubscribe to all events, a specific service, or individual event types
QueryableBrowse your full event log via API or dashboard for 30 days

Quick Start

1. Create a webhook endpoint

curl -X POST https://api.do.dev/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/dodev",
    "enabled_events": ["*"]
  }'

Response:

{
  "id": "whep_abc123",
  "url": "https://example.com/webhooks/dodev",
  "enabled_events": ["*"],
  "signing_secret": "whsec_EXAMPLE_SECRET...",
  "is_active": true,
  "message": "Webhook endpoint created. Save the signing_secret - it will not be shown again."
}

Save the signing_secret — it's shown only once.

2. Handle incoming webhooks

import crypto from "crypto";

export async function POST(request: Request) {
  const body = await request.text();
  const signature = request.headers.get("X-DoDevWebhook-Signature");
  const timestamp = request.headers.get("X-DoDevWebhook-Timestamp");

  // Verify signature
  const expected = crypto
    .createHmac("sha256", SIGNING_SECRET)
    .update(`${timestamp}.${body}`)
    .digest("hex");

  const sig = signature?.split("v1=")[1];
  if (sig !== expected) {
    return new Response("Invalid signature", { status: 401 });
  }

  // Process the event
  const event = JSON.parse(body);
  console.log(`Received ${event.type}:`, event.data);

  return new Response("OK", { status: 200 });
}

3. Trigger an event

Make any API call and watch your endpoint receive the event:

# This triggers a telco.lookup.completed event
curl https://api.do.dev/v1/telco/lookup/2125551234 \
  -H "Authorization: Bearer YOUR_API_KEY"

Event Payload

Every webhook delivery has this structure:

{
  "eventId": "evt_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "type": "send.email.sent",
  "service": "send",
  "data": {
    "messageId": "msg_abc123",
    "from": "hello@example.com",
    "to": ["user@example.com"],
    "subject": "Welcome!"
  },
  "livemode": true,
  "createdAt": 1700000000000
}

Webhook Headers

Every delivery includes these headers:

HeaderDescription
X-DoDevWebhook-Signaturet={timestamp},v1={hmac_hex}
X-DoDevWebhook-IdThe event ID (e.g., evt_...)
X-DoDevWebhook-TimestampUnix timestamp of the delivery
Content-Typeapplication/json
User-AgentDoDevWebhook/1.0

Authentication

Webhook management endpoints require an API key with platform service scopes:

ScopeDescription
platform:webhooks:readView webhook endpoints and events
platform:webhooks:manageCreate, update, and delete endpoints
platform:events:readQuery the event log

Next Steps