Skip to content
RelationsAI
Try it uses test keys only. Requests go straight from your browser to https://voice-api.relationsai.com/v1 with a rai_test_ key, which never places a real call. It works once the API is enabled for your workspace (private preview: support@relationsai.com). Your key stays in this tab's memory; live keys are refused.

Events

RelationsAI sends these events to the webhook endpoints you register. Every event has the same envelope (id, object: "event", type, created_at, livemode, api_version, data.object). Delivery is at least once and unordered across resources, so deduplicate on the event id. See Receiving webhooks and Verifying webhook signatures.

call.ended

Sent when a call ends, whatever the outcome. outcome, end_reason and duration_seconds are known; the transcript, recording, analysis and charge may still be pending (see call.settled). In live mode it is sent once the end is observed, usually within seconds and at most a few minutes after the call ends. Delivered only to enabled endpoints subscribed to call.ended, in the event's mode, while webhooks are enabled for the workspace.

JSONJSON
{ "id": "evt_5Zx9Cv3Bn7Mq2Wl8Ek4Rt6", "object": "event", "type": "call.ended", "created_at": "2026-10-21T09:32:15.000Z", "livemode": true, "api_version": "2026-10-21", "data": { "object": { "id": "call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1", "object": "call", "livemode": true, "status": "ended", "outcome": "completed", "end_reason": "hangup", "direction": "outbound", "source": "api", "agent_id": "agent_3hT9kQ2mVx7RbN4pLc8Wz1", "campaign_id": null, "phone_number_id": "pn_5Lq8Xc2Rk9TzW3mBv7Np4d", "from": "+918000000001", "to": "+919000000001", "metadata": { "crm_lead_id": "L-20931" }, "created_at": "2026-10-21T09:30:00.000Z", "ended_at": "2026-10-21T09:32:14.000Z", "duration_seconds": 118, "billable_minutes": null, "cost": null, "artifacts": { "transcript": { "state": "pending" }, "recording": { "state": "pending" }, "analysis": { "state": "pending" } }, "settled": false, "settled_at": null } } }

call.settled

Sent once everything about a call is final: outcome, duration, transcript, recording, analysis and the charge. This can be several minutes after call.ended. Use it to sync final results to your systems. Delivered only to enabled endpoints subscribed to call.settled, in the event's mode, while webhooks are enabled for the workspace.

JSONJSON
{ "id": "evt_8Nm4Bv1Cx6Zl3Kj9Hg2Fd5", "object": "event", "type": "call.settled", "created_at": "2026-10-21T09:41:02.000Z", "livemode": true, "api_version": "2026-10-21", "data": { "object": { "id": "call_2Hd8Ks4Lq7Mw3Nx9Pz5Rc1", "object": "call", "livemode": true, "status": "ended", "outcome": "completed", "end_reason": "hangup", "direction": "outbound", "source": "api", "agent_id": "agent_3hT9kQ2mVx7RbN4pLc8Wz1", "campaign_id": null, "phone_number_id": "pn_5Lq8Xc2Rk9TzW3mBv7Np4d", "from": "+918000000001", "to": "+919000000001", "metadata": { "crm_lead_id": "L-20931" }, "created_at": "2026-10-21T09:30:00.000Z", "ended_at": "2026-10-21T09:32:14.000Z", "duration_seconds": 118, "billable_minutes": 2, "cost": { "amount": 600, "currency": "INR" }, "artifacts": { "transcript": { "state": "ready" }, "recording": { "state": "ready" }, "analysis": { "state": "ready" } }, "settled": true, "settled_at": "2026-10-21T09:41:02.000Z" } } }

campaign.started

Sent when a campaign run starts dialling, after a start request or when a start that was being confirmed is confirmed. Delivered only to enabled endpoints subscribed to campaign.started, in the event's mode, while webhooks are enabled for the workspace.

