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

# Post-call CSAT and NPS surveys: IVR digit capture, agent rollup

> Play a single-digit survey at the end of a voice call — 1–5 for CSAT, 0–10 for NPS — gate it by call type and duration, then read the totals, trends, and per-agent rollups.

# Post-call CSAT and NPS surveys

A post-call survey plays once a voice call ends and asks the caller to rate the interaction with a single keypad digit: `1`–`5` for CSAT (very dissatisfied to very satisfied), `0`–`10` for NPS. The answer is recorded against the survey, the call, and the handling agent, and feeds both per-survey analytics and the queue's agent-score rollup. Manage it in the dashboard under **Voice → Post-call CSAT** / **Post-call NPS**, or through the API below; request/response schemas live in the [voice API reference](/api-reference/voice).

Post-call surveys are distinct from the recipient-facing surveys product covered in [surveys end to end](/guides/surveys-voc): the `surveys` API distributes a survey to an audience and chases non-responders; a post-call survey is played automatically as part of the call itself, with no send step and no link to tap.

## 1. Create the survey

A post-call survey is a survey of `type` `csat` or `nps` whose delivery mode is set to the post-call voice channel. Create the template the same way you create any survey — the voice behaviour is then configured on it.

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/surveys" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Inbound support CSAT",
    "type": "csat",
    "question": "How satisfied were you with this call?",
    "channels": ["sms"]
  }'
```

Keep the returned `id` — every call below references it. The survey does nothing until you switch its `delivery_mode` and enable it in the next step.

## 2. Enable the IVR delivery and tune when it plays

Read or update the survey's voice behaviour with the config endpoints:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/voice/csat/surveys/$SURVEY_ID/config" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

```bash theme={null}
curl -X PATCH "https://api.orbit.devotel.io/api/v1/voice/csat/surveys/$SURVEY_ID/config" \
  -H "X-API-Key: $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "delivery_mode": "ivr_post_call",
    "ivr_config": {
      "only_if_min_duration_sec": 30,
      "sample_rate_pct": 50,
      "exclude_disposition_in": ["abandoned", "failed"]
    }
  }'
```

The knobs that decide whether a given ended call gets the survey at all:

| Field                              | Notes                                                                                                                                |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `prompt_text` / `prompt_audio_url` | What the caller hears before keying the digit. A hosted audio file replaces the spoken text when set.                                |
| `digit_timeout_ms`                 | How long the survey waits for a digit (1–30 seconds).                                                                                |
| `max_attempts`                     | How many digit tries the caller gets (1–3).                                                                                          |
| `only_if_human_answered`           | Skip the survey when the answered side was detected a machine or fax (default: skip).                                                |
| `only_if_min_duration_sec`         | Skip calls shorter than this many seconds (default: 30).                                                                             |
| `sample_rate_pct`                  | Survey only a percentage of qualifying calls. The same call always gets the same decision, so a retried call-end never double-plays. |
| `only_if_disposition_in`           | Optional allowlist of call outcome codes (for example `resolved`, `transferred`) — the survey plays only for those outcomes.         |
| `exclude_disposition_in`           | Optional denylist of outcome codes to never survey. The denylist wins when both lists are set.                                       |

`GET` returns the same shape with every default filled in, so you can hydrate an editor without a second write. A call that passes none or all gates either way ends normally for the caller — a skipped survey just hangs up immediately.

NPS surveys use the parallel `/api/v1/voice/nps/surveys/{id}/config` endpoints with the same body and knobs; only the scale differs (`0`–`10`, where the answer `10` is keyed as two digits).

## 3. Recorded responses

Each answered survey records the survey id, the call id, the digit pressed, the parsed score, and — when the platform resolves it — the handling agent and contact. At most one response is kept per survey per call: a duplicate arrival returns the stored row instead of a second record, so analytics never double-count a retried capture.

Low scores close the loop automatically: a detractor answer for a call with a known handling agent queues a QA evaluation against that exact interaction, and the very-low band can assign a coaching plan. If you wire webhooks, every recorded response also fires `survey.csat.response_recorded` / `survey.nps.response_recorded` with the score, the satisfaction bucket (CSAT) or promoter/passive/detractor bucket (NPS), the call id, and the agent attribution — enough for a CRM to open a follow-up activity without polling.

## 4. Read the analytics

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/voice/csat/surveys/$SURVEY_ID/analytics?window=30d" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

The window is `7d`, `30d` (default), `90d`, or `all`. The response carries the total response count, the average score, the satisfaction percentage (share of responses at score `4` or `5`), the per-score breakdown, and a daily trend:

```json theme={null}
{
  "data": {
    "window": "30d",
    "total": 312,
    "satisfied": 233,
    "dissatisfied": 21,
    "satisfaction_pct": 75,
    "avg_score": 4.12,
    "score_min": 1,
    "score_max": 5,
    "breakdown": [
      { "score": 1, "count": 9 },
      { "score": 2, "count": 12 },
      { "score": 3, "count": 58 },
      { "score": 4, "count": 121 },
      { "score": 5, "count": 112 }
    ],
    "trend": [
      { "day": "2026-08-24", "count": 26, "avg_score": 4.2 }
    ]
  }
}
```

The NPS endpoint returns the same shape plus the NPS computation — promoters minus detractors on the −100 to +100 scale — and the promoter/passive/detractor counts instead of satisfaction buckets. Add `?agent_user_id=user_…` to any analytics call to scope the whole answer to one agent's calls.

## 5. Agent-score rollup

Per-survey analytics tell you how one survey performs; the queue rollup tells you who the answers attach to. The queue analytics, agent leaderboard, and queue comparison endpoints average post-call survey scores per interval, per queue, and per agent, joining responses to calls so a call's survey counts exactly once:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/voice/queues/$QUEUE_ID/agent-leaderboard" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

Each agent row carries `avg_csat`, `avg_nps`, and the matching response counts alongside the call metrics; an agent with calls but no survey answers still appears with a null average rather than dropping out of the list. Pair a low per-agent average with the VoC drivers from [surveys end to end](/guides/surveys-voc) and the workload tooling in [QA workload management](/guides/qa-workload-management) to turn the number into a coaching action.
