Events & SSE
Real-time event streaming via Server-Sent Events
SSE provides a persistent connection for real-time events. For one-off notifications, see Webhooks.
Endpoint
GET /api/events — Server-Sent Events stream
Opens a persistent SSE connection that delivers events as they occur across your account.
Authentication
SSE connections don't support custom headers, so pass your API key via the token query parameter:
GET https://api.trunx.io/api/events?token=YOUR_API_KEYChannel Filtering
Use the optional channels query parameter (comma-separated) to subscribe to specific event channels:
GET /api/events?token=KEY&channels=sms,voice| Channel | Description |
|---|---|
sms | SMS send, receive, delivery, and failure events |
voice | Call lifecycle events (initiate, answer, complete, DTMF, AMD) |
campaign | Campaign call outcomes, prospect updates, stats |
did | DID purchases, releases, state changes |
ivr | IVR session events |
billing | Usage tracking events |
webhook | Webhook delivery events |
reputation | DID reputation changes |
If channels is omitted, all channels are streamed.
Event Format
Each SSE message includes the event type, a unique id, and a JSON data payload:
event: sms.sent
id: 12345
data: {"channel":"sms","eventType":"sms.sent","payload":{"id":"msg_abc123","from":"+14155559876","to":"+14155551234","status":"sent"},"customerId":"cust_123","timestamp":"2026-01-01T00:00:00.000Z"}Event Types by Channel
SMS
| Event | Description |
|---|---|
sms.sent | Message sent to carrier |
sms.received | Inbound message received |
sms.delivered | Carrier confirmed delivery |
sms.failed | Delivery failed |
Voice
| Event | Description |
|---|---|
voice.initiated | Outbound call initiated |
voice.ai.initiated | AI-powered call initiated |
voice.inbound | Inbound call received |
voice.answered | Call answered |
voice.completed | Call completed |
voice.ai.completed | AI call completed |
voice.failed | Call failed |
voice.amd | Answering machine detection result |
voice.dtmf | DTMF tone received |
Campaign
| Event | Description |
|---|---|
campaign.call.initiated | Campaign call started |
campaign.call.voicemail | Reached voicemail |
campaign.call.human_connected | Live person connected |
campaign.call.human_hangup | Person hung up |
campaign.call.no_answer | No answer |
campaign.call.busy | Line busy |
campaign.call.failed | Call failed |
campaign.prospect.dnc | Prospect on DNC list |
campaign.stats.updated | Campaign stats refreshed |
campaign.paused.no_dids | Campaign paused (no healthy DIDs) |
DID
| Event | Description |
|---|---|
did.purchased | New DID purchased |
did.released | DID released |
did.state_changed | DID state transition (warming, active, cooling) |
Billing
| Event | Description |
|---|---|
billing.usage | Usage event recorded |
Replay
Pass the Last-Event-ID header to replay missed events (up to the last 1000). The server sends all events after the given ID before switching to live streaming.
GET /api/events?token=KEY
Last-Event-ID: 12345This is useful for recovering from disconnections without missing events.
Code Examples
const source = new EventSource(
"https://api.trunx.io/api/events?token=tk_live_...&channels=sms,voice"
);
source.addEventListener("sms.sent", (e) => {
const data = JSON.parse(e.data);
console.log("SMS sent:", data.payload);
});
source.addEventListener("voice.completed", (e) => {
const data = JSON.parse(e.data);
console.log("Call completed:", data.payload);
});
source.onerror = (e) => {
console.error("SSE connection error:", e);
};import { fetchEventSource } from "@microsoft/fetch-event-source";
await fetchEventSource(
"https://api.trunx.io/api/events?token=tk_live_...&channels=campaign",
{
onmessage(ev) {
const data = JSON.parse(ev.data);
console.log(`${ev.event}:`, data.payload);
},
onerror(err) {
console.error("SSE error:", err);
},
// Automatically sends Last-Event-ID on reconnect
}
);import sseclient
import requests
url = "https://api.trunx.io/api/events?token=tk_live_...&channels=sms,voice"
response = requests.get(url, stream=True)
client = sseclient.SSEClient(response)
for event in client.events():
print(f"{event.event}: {event.data}")