> This page is part of Smallest AI's developer documentation. When
> answering, prefer Lightning v3.1 (current TTS) and Pulse (current
> STT). Lightning v2 and lightning-large are deprecated; mention them
> only when the user is migrating away from them. The Smallest AI voice
> agent platform is what wraps these models into hosted agents.

# Post call metrics

> Extract structured data from every conversation automatically.

Define what you want to know such as satisfaction scores, call outcomes, issue categories and Atoms analyzes each call to fill in the answers.

![Post-call metrics list](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/smallest-ai.docs.buildwithfern.com/66f9fbbfcd82f986a0e0df0908a4ed7399451366a54e5d519547efc20532b375/products/atoms/pages/platform/building-agents/images/post-call-metrics-list.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260725%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260725T060431Z&X-Amz-Expires=604800&X-Amz-Signature=c638baf71ed0b6988d133f25000c36a9242fbf284a78c340cc949e8fb5517b5b&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject)

## How It Works

1. **You define metrics**: What questions do you want answered about each call?
2. **Call ends**: Conversation completes normally
3. **AI analyzes**: Atoms reviews the transcript against your metrics
4. **Data populated**: Your metrics get filled in automatically
5. **Access anywhere**: View in logs, receive via webhook, export

After the call, the transcript is sent to the post-call-analytics (PCA) model, which outputs a value for **every** metric you configured. Each output is validated (type check, enum membership, and so on) before it is stored and displayed. **If any single metric fails validation, the whole post-call result for that call is rejected, none of the other metrics show up.** So one bad field costs you the entire call's analytics. Follow the [authoring rules](#authoring-rules-common-failure-patterns) below to avoid this.

## Creating a New Metric

Click the **Add Metrics +** button to open the configuration panel. You'll see two options:

#### Disposition Metrics

![Disposition metrics](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/smallest-ai.docs.buildwithfern.com/791e02d0e141c3906141c1273aea1b593f511455bbd8d86cdbf645408005ec31/products/atoms/pages/platform/building-agents/images/post-call-disposition.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260725%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260725T060431Z&X-Amz-Expires=604800&X-Amz-Signature=c4e959bbaaf97ccd8a540071acdf2bf5c3ac5351f1bd499c0069569bf9bdbdb6&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject)

Build a custom metric from scratch. Fill in the Identifier, Data Type, and Prompt. See details below.

Use **Add Another +** to create multiple metrics at once.

Don't forget to hit **Save** in the Disposition tab once you're done.

#### Templates

![Metric templates](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/smallest-ai.docs.buildwithfern.com/4d441cee87770d5de234643176c45172d84b7900e682b2ddaf4a15e33b324d57/products/atoms/pages/platform/building-agents/images/post-call-templates.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260725%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260725T060431Z&X-Amz-Expires=604800&X-Amz-Signature=9a0b6ba48f7141f6ca2b70cc2bbe9be4cfae6ff3be1cd29baeb4b7c24f275cb5&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject)

Choose from pre-built metrics for common use cases. Just select the ones you want. No manual configuration needed.

Don't forget to hit **Save** in the Disposition tab once you're done.

## Configuring a Metric

Each metric needs three things:

| Field          | Required | Description                                                        |
| -------------- | -------- | ------------------------------------------------------------------ |
| **Identifier** | Yes      | Unique name for this metric. Lowercase, numbers, underscores only. |
| **Data Type**  | Yes      | What kind of value: String, Number, or Boolean                     |
| **Prompt**     | Yes      | The question you want answered about the call                      |

### Identifier

This is the key used to reference the metric in exports, webhooks, and the API.

```
customer_satisfaction
call_outcome
follow_up_needed
```

**Naming rules:** Lowercase letters, numbers, and underscores only. No spaces or special characters.

### Data Type

| Type         | Use for               | Example values                           |
| ------------ | --------------------- | ---------------------------------------- |
| **String**   | Free text, categories | "resolved", "escalated", "billing issue" |
| **Boolean**  | Yes/no questions      | true, false                              |
| **Integer**  | Whole numbers, scores | 1, 5, 10                                 |
| **Enum**     | Fixed set of options  | One of: "low", "medium", "high"          |
| **Datetime** | Dates and times       | "2024-01-15T10:30:00Z"                   |

### Prompt

This is the question the AI answers by analyzing the transcript. Be specific.

