Platform

Events

Everything observable on your account is persisted as an event and consumable three ways. Same events, different delivery — pick per consumer.

Event types

TypeFired when
call.startedA call (inbound or outbound) connects
call.endedThe call hangs up
call.transcribedThe final transcript is ready
call.completedPost-call insights (summary, sentiment) are ready
call.takeoverA human takes over a live call
message.receivedInbound SMS/WhatsApp lands on your number
message.sentAn outbound message is accepted
webhook.pingYou fire a test ping at a subscription

Cursor polling

curl "https://klaw-voice.netlify.app/api/v1/events?type=call.ended&since=$CURSOR&limit=50" \
  -H "Authorization: Bearer $KLAW_KEY"

Returns {"events": [...], "cursor": "..."} — pass the cursor back to resume where you left off.

Long-poll (block until something happens)

curl -X POST https://klaw-voice.netlify.app/api/v1/events/wait \
  -H "Authorization: Bearer $KLAW_KEY" -H "Content-Type: application/json" \
  -d '{"types": ["message.received", "call.ended"], "timeout_ms": 55000}'

Resolves with {"event"} the moment one lands, or {"event": null, "timed_out": true}. Max wait 55s — loop it. This is what the MCP wait_for_event tool uses.

Server-sent events

TOKEN=$(curl -s -X POST https://klaw-voice.netlify.app/api/v1/events/stream-token \
  -H "Authorization: Bearer $KLAW_KEY" | jq -r .token)
curl -N "https://klaw-voice.netlify.app/api/v1/events/stream?token=$TOKEN"

Streams run ~50 seconds then close (reconnect with a fresh token); up to 6 concurrent streams per account. Permanent klw_ keys are refused in stream URLs — that's what the 120-second klwst_ token is for.

For push delivery to your servers, use Webhooks.