# 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](/guides/receiving-webhooks) and [Verifying webhook signatures](/guides/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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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.

```json
{
  "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/&#123;webhook_endpoint_id&#125;/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.

```json
{
  "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
    }
  }
}
```