JSONJSON
{ "id": "evt_1Aq2Sw3De4Fr5Gt6Hy7Ju8", "object": "event", "type": "campaign.started", "created_at": "2026-10-20T08:05:00.000Z", "livemode": true, "api_version": "2026-10-21", "data": { "object": { "id": "cmp_7Wq3Er9Ty2Ui5Op8As4Df6", "object": "campaign", "livemode": true, "name": "November renewals", "agent_id": "agent_3hT9kQ2mVx7RbN4pLc8Wz1", "dnc_screening": "enforced", "status": "running", "capabilities": { "start": false, "pause": true, "resume": false, "stop": true, "update": false, "add_recipients": false }, "concurrency_limit": 5, "budget_cap": { "amount": 500000, "currency": "INR" }, "recipient_count": 1200, "progress": { "calls": 702, "connected": 451, "no_answer": 210, "failed": 41, "in_progress": 0 }, "spend": { "amount": 270600, "currency": "INR" }, "run_number": 1, "created_at": "2026-10-20T08:00:00.000Z" }, "reason": null } }

campaign.paused

Sent when a campaign is paused, by a request or automatically. data.reason says why, for example budget_cap_reached or insufficient_balance. A campaign paused automatically can be resumed once the cause is fixed. Delivered only to enabled endpoints subscribed to campaign.paused, in the event's mode, while webhooks are enabled for the workspace.

JSONJSON
{ "id": "evt_2Ws3Ed4Rf5Tg6Yh7Uj8Ik9", "object": "event", "type": "campaign.paused", "created_at": "2026-10-20T11:42:00.000Z", "livemode": true, "api_version": "2026-10-21", "data": { "object": { "id": "cmp_7Wq3Er9Ty2Ui5Op8As4Df6", "object": "campaign", "livemode": true, "name": "November renewals", "agent_id": "agent_3hT9kQ2mVx7RbN4pLc8Wz1", "dnc_screening": "enforced", "status": "paused", "capabilities": { "start": true, "pause": false, "resume": true, "stop": true, "update": true, "add_recipients": false }, "concurrency_limit": 5, "budget_cap": { "amount": 500000, "currency": "INR" }, "recipient_count": 1200, "progress": { "calls": 702, "connected": 451, "no_answer": 210, "failed": 41, "in_progress": 0 }, "spend": { "amount": 270600, "currency": "INR" }, "run_number": 1, "created_at": "2026-10-20T08:00:00.000Z" }, "reason": "budget_cap_reached" } }

campaign.resumed

Sent when a paused campaign resumes its run. Delivered only to enabled endpoints subscribed to campaign.resumed, in the event's mode, while webhooks are enabled for the workspace.

JSONJSON
{ "id": "evt_3Ed4Rf5Tg6Yh7Uj8Ik9Ol1", "object": "event", "type": "campaign.resumed", "created_at": "2026-10-20T12:10:00.000Z", "livemode": true, "api_version": "2026-10-21", "data": { "object": { "id": "cmp_7Wq3Er9Ty2Ui5Op8As4Df6", "object": "campaign", "livemode": true, "name": "November renewals", "agent_id": "agent_3hT9kQ2mVx7RbN4pLc8Wz1", "dnc_screening": "enforced", "status": "running", "capabilities": { "start": false, "pause": true, "resume": false, "stop": true, "update": false, "add_recipients": false }, "concurrency_limit": 5, "budget_cap": { "amount": 500000, "currency": "INR" }, "recipient_count": 1200, "progress": { "calls": 702, "connected": 451, "no_answer": 210, "failed": 41, "in_progress": 0 }, "spend": { "amount": 270600, "currency": "INR" }, "run_number": 1, "created_at": "2026-10-20T08:00:00.000Z" }, "reason": null } }

campaign.stopped

Sent when a campaign is stopped. data.reason is requested for a stop request. Delivered only to enabled endpoints subscribed to campaign.stopped, in the event's mode, while webhooks are enabled for the workspace.

JSONJSON
{ "id": "evt_4Rf5Tg6Yh7Uj8Ik9Ol1Pm2", "object": "event", "type": "campaign.stopped", "created_at": "2026-10-20T15:00:00.000Z", "livemode": true, "api_version": "2026-10-21", "data": { "object": { "id": "cmp_7Wq3Er9Ty2Ui5Op8As4Df6", "object": "campaign", "livemode": true, "name": "November renewals", "agent_id": "agent_3hT9kQ2mVx7RbN4pLc8Wz1", "dnc_screening": "enforced", "status": "stopped", "capabilities": { "start": true, "pause": false, "resume": false, "stop": false, "update": true, "add_recipients": false }, "concurrency_limit": 5, "budget_cap": { "amount": 500000, "currency": "INR" }, "recipient_count": 1200, "progress": { "calls": 702, "connected": 451, "no_answer": 210, "failed": 41, "in_progress": 0 }, "spend": { "amount": 270600, "currency": "INR" }, "run_number": 1, "created_at": "2026-10-20T08:00:00.000Z" }, "reason": "requested" } }

