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

# Recap: post-call notes

> Notes, next steps, and structured fields the moment a call ends. No bot to invite. Webhook delivery, plus Salesforce when you map fields.

Recap fires when the call ends, on audio or a transcript PyAI already has.
There is no notetaker bot to invite and no capture pipeline to build. You get
a headline, a detailed summary, decisions, action items, next steps, and the
structured fields you define.

Recap does not transcribe audio. Use Hear (async jobs or streaming) or an
Omni / Agents call, then read the Recap by `call_id`. Delivered to your
webhook, and to Salesforce when you map those fields.

## Speaker diarization before call analysis

If you start with a recording, use [Hear speaker diarization](/guides/speaker-diarization) to obtain a speaker-labelled transcript before preparing Recap input. Speaker labels are neutral: confirm agent/customer roles from your call context before mapping them into Recap. If you already have a suitable transcript, you can submit it directly.

## Enable Recap

You need `recap:configure` to change the organization setting and `recap:read`
to list or read results. A sandbox key includes both and mints with Recap
already enabled.

```bash theme={null}
curl -X PUT https://api.pyai.com/v1/recap/config \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "default_pack_id": "sales_outbound"
  }'
```

## Create a Recap from an async transcription job

Add a stable `call_id` to the job. The other Recap fields are optional.
`language` controls the language of the notes, not speech recognition. Async
transcription auto-detects the spoken language per call across the eight
supported Hear languages, and the transcript is in the detected language.

```bash theme={null}
curl -X POST https://api.pyai.com/v1/transcription/jobs \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: call-481-transcription" \
  -d '{
    "audio_url": "https://recordings.example.com/call-481.wav",
    "channel": true,
    "call_id": "call_481",
    "call_direction": "outbound",
    "customer_name": "Acme",
    "pack_id": "sales_outbound"
  }'
```

When transcription completes, PyAI sends the complete segment list to Recap.
The Recap record moves through `pending`, `processing`, and `complete`, or
`failed` if processing cannot finish. `pending` is the instant before the
record reaches the Recap service, so what you actually read back is
`processing` and then `complete`: `POST /v1/recap/calls/{call_id}` answers
`202` with `"status": "processing"`, never `"pending"`. Poll
`GET /v1/recap/calls/{call_id}` until it is `complete` or `failed`.

## Create a Recap from Hear streaming

For a Recap-enabled organization, the streaming adapter submits committed
utterances when the socket closes. Pass a stable `call_id` so the result can be
joined to your own call record:

```text theme={null}
wss://api.pyai.com/v1/audio/transcriptions/stream
  ?protocol=pyai-hear-v1
  &call_id=call_481
  &pack_id=sales_outbound
  &call_direction=inbound
```

Keep sending audio frames through pauses so turn detection can observe silence.
Only committed utterances become part of the retained transcript.

## Submit an existing transcript

If you already have speaker-labelled utterances, trigger Recap directly:

```bash theme={null}
curl -X POST https://api.pyai.com/v1/recap/calls/call_481 \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "call_direction": "outbound",
    "customer_name": "Acme",
    "utterances": [
      {
        "speaker_role": "agent",
        "text": "I will send the pricing sheet today.",
        "offset_s": 12.4,
        "duration_s": 3.1
      },
      {
        "speaker_role": "customer",
        "text": "Please include the annual option.",
        "offset_s": 16.1,
        "duration_s": 2.3
      }
    ]
  }'
```

## Read the call detail

```bash theme={null}
curl https://api.pyai.com/v1/recap/calls/call_481 \
  -H "Authorization: Bearer $PYAI_API_KEY"
```

A completed response includes two separate artifacts:

* `transcript`: the full retained utterance list with speaker roles and timing.
* `record`: typed intelligence (`recap.record.v1`). `tldr` is the one-line
  headline; `summary` is the detailed notes. `action_items`, `next_steps`,
  `talk_ratio`, `signals`, and `fields` are always present (null or empty when
  unknown).

