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

# Retrieve and Interpret AI Call Analysis from Shilo

> Learn how to poll for completed AI analysis on calls, appointments, and roleplays, and how to read each analysis field returned by Shilo.

Once you submit a recording to Shilo, the AI pipeline processes it asynchronously. Retrieving analysis requires polling the appropriate endpoint until the `progress` field reaches `100`, then reading the structured result. This guide covers the polling pattern, every analysis field, and how to retrieve the full call transcript.

## Analysis Endpoints

All three recording types expose identical analysis and transcript endpoints:

| Resource     | Analysis endpoint                                | Transcript endpoint                                |
| ------------ | ------------------------------------------------ | -------------------------------------------------- |
| Calls        | `GET /api/v1/calls/{identifier}/analysis`        | `GET /api/v1/calls/{identifier}/transcript`        |
| Appointments | `GET /api/v1/appointments/{identifier}/analysis` | `GET /api/v1/appointments/{identifier}/transcript` |
| Roleplays    | `GET /api/v1/roleplays/{identifier}/analysis`    | `GET /api/v1/roleplays/{identifier}/transcript`    |

## Choosing Your Identifier

Right after submitting a call, use the `call_event_id` from the `202` response as your identifier:

```text theme={null}
call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31
```

Once analysis completes and you have retrieved the full call object (which contains the stable Shilo `id`), you can switch to the plain UUID for any subsequent lookups. You can also use `external_recording_id:{your-recording-id}` at any time if you prefer to reference calls by your own IDs.

## Polling Until Complete

The `progress` field in the analysis response is an integer from `0` to `100`. Keep polling until it equals `100`.

```bash theme={null}
curl https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31/analysis \
  -H "x-api-key: YOUR_API_KEY"
```

**While processing** (`progress < 100`):

```json theme={null}
{
  "id": "a1b2c3d4-0000-0000-0000-111122223333",
  "recording_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31",
  "created_at": "2030-09-24T12:34:56Z",
  "progress": 60
}
```

**When complete** (`progress == 100`), processing has finished. Individual sub-objects (`action_items`, `coaching`, `disposition`, `objections`, `rating`, `speakers`, and `summary`) are optional and may still be `null` or omitted, so check for presence on each field before reading it.

<Tip>
  Use exponential backoff when polling. Start with a 5-second interval, then double it on each unsuccessful poll up to a maximum of 60 seconds. Most calls complete within a few seconds to a few minutes depending on recording length.
</Tip>

## Analysis Fields

### `rating`

The AI's numeric assessment of the call quality.

```json theme={null}
"rating": {
  "id": "r1r1r1r1-0000-0000-0000-000000000001",
  "outcome": 4,
  "reasoning": "Strong rapport and clear value proposition; discovery questions could be more open-ended."
}
```

* **`outcome`** (number) — Numeric score representing overall call quality or outcome result
* **`reasoning`** (string) — Human-readable explanation of the score

### `summary`

A concise narrative of the call. The `outcome` field may be either an object (commonly `{ "summary": string }`) or a plain string, so clients must handle both shapes.

Object form:

```json theme={null}
"summary": {
  "id": "s1s1s1s1-0000-0000-0000-000000000002",
  "outcome": {
    "summary": "Prospect expressed interest in the property and agreed to a follow-up appointment next Thursday."
  }
}
```

String form:

```json theme={null}
"summary": {
  "id": "s1s1s1s1-0000-0000-0000-000000000002",
  "outcome": "Prospect expressed interest in the property and agreed to a follow-up appointment next Thursday."
}
```

* **`outcome`** (object | string) — Either an object with a `summary` field or a plain summary string.
* **`outcome.summary`** (string) — When `outcome` is an object, the natural-language summary of the conversation.

### `coaching`

Structured coaching feedback for the agent.

```json theme={null}
"coaching": {
  "id": "c1c1c1c1-0000-0000-0000-000000000003",
  "possible_improvements": [
    "Ask more open-ended discovery questions before presenting price",
    "Acknowledge objections before pivoting to benefits"
  ],
  "top_moments": [
    "Handled the timeline objection with a compelling urgency frame",
    "Confirmed next steps clearly at the end of the call"
  ]
}
```

* **`possible_improvements`** (string\[]) — Specific behaviors to work on in future calls
* **`top_moments`** (string\[]) — Positive highlights worth reinforcing in coaching sessions

### `disposition`

The AI's classification of the call outcome.

```json theme={null}
"disposition": {
  "id": "d1d1d1d1-0000-0000-0000-000000000004",
  "outcomes": ["Qualified lead"],
  "reasoning": "Prospect confirmed budget and expressed positive intent to move forward."
}
```