campaign.completed

Sent when a campaign run has worked through every recipient. In live mode it can arrive up to about 15 minutes after the last call ends. Delivered only to enabled endpoints subscribed to campaign.completed, in the event's mode, while webhooks are enabled for the workspace.

JSONJSON
{ "id": "evt_5Tg6Yh7Uj8Ik9Ol1Pm2Nb3", "object": "event", "type": "campaign.completed", "created_at": "2026-10-20T16:20:00.000Z", "livemode": true, "api_version": "2026-10-21", "data": { "object": { "id": "cmp_7Wq3Er9Ty2Ui5Op8As4Df6", "object": "campaign", "livemode": true, "name": "November renewals", "agent_id": "agent_3hT9kQ2mVx7RbN4pLc8Wz1", "dnc_screening": "enforced", "status": "completed", "capabilities": { "start": true, "pause": false, "resume": false, "stop": false, "update": true, "add_recipients": false }, "concurrency_limit": 5, "budget_cap": { "amount": 500000, "currency": "INR" }, "recipient_count": 1200, "progress": { "calls": 702, "connected": 451, "no_answer": 210, "failed": 41, "in_progress": 0 }, "spend": { "amount": 270600, "currency": "INR" }, "run_number": 1, "created_at": "2026-10-20T08:00:00.000Z" }, "reason": null } }

campaign.failed

Sent when a campaign run ends in failure before working through its recipients. In live mode it can arrive up to about 15 minutes after the run ends. Retrieve the recipients list to see who was reached. Delivered only to enabled endpoints subscribed to campaign.failed, in the event's mode, while webhooks are enabled for the workspace.

JSONJSON
{ "id": "evt_6Yh7Uj8Ik9Ol1Pm2Nb3Vc4", "object": "event", "type": "campaign.failed", "created_at": "2026-10-20T16:20:00.000Z", "livemode": true, "api_version": "2026-10-21", "data": { "object": { "id": "cmp_7Wq3Er9Ty2Ui5Op8As4Df6", "object": "campaign", "livemode": true, "name": "November renewals", "agent_id": "agent_3hT9kQ2mVx7RbN4pLc8Wz1", "dnc_screening": "enforced", "status": "failed", "capabilities": { "start": true, "pause": false, "resume": false, "stop": false, "update": true, "add_recipients": false }, "concurrency_limit": 5, "budget_cap": { "amount": 500000, "currency": "INR" }, "recipient_count": 1200, "progress": { "calls": 702, "connected": 451, "no_answer": 210, "failed": 41, "in_progress": 0 }, "spend": { "amount": 270600, "currency": "INR" }, "run_number": 1, "created_at": "2026-10-20T08:00:00.000Z" }, "reason": null } }

webhook_endpoint.test

Sent only when you call POST /v1/webhook-endpoints/{webhook_endpoint_id}/test, and only to that endpoint (which must be enabled). It cannot be subscribed to. data.object is the endpoint, never its secret. Use it to check your signature verification.

JSONJSON
{ "id": "evt_3Df7Gh1Jk5Lz9Xc2Vb6Nm8", "object": "event", "type": "webhook_endpoint.test", "created_at": "2026-10-21T09:45:00.000Z", "livemode": false, "api_version": "2026-10-21", "data": { "object": { "id": "we_9Pl3Ok7Ij2Uh6Yg4Tf8Rd1", "object": "webhook_endpoint", "livemode": false, "url": "https://example.com/webhooks/relationsai", "description": "CRM sync (test)", "events": [ "call.ended", "call.settled", "campaign.completed" ], "status": "enabled", "secret_last4": "x9Qa", "created_at": "2026-10-21T08:00:00.000Z", "updated_at": "2026-10-21T08:00:00.000Z", "last_delivery": null } } }