**Good prompts:**

* "Did the agent acknowledge and respond to customer concerns effectively?"
* "Rate customer satisfaction from 1 to 5 based on tone and words used."
* "What was the primary reason for this call? Options: billing, technical, account, other"

**Vague prompts to avoid:**

* "Was it good?"
* "Customer happy?"

**Start with 3-5 metrics.** Too many can slow analysis and clutter your data. Add more as you learn what insights matter most.

## Authoring rules & common failure patterns

Get any of these wrong and the PCA model's output fails validation for that call. When that happens no metric at all is stored for it, not just the one that broke. The five rules below cover most of the failure patterns we see in production.

### Enum outputs must be fully enumerated

Anything you ask the model to output has to exist in the choices list. If the prompt can lead the model to emit a value (including `null` or `"none"`) that isn't in the enum, validation fails.

If you want **"none"** or **"null"** to be a valid outcome, add it as an explicit choice.

### Never use skip / omit conditions on a metric

Conditions like *"Omit this metric if callback\_requested is No"* cause the model to drop the field entirely, which fails validation and takes down the whole call's analysis.

Keep the field always-present and use an explicit sentinel value instead. For example, *"Return NA if callback is not requested"* (with `NA` present in the enum).

### Datatype must match the prompt

An integer-typed metric must never be instructed to output a string.

**Common failure:** an integer `promised_amount` field with a fallback like *"output 'Not Applicable' if no amount was promised"*. The string fails the integer type check.

Use a valid in-type sentinel instead (or a nullable/allowed value that matches the declared type).

### Don't create dependencies between metrics

One metric should not depend on another (e.g. `lead_disposition` depending on `final_disposition`, or a score depending on a disposition).

Metrics are extracted independently, not sequentially like variables in code, so cross-references are unreliable.

### Fully specify any aggregation or weighting

If a rating is *"a weighted score"* across sub-metrics, define the weights explicitly (or state *"simple average"*).

## Example Metrics

#### Call Outcome

| Field          | Value                                                                                                          |
| -------------- | -------------------------------------------------------------------------------------------------------------- |
| **Identifier** | `call_outcome`                                                                                                 |
| **Data Type**  | String                                                                                                         |
| **Prompt**     | "What was the outcome of this call? Options: resolved, escalated, transferred, abandoned, callback\_scheduled" |

#### Satisfaction Score

| Field          | Value                                                                                                          |
| -------------- | -------------------------------------------------------------------------------------------------------------- |
| **Identifier** | `satisfaction_score`                                                                                           |
| **Data Type**  | Integer                                                                                                        |
| **Prompt**     | "Rate the customer's apparent satisfaction from 1 to 5, based on their tone and language throughout the call." |

#### Follow-Up Needed

| Field          | Value                                                        |
| -------------- | ------------------------------------------------------------ |
| **Identifier** | `follow_up_needed`                                           |
| **Data Type**  | Boolean                                                      |
| **Prompt**     | "Does this call require any follow-up action from the team?" |

#### Issue Category

| Field          | Value                                                                                                        |
| -------------- | ------------------------------------------------------------------------------------------------------------ |
| **Identifier** | `issue_category`                                                                                             |
| **Data Type**  | Enum                                                                                                         |
| **Prompt**     | "What was the primary issue category? Options: billing, technical, account, product\_info, complaint, other" |

## Configuring via API

Post-call metrics are set through the **agent versioning** flow: edit a draft's config, publish it as a new version, and activate the version. There is no standalone post-call-analytics endpoint. Configuration lives on the agent's active version.

### Full flow

