Calls & Playbook
Configure the AI coach that listens on live sales calls, and pull back the call history it produced — over both REST and MCP.
Two surfaces share the same data. The Sales Playbook drives what the live-call coach knows: a base coaching prompt, a set of call types (each with its own script, checklist, and prompt additions), and reference documents. The Call History surface is read-only recall of completed calls — transcript, checklist coverage, sentiment, lead verdict, and drafted emails.
Each organization has exactly one playbook. GET /api/v1/playbook creates it on first access, so there is no "create playbook" call — you read it, then edit its parts.
Authentication
REST endpoints accept an API key as a bearer token:
Authorization: Bearer avs_YOUR_API_KEY. The same key authorizes the MCP server,
where tenant scope comes from the connected agent's context. See
Authentication for how to obtain a key.
Every successful REST response — including create and delete — returns HTTP 200 with the envelope { "success": true, "data": ... }. There is no 201 Created.
REST — Playbook Configuration
Base path /api/v1/playbook. All numeric IDs are integers.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/playbook |
Get the full playbook (prompt, call types, documents) |
| PUT | /api/v1/playbook/coaching-prompt |
Replace the base coaching prompt |
| GET | /api/v1/playbook/call-types |
List all call types |
| GET | /api/v1/playbook/call-types/{id} |
Get one call type |
| POST | /api/v1/playbook/call-types |
Create a call type |
| PUT | /api/v1/playbook/call-types/{id} |
Replace a call type |
| DELETE | /api/v1/playbook/call-types/{id} |
Delete a call type |
| GET | /api/v1/playbook/documents |
List reference documents |
| GET | /api/v1/playbook/documents/{id} |
Get one document |
| POST | /api/v1/playbook/documents |
Create a document |
| PUT | /api/v1/playbook/documents/{id} |
Replace a document |
| DELETE | /api/v1/playbook/documents/{id} |
Delete a document |
GET /api/v1/playbook
Returns the whole playbook. The appliesTo value is one of Phone, Video, or Both.
{
"success": true,
"data": {
"id": 1,
"baseCoachingPrompt": "You are a discovery-call coach. Keep the rep curious...",
"callTypes": [
{
"id": 4,
"name": "Discovery Call",
"appliesTo": "Phone",
"isDefault": true,
"isActive": true,
"promptAdditions": "Probe for budget authority before pitching.",
"endGoal": "Book a 30-minute discovery demo",
"callScript": "Open with the referral source, then ask...",
"checklist": [
{ "text": "Confirmed decision maker", "coverageHint": "Ask who signs off" },
{ "text": "Identified pain point", "coverageHint": null }
]
}
],
"documents": [
{ "id": 2, "title": "Objection Handling", "content": "When they say it's too expensive..." }
],
"updatedAt": "2026-06-18T14:22:05Z"
},
"timestamp": "2026-06-18T14:30:00Z"
}
PUT /api/v1/playbook/coaching-prompt
Replaces the base prompt. Call types and documents are preserved.
Request body
{
"baseCoachingPrompt": "You are a discovery-call coach. Keep the rep curious..."
}
POST /api/v1/playbook/call-types
Creates a call type. appliesTo defaults to Phone; isActive defaults to true. endGoal is optional — the outcome this call drives toward, which the live AI coach steers every suggestion toward. Each checklist item has a text and an optional coverageHint.
Request body
{
"name": "Discovery Call",
"appliesTo": "Phone",
"isDefault": true,
"isActive": true,
"promptAdditions": "Probe for budget authority before pitching.",
"endGoal": "Book a 30-minute discovery demo",
"callScript": "Open with the referral source, then ask...",
"checklist": [
{ "text": "Confirmed decision maker", "coverageHint": "Ask who signs off" }
]
}
The response wraps the created call type (with its new id) in the standard envelope.
DELETE /api/v1/playbook/call-types/{id}
{
"success": true,
"data": { "id": 4, "deleted": true },
"timestamp": "2026-06-18T14:30:00Z"
}
REST — Call History (read-only)
Base path /api/v1/calls. Recall only — billing and internal fields are never returned (see the callout below).
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/calls |
List or search calls; with recent, returns the last N |
| GET | /api/v1/calls/{id} |
Get one call with transcript, checklist results, sentiment, lead verdict, and emails |
Query parameters for /api/v1/calls
| Param | Type | Description |
|---|---|---|
outcome |
string | Filter by outcome label (e.g. Interested, NotNow, NoAnswer) |
from |
ISO-8601 | Start of the date window (inclusive) |
to |
ISO-8601 | End of the date window (inclusive) |
search |
string | Free-text across contact, company, outcome, and notes |
recent |
integer | Return the N most-recent calls with no aggregate totals |
The filtered list adds totalHours and totalCredits aggregates; the recent list omits them.
{
"success": true,
"data": {
"count": 2,
"totalHours": 0.85,
"totalCredits": 51,
"calls": [
{
"id": 318,
"source": "Browser",
"callTypeId": 4,
"status": "Completed",
"startedAt": "2026-06-18T13:02:11Z",
"endedAt": "2026-06-18T13:23:48Z",
"durationSeconds": 1297,
"fromNumber": "+15125551212",
"toNumber": "+16317454144",
"contactName": "Dana Reyes",
"companyName": "Northside Integrators",
"outcome": "Interested",
"coverageCovered": 5,
"coverageTotal": 6
}
]
},
"timestamp": "2026-06-18T14:30:00Z"
}
GET /api/v1/calls/{id} returns the same fields plus summary, nextSteps, and the parsed JSON columns transcript, checklistResults, sentiment, leadVerdict, and emails.
Call recall uses a strict allow-list. Credits used, credits settled, the Twilio call SID, the internal user ID, and lead linkage are never present in any response — by design, not by omission.
MCP Tools
The same configuration and recall are available to AI agents as MCP tools. Tool inputs and
outputs use snake_case. Connect the MCP server as described in
MCP Server.
Playbook configuration tools
| Tool | Key parameters | Description |
|---|---|---|
get_sales_playbook |
— | Full playbook: prompt, call types, documents |
update_coaching_prompt |
base_coaching_prompt |
Replace the base coaching prompt |
list_call_types |
— | List all call types |
get_call_type |
call_type_id |
Get one call type |
create_call_type |
name, applies_to, is_default, is_active, prompt_additions, end_goal, call_script, checklist_json |
Create a call type |
update_call_type |
call_type_id + any field to change |
Partial update; omitted fields are unchanged |
delete_call_type |
call_type_id |
Delete a call type |
list_playbook_documents |
— | List reference documents |
get_playbook_document |
document_id |
Get one document |
create_playbook_document |
title, content |
Create a document |
update_playbook_document |
document_id, title, content |
Partial update; omitted fields are unchanged |
delete_playbook_document |
document_id |
Delete a document |
Call recall tools
| Tool | Key parameters | Description |
|---|---|---|
list_calls |
outcome, from, to, search, recent |
List or search calls; recent returns the last N with no aggregates |
get_call |
call_id |
Full call detail including transcript and analysis columns |
The optional end_goal parameter sets the outcome the call drives toward; the live AI coach steers every suggestion toward it. The checklist_json parameter takes a raw JSON array. Note the casing asymmetry: input items use coverageHint, while tool output renders it as coverage_hint.
{
"id": 4,
"name": "Discovery Call",
"applies_to": "Phone",
"is_default": true,
"is_active": true,
"prompt_additions": "Probe for budget authority before pitching.",
"end_goal": "Book a 30-minute discovery demo",
"call_script": "Open with the referral source, then ask...",
"checklist": [
{ "text": "Confirmed decision maker", "coverage_hint": "Ask who signs off" }
]
}
Recall tools return snake_case fields. A list_calls item:
{
"count": 1,
"calls": [
{
"id": 318,
"source": "Browser",
"call_type_id": 4,
"status": "Completed",
"started_at": "2026-06-18T13:02:11Z",
"ended_at": "2026-06-18T13:23:48Z",
"duration_seconds": 1297,
"from_number": "+15125551212",
"to_number": "+16317454144",
"contact_name": "Dana Reyes",
"company_name": "Northside Integrators",
"outcome": "Interested",
"coverage_covered": 5,
"coverage_total": 6
}
]
}
MCP errors are flat: { "error": "not_found" } for a missing ID, and { "error": "invalid", "message": "..." } for a bad value. Deletes return { "success": true, "id": 4, "deleted": true }.
Error codes (REST)
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID |
appliesTo or checklist value could not be parsed |
| 400 | INVALID_TENANT |
The request had no resolvable organization context |
| 404 | NOT_FOUND |
The call type, document, or call ID does not exist for this organization |
| 500 | INTERNAL_ERROR |
Unexpected server error |