```json theme={null}
{
  "object": "recap.call",
  "call_id": "call_481",
  "status": "complete",
  "headline": "Acme requested annual pricing and agreed to review it this week.",
  "transcript": {
    "format": "utterances.v1",
    "utterances": [
      {
        "speaker_role": "agent",
        "text": "I will send the pricing sheet today.",
        "offset_s": 12.4,
        "duration_s": 3.1
      }
    ]
  },
  "record": {
    "format": "recap.record.v1",
    "tldr": "Acme requested annual pricing and agreed to review it this week.",
    "summary": "The call focused on pricing structure and the next review step.",
    "action_items": [
      {
        "owner": "agent",
        "task": "Send annual pricing",
        "due": "today"
      }
    ],
    "disposition": null,
    "next_steps": "Email the annual option.",
    "talk_ratio": { "agent": 0.55, "customer": 0.45 },
    "signals": [],
    "fields": {}
  }
}
```

## Choose a pack

`default_pack_id` on `PUT /v1/recap/config` is the organization fallback.
`pack_id` on a Hear job, Hear stream, or manual Recap submission overrides it
for that call.

A pack selects the field and signal definitions Recap should produce for a use
case. For example, `sales_outbound` targets outbound sales notes. It does not
change speech recognition or speaker separation. Keep a stable pack id in your
application rather than inferring one from call direction.

## Receive completion webhooks

Set `webhook_url` on the organization Recap config:

```bash theme={null}
curl -X PUT https://api.pyai.com/v1/recap/config \
  -H "Authorization: Bearer $PYAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "default_pack_id": "sales_outbound",
    "webhook_url": "https://app.example.com/webhooks/recap"
  }'
```

When processing completes, PyAI posts a `recap.complete` payload containing
`call_id`, `pack_id`, `status`, `completed_at`, and the typed `record`. Verify
`X-PyAI-Signature` against the raw body with the organization webhook signing
secret. Treat webhook delivery as retriable and deduplicate by `call_id`.

## Salesforce field mapping

`PUT /v1/recap/crm-config` configures the design-partner Salesforce mapping.
It maps logical Recap fields to Salesforce API field names and can create a Task
from the TL;DR and summary. Secret fields are redacted on reads; omit an
existing secret on update to preserve it.

Most teams should configure Salesforce from **Console → Integrations** and use
the [Salesforce integration guide](/guides/integrations-salesforce). Use the
direct CRM-config endpoint only when you explicitly need the API-managed field
map.

## Review in the console

The Recap call view keeps processing and failed calls visible. A completed call
has separate Summary, Insights, Transcript, and Ops views. The Transcript view
contains every retained utterance and can be copied with timestamps.

Recap rows, including their transcript and generated intelligence, are retained
for 90 days. Input audio follows the retention policy of the Hear surface that
created the transcript. See [Security and data handling](/security-and-data).

## Troubleshooting

| Symptom | What to check |
| - | - |
| Call remains `processing` | Confirm Recap is enabled and retry the source job or transcript submission. |
| Only a one-line headline appears | Read `record.summary` or `record.summary_draft`; `tldr` is intentionally brief. |
| Transcript is missing | The record predates transcript retention or the trigger did not contain committed utterances. |
| Speaker roles are wrong | Use `channel: true` for stereo recordings or `diarize: true` for mono recordings. |
| Summary language is wrong | Set the job or manual-trigger `language`; it changes Recap output only. |

## Topics, moments and follow-ups

The Recap overview has an action worklist and a Topics view. Filter actions by
status, owner or text, then export the matching rows. Topic counts compare the
selected 7, 30 or 90 days with the preceding period of equal length. Matching
names are grouped; each call counts once per topic. Reports include all matching
calls, not just the current table page.

Open a call workspace to review **Moments & follow-ups** beside its transcript.
Topics, action items, decisions and risks can link to a supporting passage.
Extraction uses verbatim quotes and transcript turn references. Unsupported or
ambiguous references stay unlinked instead of using an estimated timestamp.
Click a linked moment to reveal the passage and play its recording when present.

Use **Tag** on a transcript turn to add a topic, action, decision, risk or note.
Assign actions to a teammate, set a due date, add tags and mark them completed.
Changes are shared with the organization and saved with revision history. Owners,
admins and developers can edit; billing members have read access.
**Completed by team** records a teammate's update, not confirmation from a CRM
or scheduling system. The transcript and original Trace scorecard stay intact.

Follow-up reports use the call's received date. Tasks from calls outside the
selected period are not included. Literal due phrases from extraction remain
visible; overdue counts use a date selected by a teammate.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.