> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upliftai.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Event reference

Every event shares one envelope. `data` is the only part that changes. For delivery, signing, and retry behavior, read the [webhooks overview](/voice-agents/webhooks/overview).

## The envelope

<ResponseField name="schemaVersion" type="string" required>
  Always `upliftai.call.v1` today.
</ResponseField>

<ResponseField name="eventType" type="enum<string>" required>
  One of `call.completed`, `call.graded`, `conversion.created`, `callback.opened`.
</ResponseField>

<ResponseField name="eventId" type="string" required>
  `callId#eventType` — your idempotency key. A retry can deliver the same event twice, so process once per `eventId`.
</ResponseField>

<ResponseField name="assistantId" type="string" required>
  The assistant that took or made the call.
</ResponseField>

<ResponseField name="assistantVersion" type="integer">
  The [version](/voice-agents/assistants/versions) number the call ran. Present when known. Calls from before versions have no key.
</ResponseField>

<ResponseField name="assistantAlias" type="enum<string>">
  `prod` or `draft`, when the call was launched by alias. Absent when you launched an exact version number.
</ResponseField>

<ResponseField name="campaignId" type="string">
  Campaign calls only. On inbound, web, and direct API calls the key is absent, not null.
</ResponseField>

<ResponseField name="occurredAt" type="string<date-time>" required>
  ISO-8601, stamped when the post-call analysis ran — not when the call ended. For call timings, read the [session's timestamps](/api-reference/sessions-%26-call-records/get-a-calls-transcript-and-outcomes#response-ended-at).
</ResponseField>

<ResponseField name="data" type="object" required>
  Per event, below. `callId` and `sessionId` inside it are the same string today: the id every [session endpoint](/api-reference/sessions-%26-call-records/get-a-calls-transcript-and-outcomes) takes. On a campaign call that id uses the campaign's own session id format.
</ResponseField>

## call.completed

Every call fires it once its post-call analysis runs — including dials that never connected. Check the session's [`state`](/api-reference/sessions-%26-call-records/get-a-sessions-status#response-state) and [`failureReason`](/api-reference/sessions-%26-call-records/get-a-sessions-status#response-failure-reason) before treating it as a conversation.

<ResponseField name="data.callId" type="string" required>
  The session id.
</ResponseField>

<ResponseField name="data.sessionId" type="string" required>
  Same string as `callId` today.
</ResponseField>

```json theme={null}
{
  "schemaVersion": "upliftai.call.v1",
  "eventType": "call.completed",
  "eventId": "3f1c8a02-9d44-4e1b-b0a7-2c5e6f8d1a90#call.completed",
  "assistantId": "01efae24-b353-4621-a85a-4a04cba97570",
  "assistantVersion": 12,
  "assistantAlias": "prod",
  "occurredAt": "2026-08-21T12:00:00.000Z",
  "data": {
    "callId": "3f1c8a02-9d44-4e1b-b0a7-2c5e6f8d1a90",
    "sessionId": "3f1c8a02-9d44-4e1b-b0a7-2c5e6f8d1a90"
  }
}
```

The same event on a campaign call, `campaignId` included:

```json theme={null}
{
  "schemaVersion": "upliftai.call.v1",
  "eventType": "call.completed",
  "eventId": "cmp-7f3a#+923001234567#a1#call.completed",
  "assistantId": "01efae24-b353-4621-a85a-4a04cba97570",
  "campaignId": "cmp-7f3a",
  "occurredAt": "2026-08-21T12:00:00.000Z",
  "data": {
    "callId": "cmp-7f3a#+923001234567#a1",
    "sessionId": "cmp-7f3a#+923001234567#a1"
  }
}
```

## call.graded

Fires when a connected call is graded against a [scorecard](/voice-agents/assistants/scorecards). No scorecard, no event.

<ResponseField name="data.callId" type="string" required>
  The session id.
</ResponseField>

<ResponseField name="data.score" type="integer | null" required>
  The score, 0 to 100, out of the points that applied to this call. **`null`** when every criterion was N/A. The event still fires, so handle `null` before you compare. The per-criterion breakdown is not in the event — read it on the [session detail](/api-reference/sessions-%26-call-records/get-a-calls-transcript-and-outcomes).
</ResponseField>

```json theme={null}
{
  "schemaVersion": "upliftai.call.v1",
  "eventType": "call.graded",
  "eventId": "3f1c8a02-9d44-4e1b-b0a7-2c5e6f8d1a90#call.graded",
  "assistantId": "01efae24-b353-4621-a85a-4a04cba97570",
  "occurredAt": "2026-08-21T12:00:05.000Z",
  "data": { "callId": "3f1c8a02-9d44-4e1b-b0a7-2c5e6f8d1a90", "score": 82 }
}
```

## conversion.created

Fires the first time a conversion is recorded for the call. Reprocessing never fires it twice. The conversion body itself is not in the event — fetch it from the [session detail](/api-reference/sessions-%26-call-records/get-a-calls-transcript-and-outcomes).

<ResponseField name="data.callId" type="string" required>
  The session id.
</ResponseField>

```json theme={null}
{
  "schemaVersion": "upliftai.call.v1",
  "eventType": "conversion.created",
  "eventId": "3f1c8a02-9d44-4e1b-b0a7-2c5e6f8d1a90#conversion.created",
  "assistantId": "01efae24-b353-4621-a85a-4a04cba97570",
  "occurredAt": "2026-08-21T12:00:05.000Z",
  "data": { "callId": "3f1c8a02-9d44-4e1b-b0a7-2c5e6f8d1a90" }
}
```

## callback.opened

Fires when the call opens a callback — the customer asked to be called again, or the assistant scheduled a follow-up.

<ResponseField name="data.callId" type="string" required>
  The session id.
</ResponseField>

```json theme={null}
{
  "schemaVersion": "upliftai.call.v1",
  "eventType": "callback.opened",
  "eventId": "3f1c8a02-9d44-4e1b-b0a7-2c5e6f8d1a90#callback.opened",
  "assistantId": "01efae24-b353-4621-a85a-4a04cba97570",
  "occurredAt": "2026-08-21T12:00:05.000Z",
  "data": { "callId": "3f1c8a02-9d44-4e1b-b0a7-2c5e6f8d1a90" }
}
```