* **`outcomes`** (string\[]) — One or more outcome labels for the call
* **`reasoning`** (string) — Explanation for the classification

### `objections`

Objections the prospect raised during the conversation.

```json theme={null}
"objections": {
  "id": "o1o1o1o1-0000-0000-0000-000000000005",
  "outcomes": ["Price concerns", "Needs to consult spouse"]
}
```

* **`outcomes`** (string\[]) — List of objection strings identified by the AI

### `action_items`

Follow-up tasks extracted from the call, split by priority.

```json theme={null}
"action_items": {
  "id": "ai1ai1a1-0000-0000-0000-000000000006",
  "primary": ["Schedule follow-up appointment for next Thursday"],
  "secondary": ["Send recap email with listing details"]
}
```

* **`primary`** (string\[]) — High-priority tasks the agent should act on immediately
* **`secondary`** (string\[]) — Supporting or lower-priority follow-up actions

### `speakers`

AI-resolved speaker identities.

```json theme={null}
"speakers": {
  "id": "sp1sp1s1-0000-0000-0000-000000000007",
  "user_name": "Alex Johnson",
  "client_name": "Jamie Rivera"
}
```

* **`user_name`** (string) — Resolved name of the agent, reconciled against your user data
* **`client_name`** (string) — Resolved name of the client or prospect

## Complete Example Response

The following payload shows what a fully populated response can look like. It is an illustrative example, not a guaranteed shape: any of `action_items`, `coaching`, `disposition`, `objections`, `rating`, `speakers`, and `summary` may be `null` or omitted, and `summary.outcome` may be an object or a string.

```json theme={null}
{
  "id": "a1b2c3d4-0000-0000-0000-111122223333",
  "recording_id": "ee6f2136-b94a-4438-9335-3acf5b2a0d31",
  "created_at": "2030-09-24T12:34:56Z",
  "progress": 100,
  "rating": {
    "id": "r1r1r1r1-0000-0000-0000-000000000001",
    "outcome": 4,
    "reasoning": "Strong rapport and clear value proposition; discovery questions could be more open-ended."
  },
  "summary": {
    "id": "s1s1s1s1-0000-0000-0000-000000000002",
    "outcome": {
      "summary": "Prospect expressed interest in the property and agreed to a follow-up appointment next Thursday."
    }
  },
  "coaching": {
    "id": "c1c1c1c1-0000-0000-0000-000000000003",
    "possible_improvements": [
      "Ask more open-ended discovery questions before presenting price",
      "Acknowledge objections before pivoting to benefits"
    ],
    "top_moments": [
      "Handled the timeline objection with a compelling urgency frame",
      "Confirmed next steps clearly at the end of the call"
    ]
  },
  "disposition": {
    "id": "d1d1d1d1-0000-0000-0000-000000000004",
    "outcomes": ["Qualified lead"],
    "reasoning": "Prospect confirmed budget and expressed positive intent to move forward."
  },
  "objections": {
    "id": "o1o1o1o1-0000-0000-0000-000000000005",
    "outcomes": ["Price concerns", "Needs to consult spouse"]
  },
  "action_items": {
    "id": "ai1ai1a1-0000-0000-0000-000000000006",
    "primary": ["Schedule follow-up appointment for next Thursday"],
    "secondary": ["Send recap email with listing details"]
  },
  "speakers": {
    "id": "sp1sp1s1-0000-0000-0000-000000000007",
    "user_name": "Alex Johnson",
    "client_name": "Jamie Rivera"
  }
}
```

## Retrieving the Transcript

Once speaker resolution is complete, you can retrieve the full sanitized transcript with AI-resolved speaker labels:

```bash theme={null}
curl https://api.shilo.ai/api/v1/calls/call_event_id:ee6f2136-b94a-4438-9335-3acf5b2a0d31/transcript \
  -H "x-api-key: YOUR_API_KEY"
```

If the transcript is not yet ready, you receive a `409 Conflict` response. Wait a moment and retry.

<Warning>
  For Shilo accounts connected to Follow Up Boss, only the **call and appointment** transcript endpoints (`GET /api/v1/calls/{identifier}/transcript` and `GET /api/v1/appointments/{identifier}/transcript`) are unsupported and return `403 Forbidden` with a message indicating the CRM integration limitation.
</Warning>

<Note>
  The roleplay transcript endpoint, `GET /api/v1/roleplays/{identifier}/transcript`, remains supported for all integrations, including Follow Up Boss.
</Note>