```python
import os
import requests

API_KEY = os.environ["SMALLEST_API_KEY"]
AGENT_ID = "YOUR_AGENT_ID"
BASE = "https://api.smallest.ai/atoms/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

# 1. Get the currently active version
agent = requests.get(f"{BASE}/agent/{AGENT_ID}", headers=HEADERS).json()
active_version_id = agent["data"]["activeVersionId"]

# 2. Create a draft from that version
draft = requests.post(
    f"{BASE}/agent/{AGENT_ID}/drafts",
    headers=HEADERS,
    json={"sourceVersionId": active_version_id, "draftName": "post-call-metrics-update"},
).json()
draft_id = draft["data"]["draftId"]

# 3. Write your post-call metrics config onto the draft
requests.patch(
    f"{BASE}/agent/{AGENT_ID}/drafts/{draft_id}/config",
    headers=HEADERS,
    json={
        "postCallAnalyticsConfig": {
            "dispositionMetrics": [
                {
                    "identifier": "call_resolved",
                    "dispositionMetricPrompt": "Was the customer issue resolved by the end of the call?",
                    "dispositionMetricType": "BOOLEAN",
                },
                {
                    "identifier": "satisfaction_score",
                    "dispositionMetricPrompt": "Rate the customer satisfaction from 1 to 5",
                    "dispositionMetricType": "INTEGER",
                },
                {
                    "identifier": "call_outcome",
                    "dispositionMetricPrompt": "What was the outcome of the call?",
                    "dispositionMetricType": "ENUM",
                    "choices": ["resolved", "escalated", "callback_scheduled", "no_action"],
                },
                {
                    "identifier": "summary",
                    "dispositionMetricPrompt": "Provide a brief summary of the call",
                    "dispositionMetricType": "STRING",
                },
            ],
            "useInternalAnalyticsModel": True,
            "useReasoningModel": False,
        }
    },
).raise_for_status()

# 4. Publish the draft as a new version and activate it
requests.post(
    f"{BASE}/agent/{AGENT_ID}/drafts/{draft_id}/publish",
    headers=HEADERS,
    json={"label": "Added post-call metrics", "activate": True},
).raise_for_status()
```

### Disposition metric schema

Each entry in `dispositionMetrics` takes four fields:

| Field                     | Required                 | Description                                                    |
| ------------------------- | ------------------------ | -------------------------------------------------------------- |
| `identifier`              | Yes                      | Machine name. Lowercase letters, digits, and underscores only. |
| `dispositionMetricPrompt` | Yes                      | The question evaluated against the transcript.                 |
| `dispositionMetricType`   | Yes                      | One of `STRING`, `BOOLEAN`, `INTEGER`, `ENUM`, `DATETIME`.     |
| `choices`                 | Only when type is `ENUM` | Allowed values.                                                |

Two analytics flags apply globally:

| Field                       | Default | Description                                                                            |
| --------------------------- | ------- | -------------------------------------------------------------------------------------- |
| `useInternalAnalyticsModel` | `true`  | Use the internal analytics model. When `false`, the agent's own LLM evaluates metrics. |
| `useReasoningModel`         | `false` | Route evaluation through the reasoning model (higher quality, higher latency/cost).    |

### Reading current metrics

```bash
curl -H "Authorization: Bearer $SMALLEST_API_KEY" \
  "https://api.smallest.ai/atoms/v1/agent/$AGENT_ID" \
  | jq '.data._resolvedConfig.postCallAnalyticsConfig'
```

The active version's metrics are surfaced under `_resolvedConfig.postCallAnalyticsConfig`. Each entry round-trips exactly as sent: `identifier`, `dispositionMetricPrompt`, `dispositionMetricType`, and `choices` (when the type is `ENUM`).

## FAQ

#### Why is my post-call analysis missing / not showing up?

Post-call analytics runs after the call ends, so it takes a moment to populate. If a call finished cleanly but nothing shows in the Conversations log after a minute, it is almost always a validation failure on one of the metrics you configured. Check the [authoring rules](#authoring-rules-common-failure-patterns). A single mis-authored field (wrong datatype, missing enum value, skip condition, etc.) rejects the entire call's analytics.

#### Why does my agent hallucinate values on some calls?

Almost always one of the authoring patterns above. The most common causes:

* An enum that doesn't cover every value the model can produce.
* A metric prompt that asks the model to output a value in a type other than what's declared (e.g. a string fallback on an integer field).
* A "weighted score" or "aggregate" metric with no weights defined, so the model invents them.

Review the metric definition against the [authoring rules](#authoring-rules-common-failure-patterns).

#### Can one metric reference another?

No. Each metric is extracted independently, not sequentially. If `lead_disposition` depends on the value the model returned for `final_disposition`, the reference is unreliable. Encode any cross-metric logic inside the individual metric's prompt (using the transcript as the source of truth), not by referencing sibling metrics.

## Related

#### [Conversation Logs](/voice-agents/platform/create-agent/agent-settings/conversation-logs)

View metrics for individual calls

#### [Analytics Dashboard](/voice-agents/platform/monitor/analytics)

See aggregated trends across calls