> ## 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.

# Understanding AI Analysis Results from Shilo

> Learn what Shilo's AI analysis object contains, how to interpret each field, and how to poll for completion before reading results.

When you submit a recording to Shilo, the AI pipeline processes it asynchronously and populates an analysis object with structured coaching data. The same analysis schema is returned for calls, appointments, and roleplays, so the concepts here apply across all three resource types. Understanding how to read and interpret the analysis object is the foundation of any Shilo integration.

## Analysis Endpoints

Each recording type exposes a dedicated analysis endpoint:

| Resource     | Endpoint                                         |
| ------------ | ------------------------------------------------ |
| Calls        | `GET /api/v1/calls/{identifier}/analysis`        |
| Appointments | `GET /api/v1/appointments/{identifier}/analysis` |
| Roleplays    | `GET /api/v1/roleplays/{identifier}/analysis`    |

## The `progress` Field

The `progress` field is an integer from `0` to `100` that indicates how far along the AI processing pipeline the recording has advanced. Poll the analysis endpoint and check `progress` before reading any other field:

* **`progress < 100`** — Processing is still in progress. Analysis sub-objects may be `null` or absent. Do not use partial results.
* **`progress == 100`** — Processing is complete. Individual analysis sub-objects (`action_items`, `coaching`, `disposition`, `objections`, `rating`, `speakers`, and `summary`) are optional and may still be `null` or omitted, so clients must check for presence before reading each field.

<Tip>
  Store the completed analysis object in your own database after `progress` reaches `100`. This avoids repeated polling on already-processed recordings and reduces unnecessary API calls.
</Tip>

## Analysis Sub-Objects

### `rating`

The AI's overall assessment of the call's quality or outcome.

| Field       | Type   | Description                                                  |
| ----------- | ------ | ------------------------------------------------------------ |
| `outcome`   | number | Numeric score representing call quality or result (e.g. `4`) |
| `reasoning` | string | Human-readable explanation for the score                     |

**Example:**

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

### `summary`

A concise natural-language narrative of what happened on the call.

| Field             | Type             | Description                                                                                             |
| ----------------- | ---------------- | ------------------------------------------------------------------------------------------------------- |
| `outcome`         | object \| string | Either an object (commonly `{ "summary": string }`) or a plain string. Clients must handle both shapes. |
| `outcome.summary` | string           | When `outcome` is an object, the human-readable summary of the conversation.                            |

**Example (object form):**

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

**Example (string form):**

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

### `coaching`

Structured coaching feedback broken into two complementary lists.

| Field                   | Type      | Description                                              |
| ----------------------- | --------- | -------------------------------------------------------- |
| `possible_improvements` | string\[] | Specific behaviors the agent can improve on future calls |
| `top_moments`           | string\[] | Positive highlights worth reinforcing                    |

**Example:**

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

The AI's classification of how the call ended or what outcome it represents.

| Field       | Type      | Description                                              |
| ----------- | --------- | -------------------------------------------------------- |
| `outcomes`  | string\[] | One or more disposition labels (e.g. `"Qualified lead"`) |
| `reasoning` | string    | Explanation of why the call was classified this way      |

**Example:**

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

### `objections`

Objections that the prospect raised during the conversation.

| Field      | Type      | Description                          |
| ---------- | --------- | ------------------------------------ |
| `outcomes` | string\[] | List of identified objection strings |

**Example:**

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

### `action_items`

Follow-up tasks identified from the call, split into two priority tiers.

| Field       | Type      | Description                                             |
| ----------- | --------- | ------------------------------------------------------- |
| `primary`   | string\[] | High-priority actions the agent should take immediately |
| `secondary` | string\[] | Supporting or lower-priority follow-up tasks            |

**Example:**

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

### `speakers`

AI-resolved speaker identities reconciled with your user and contact data.

| Field         | Type   | Description                             |
| ------------- | ------ | --------------------------------------- |
| `user_name`   | string | Resolved name of the agent on the call  |
| `client_name` | string | Resolved name of the client or prospect |

**Example:**

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

## Complete Analysis Response Example

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": "Great 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"
    ],
    "top_moments": [
      "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"
  }
}
```

## Transcripts

In addition to the structured analysis object, you can retrieve the full call transcript with AI-resolved speaker names:

| Resource     | Endpoint                                           |
| ------------ | -------------------------------------------------- |
| Calls        | `GET /api/v1/calls/{identifier}/transcript`        |
| Appointments | `GET /api/v1/appointments/{identifier}/transcript` |
| Roleplays    | `GET /api/v1/roleplays/{identifier}/transcript`    |

A `409 Conflict` response means the transcript is not yet ready—speaker resolution must complete before the transcript is available. Poll and retry after a short wait.

<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`. The roleplay transcript endpoint, `GET /api/v1/roleplays/{identifier}/transcript`, remains supported for all integrations, including Follow Up Boss.
</Warning>
