Coval Conversations API
Submit and manage real-world conversation monitoring evaluations
Submit and manage real-world conversation monitoring evaluations
openapi: 3.0.3
info:
title: Coval Agents Conversations API
version: 1.0.0
description: '
Manage configurations for simulations and evaluations.
'
contact:
name: Coval API Support
email: support@coval.dev
url: https://docs.coval.ai
license:
name: Proprietary
url: https://coval.dev/terms
servers:
- url: https://api.coval.dev/v1
description: Production API
security:
- ApiKeyAuth: []
tags:
- name: Conversations
description: Submit and manage real-world conversation monitoring evaluations
paths:
/conversations:submit:
post:
tags:
- Conversations
summary: Submit conversation for evaluation
description: 'Submit a conversation for monitoring evaluation.
'
operationId: submitConversation
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitConversationRequest'
examples:
transcriptOnly:
summary: Submit transcript only (no timing needed)
value:
transcript:
- role: user
content: Hi, I'd like to check my account balance
- role: assistant
content: I can help you with that. Let me pull up your account.
- role: assistant
content: Your current balance is $1,247.53
- role: user
content: Thank you!
external_conversation_id: external-call-7x8z9a
occurred_at: '2025-11-03T14:32:00Z'
metadata:
campaign: q4-support
channel: phone
customer_tier: premium
tags:
- restaurant
- support-tier-1
audioUrl:
summary: Submit with audio URL
value:
audio_url: https://recordings.s3.amazonaws.com/calls/2025/11/call-4k2m9p.wav?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
external_conversation_id: twilio-call-CA4k2m9p
occurred_at: '2025-11-03T09:15:00Z'
metadata:
department: sales
product_interest: enterprise-plan
transcriptAndAudio:
summary: Submit transcript with audio URL (with timing to avoid retranscription)
value:
transcript:
- role: user
content: I'm having trouble logging in
start_time: 0.0
end_time: 2.3
- role: assistant
content: I understand you're experiencing login issues. Let me help troubleshoot that.
start_time: 2.8
end_time: 7.5
audio_url: https://storage.googleapis.com/support-recordings/call-mn3p8q.mp3?X-Goog-Algorithm=...
external_conversation_id: zendesk-ticket-19283
metrics:
- 29BlkepvvX19ebbLDB0y6Q
- mymKvEg6ZA65srXbTX5wSM
metadata:
ticket_id: '19283'
priority: high
customMetrics:
summary: Submit with custom metrics and conditional logic
value:
transcript:
- role: assistant
content: Hello! How can I help you today?
- role: user
content: I want to upgrade my subscription
- role: assistant
content: Great! Let me show you our available plans.
external_conversation_id: intercom-conv-xyz789
metadata:
conversation_type: sales
lead_score: 85
region: us-west
metrics:
- 29BlkepvvX19ebbLDB0y6Q
- mymKvEg6ZA65srXbTX5wSM
withToolCalls:
summary: Submit conversation with tool calls (OpenAI format)
value:
transcript:
- role: user
content: What's the weather like in San Francisco?
- role: assistant
content: null
tool_calls:
- id: call_abc123
type: function
function:
name: get_weather
arguments: '{"location": "San Francisco", "unit": "fahrenheit"}'
- role: tool
tool_call_id: call_abc123
content: '{"temperature": 72, "condition": "sunny", "humidity": 45}'
- role: assistant
content: The weather in San Francisco is currently sunny with a temperature of 72°F and 45% humidity.
- role: user
content: Thanks! Can you also check my account balance?
- role: assistant
content: null
tool_calls:
- id: call_def456
type: function
function:
name: get_account_balance
arguments: '{"account_type": "checking"}'
- role: tool
tool_call_id: call_def456
content: '{"balance": 1247.53, "currency": "USD", "as_of": "2025-11-03T14:30:00Z"}'
- role: assistant
content: Your checking account balance is $1,247.53 as of today.
external_conversation_id: chatbot-session-tool-demo
metadata:
has_tool_calls: true
tool_count: 2
transcriptWithTiming:
summary: Submit transcript with timing offsets (start_time/end_time)
value:
transcript:
- role: user
content: Hello, can you help me?
start_time: 0.0
end_time: 1.5
- role: assistant
content: Of course! What do you need assistance with?
start_time: 2.1
end_time: 4.8
- role: user
content: I need to update my billing information
start_time: 5.2
end_time: 7.3
- role: assistant
content: I can help you with that right away.
start_time: 7.9
end_time: 10.2
external_conversation_id: call-timing-example-001
occurred_at: '2025-11-03T16:00:00Z'
metadata:
channel: phone
duration_seconds: 10.2
transcriptWithAlternativeTiming:
summary: Submit transcript with alternative timing fields (firstWordStart/lastWordEnd)
value:
transcript:
- role: assistant
content: Thank you for calling. How may I assist you today?
firstWordStart: 0.0
lastWordEnd: 2.8
- role: user
content: I have a question about my recent order
firstWordStart: 3.5
lastWordEnd: 5.9
- role: assistant
content: I'd be happy to help. Can you provide your order number?
firstWordStart: 6.4
lastWordEnd: 9.1
external_conversation_id: call-timing-example-002
occurred_at: '2025-11-03T17:30:00Z'
metadata:
channel: phone
order_inquiry: true
responses:
'200':
description: Conversation submitted successfully
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitConversationResponse'
examples:
success:
summary: Successful submission
value:
conversation:
name: conversations/gk3jK9mPq2xRt5vW8yZaBc
conversation_id: gk3jK9mPq2xRt5vW8yZaBc
status: PENDING
create_time: '2025-11-03T14:32:30Z'
external_conversation_id: external-call-7x8z9a
occurred_at: '2025-11-03T14:32:00Z'
has_audio: true
agent_id: null
persona_id: null
metadata:
campaign: q4-support
channel: phone
customer_tier: premium
tags:
- restaurant
- support-tier-1
'400':
$ref: '#/components/responses/InvalidArgument'
'401':
$ref: '#/components/responses/Unauthenticated'
'404':
description: Referenced resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
agentNotFound:
summary: Agent not found
value:
error:
code: NOT_FOUND
message: 'Agent not found: gk3jK9mPq2xRt5vW8yZaBc'
details:
- field: agent_id
description: 'Agent not found: gk3jK9mPq2xRt5vW8yZaBc'
uploadNotFound:
summary: Upload not found
value:
error:
code: NOT_FOUND
message: 'Upload not found: upl_01HRAB8N9G7Q4Y3K2J5W6X1ZTC'
details:
- field: upload_id
description: 'Upload not found: upl_01HRAB8N9G7Q4Y3K2J5W6X1ZTC'
'413':
$ref: '#/components/responses/PayloadTooLarge'
'500':
$ref: '#/components/responses/InternalError'
/conversations:
get:
tags:
- Conversations
summary: List conversations
description: 'List conversations with optional filtering, pagination, and ordering.
'
operationId: listConversations
parameters:
- name: page_size
in: query
description: Maximum number of conversations to return (1-250)
required: false
schema:
type: integer
minimum: 1
maximum: 250
default: 50
- name: page_token
in: query
description: Token for retrieving next page (from previous response)
required: false
schema:
type: string
example: eyJvZmZzZXQiOiA1MH0=
- name: filter
in: query
description: 'Filter expression syntax.
**Operators:** `=`, `!=`, `>`, `<`, `>=`, `<=`, `AND`, `OR`
Values may be unquoted or double-quoted. Values containing spaces must be quoted.
**Fields:**
- `status` - PENDING, IN_QUEUE, IN_PROGRESS, COMPLETED, FAILED, CANCELLED, DELETED
- `external_conversation_id` - Your system''s conversation ID
- `create_time` - ISO 8601 timestamp
- `occurred_at` - ISO 8601 timestamp
- `metadata.{key}` - Custom metadata fields
**Examples:**
- `status=COMPLETED`
- `create_time>"2025-11-01T00:00:00Z"`
- `status=COMPLETED AND occurred_at>="2025-11-01T00:00:00Z"`
- `external_conversation_id=external-call-abc`
'
required: false
schema:
type: string
examples:
byStatus:
value: status=COMPLETED
summary: Filter by status
byDateRange:
value: create_time>="2025-11-01T00:00:00Z" AND create_time<"2025-12-01T00:00:00Z"
summary: Filter by date range
byExternalId:
value: external_conversation_id=external-call-7x8z9a
summary: Filter by external ID
byMetadata:
value: metadata.channel=phone
summary: Filter by custom metadata
combined:
value: status=COMPLETED AND metadata.department=sales
summary: Combined filters with metadata
- name: order_by
in: query
description: 'Sort field with optional `-` prefix for descending order.
**Fields:** `create_time`, `occurred_at`, `status`
**Examples:**
- `create_time` (ascending)
- `-create_time` (descending, most recent first)
- `-occurred_at` (most recent conversations first)
'
required: false
schema:
type: string
default: -occurred_at
examples:
newest:
value: -create_time
summary: Newest first
oldest:
value: create_time
summary: Oldest first
recentConversations:
value: -occurred_at
summary: Most recent conversations
- name: view
in: query
description: 'Set to `metric_breakdown` to return an aggregate of one metric''s scores
grouped by a `customer_metadata` key (e.g. vendor), computed over the whole
scored monitoring corpus, instead of the conversation list. Requires
`metric_id` and `group_by_metadata`; the response is a metric-breakdown object
(`{view, metric_id, group_by_metadata, aggregation, breakdown:[{metadata_value,
value, count}], total_count}`).
'
required: false
schema:
type: string
enum:
- metric_breakdown
- name: metric_id
in: query
description: 'Metric to aggregate when `view=metric_breakdown`, or the metric whose full
outputs should be embedded when `include=metric_outputs`.
'
required: false
schema:
type: string
- name: include
in: query
description: 'Set to `metric_outputs` to embed full outputs for `metric_id` on every
conversation in the returned page. Omitted by default to keep list payloads small.
'
required: false
schema:
type: string
enum:
- metric_outputs
- name: group_by_metadata
in: query
description: 'Required when `view=metric_breakdown`: the customer_metadata key to group by (e.g. nlp_provider).'
required: false
schema:
type: string
example: nlp_provider
- name: aggregation
in: query
description: 'Aggregation for `view=metric_breakdown`. Defaults to `success` (a YES/NO
success rate) for binary/string metrics and `avg` (numeric mean) for float
metrics.
'
required: false
schema:
type: string
enum:
- success
- avg
- name: start_date
in: query
description: Optional ISO-8601 lower bound (occurred_at) for `view=metric_breakdown`.
required: false
schema:
type: string
format: date-time
- name: end_date
in: query
description: Optional ISO-8601 upper bound (occurred_at) for `view=metric_breakdown`.
required: false
schema:
type: string
format: date-time
responses:
'200':
description: List of conversations, or a metric breakdown when `view=metric_breakdown`
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/ListConversationsResponse'
- $ref: '#/components/schemas/MetricBreakdownResponse'
examples:
withResults:
summary: List with multiple conversations
value:
conversations:
- name: conversations/gk3jK9mPq2xRt5vW8yZaBc
conversation_id: gk3jK9mPq2xRt5vW8yZaBc
status: COMPLETED
create_time: '2025-11-03T14:32:30Z'
external_conversation_id: external-call-7x8z9a
occurred_at: '2025-11-03T14:32:00Z'
has_audio: true
metadata:
campaign: q4-support
- name: conversations/hL4kL0nQr3ySt6vX9zAcDd
conversation_id: hL4kL0nQr3ySt6vX9zAcDd
status: IN_PROGRESS
create_time: '2025-11-03T15:20:18Z'
external_conversation_id: twilio-call-CA9m2k4p
occurred_at: '2025-11-03T15:20:00Z'
has_audio: true
metadata:
department: sales
next_page_token: eyJvZmZzZXQiOiA1MH0=
empty:
summary: Empty result set
value:
conversations: []
next_page_token: null
metricBreakdown:
summary: Metric breakdown grouped by a customer_metadata key
value:
view: metric_breakdown
metric_id: 29BlkepvvX19ebbLDB0y6Q
group_by_metadata: nlp_provider
aggregation: success
breakdown:
- metadata_value: decagon
value: 0.93
count: 412
- metadata_value: sierra
value: 0.88
count: 377
total_count: 789
'400':
$ref: '#/components/responses/InvalidArgument'
'401':
$ref: '#/components/responses/Unauthenticated'
'404':
$ref: '#/components/responses/NotFound'
'500':
$ref: '#/components/responses/InternalError'
/conversations/{conversation_id}:
get:
tags:
- Conversations
summary: Get conversation details
description: 'Retrieve detailed information about a specific conversation.
'
operationId: getConversation
parameters:
- name: conversation_id
in: path
description: Unique conversation identifier (22-26 characters)
required: true
schema:
type: string
minLength: 22
maxLength: 26
example: gk3jK9mPq2xRt5vW8yZaBc
- name: include_progress
in: query
description: Include progress tracking information
required: false
schema:
type: boolean
default: true
responses:
'200':
description: Conversation details
content:
application/json:
schema:
$ref: '#/components/schemas/GetConversationResponse'
examples:
completed:
summary: Completed conversation
value:
conversation:
name: conversations/gk3jK9mPq2xRt5vW8yZaBc
conversation_id: gk3jK9mPq2xRt5vW8yZaBc
status: COMPLETED
create_time: '2025-11-03T14:32:30Z'
external_conversation_id: external-call-7x8z9a
occurred_at: '2025-11-03T14:32:00Z'
has_audio: true
agent_id: null
persona_id: null
progress:
total_metrics: 5
completed_metrics: 5
failed_metrics: 0
in_progress_metrics: 0
metadata:
campaign: q4-support
channel: phone
customer_tier: premium
metric_ids:
- 29BlkepvvX19ebbLDB0y6Q
- mymKvEg6ZA65srXbTX5wSM
- fstokU4ev5UmT8sUBexiwV
error: null
inProgress:
summary: In-progress conversation
value:
conversation:
name: conversations/hL4kL0nQr3ySt6vX9zAcDd
conversation_id: hL4kL0nQr3ySt6vX9zAcDd
status: IN_PROGRESS
create_time: '2025-11-03T15:20:18Z'
external_conversation_id: twilio-call-CA9m2k4p
occurred_at: '2025-11-03T15:20:00Z'
has_audio: true
agent_id: null
persona_id: null
progress:
total_metrics: 4
completed_metrics: 2
failed_metrics: 0
in_progress_metrics: 2
metadata:
department: sales
metric_ids:
- jN8pQ3rSt6vUw9yZ2aCdFg
failed:
summary: Failed conversation
value:
conversation:
name: conversations/iM6pQ2rSt5vUw8yZ1aCdFg
conversation_id: iM6pQ2rSt5vUw8yZ1aCdFg
status: FAILED
create_time: '2025-11-03T16:45:22Z'
external_conversation_id: zendesk-19283
occurred_at: '2025-11-03T16:45:00Z'
has_audio: false
agent_id: null
persona_id: null
progress:
total_metrics: 3
completed_metrics: 1
failed_metrics: 2
in_progress_metrics: 0
metadata:
ticket_id: '19283'
metric_ids:
- kO9qR4sTu7vVx0yZ3bCeFh
error: 'Audio transcription failed: invalid audio format'
'404':
$ref: '#/components/responses/NotFound'
'401':
$ref: '#/components/responses/Unauthenticated'
'500':
$ref: '#/components/responses/InternalError'
delete:
tags:
- Conversations
summary: Delete or cancel conversation
description: 'Delete or cancel a conversation evaluation.
'
operationId: deleteConversation
parameters:
- name: conversation_id
in: path
description: Unique conversation identifier
required: true
schema:
type: string
minLength: 22
maxLength: 26
example: gk3jK9mPq2xRt5vW8yZaBc
responses:
'200':
description: Conversation deleted or cancelled successfully
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteConversationResponse'
examples:
deleted:
summary: Completed conversation deleted
value:
conversation:
name: conversations/gk3jK9mPq2xRt5vW8yZaBc
conversation_id: gk3jK9mPq2xRt5vW8yZaBc
status: DELETED
create_time: '2025-11-03T14:32:30Z'
cancelled:
summary: In-progress conversation cancelled
value:
conversation:
name: conversations/hL4kL0nQr3ySt6vX9zAcDd
conversation_id: hL4kL0nQr3ySt6vX9zAcDd
status: CANCELLED
create_time: '2025-11-03T15:20:18Z'
'404':
$ref: '#/components/responses/NotFound'
'401':
$ref: '#/components/responses/Unauthenticated'
'500':
$ref: '#/components/responses/InternalError'
patch:
tags:
- Conversations
summary: Attach audio to a conversation
description: "Attach an audio recording to a conversation previously submitted via\n`POST /v1/conversations:submit` without audio, and trigger audio-dependent\nmetrics as a second wave.\n\n**When to use this endpoint**\n\nUse this endpoint when your recording URL is not available at the moment\nthe call ends (for example, Twilio Programmable Voice recordings that are\nonly fetchable after an asynchronous job completes ~60 seconds later).\nSubmit the transcript immediately at call end to get a `conversation_id`\nfor trace correlation, then PATCH the audio when the recording URL is\nready.\n\n**Two-wave metric timing**\n\n- Text-only metrics fire immediately after `POST /v1/conversations:submit`\n and deliver their results via your configured webhook.\n- Audio-dependent metrics fire after this PATCH and deliver a separate,\n later webhook. Configure your consumer to expect both waves.\n\n**One-shot**\n\nAudio can be attached only once per conversation. Overwriting is not\nsupported in v1 — a second PATCH on a conversation that already has\naudio returns `409 ALREADY_EXISTS`.\n\n**Body**\n\nExactly one of `audio` or `audio_url` is required.\n"
operationId: patchConversation
parameters:
- name: conversation_id
in: path
description: Unique conversation identifier (22-26 characters)
required: true
schema:
type: string
minLength: 22
maxLength: 26
example: gk3jK9mPq2xRt5vW8yZaBc
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PatchConversationRequest'
examples:
audioUrl:
summary: Attach via presigned URL (typical)
value:
audio_url: https://recordings.s3.amazonaws.com/calls/2025/11/call-4k2m9p.wav?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
audioBase64:
summary: Attach raw audio (small files only)
value:
audio: UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAIA+AAACABAAZGF0YQAAAAA=
responses:
'200':
description: Audio attached successfully; audio metrics queued
content:
application/json:
schema:
$ref: '#/components/schemas/GetConversationResponse'
examples:
attached:
summary: Audio attached, metrics queued
value:
conversation:
name: conversations/gk3jK9mPq2xRt5vW8yZaBc
conversation_id: gk3jK9mPq2xRt5vW8yZaBc
status: IN_PROGRESS
create_time: '2025-11-03T14:32:30Z'
external_conversation_id: external-call-7x8z9a
occurred_at: '2025-11-03T14:32:00Z'
has_audio: true
agent_id: null
persona_id: null
metadata:
campaign: q4-support
'400':
$ref: '#/components/responses/InvalidArgument'
'401':
$ref: '#/components/responses/Unauthenticated'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: Audio is already attached to this conversation
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error:
code: ALREADY_EXISTS
message: Conversation 'gk3jK9mPq2xRt5vW8yZaBc' already has audio attached. Overwriting audio is not supported.
details:
- field: audio
description: Audio already attached
'500':
$ref: '#/components/responses/InternalError'
/conversations/{conversation_id}/metrics:
get:
tags:
- Conversations
summary: List conversation metrics
description: 'List all metrics computed for a specific conversation.
'
operationId: listConversationMetrics
parameters:
- name: conversation_id
in: path
description: Unique conversation identifier
required: true
schema:
type: string
minLength: 22
maxLength: 26
example: gk3jK9mPq2xRt5vW8yZaBc
- name: filter
in: query
description: 'Filter expression syntax.
Values may be unquoted or double-quoted. Values containing spaces must be quoted.
**Supported fields:**
- `metric_name` (string): Filter by metric name (e.g., `metric_name=latency`)
- `status` (string): Filter by status (e.g., `status=COMPLETED`)
- `output_type` (string): Filter by type (e.g., `output_type=float`)
**Examples:**
- `filter=status=COMPLETED`
- `filter=metric_name=latency AND status=COMPLETED`
- `filter=output_type=float`
'
required: false
schema:
type: string
example: status=COMPLETED
- name: page_size
in: query
description: Maximum number of metrics to return (1-1000)
required: false
schema:
type: integer
minimum: 1
maximum: 1000
default: 50
example: 50
- name: page_token
in: query
description: Pagination token from previous response (for fetching next page)
required: false
schema:
type: string
example: eyJvZmZzZXQiOiA1MH0=
- name: order_by
in: query
description: 'Field to order results by.
**Supported fields:**
- `metric_name` (default): Sort by metric name alphabetically
- `create_time`: Sort by creation time
- `start_time`: Sort by computation start time
- `end_time`: Sort by computation end time
- `value`: Sort by metric value (float types only)
**Prefix with `-` for descending order** (e.g., `-create_time`)
'
required: false
schema:
type: string
default: metric_name
example: metric_name
responses:
'200':
description: List of metrics
content:
application/json:
schema:
$ref: '#/components/schemas/ListConversationMetricsResponse'
examples:
success:
summary: List of conversation metrics
value:
metrics:
- metric_output_id: 01JCQR8Z9PQSTNVWXY12345678
metric_id: 29BlkepvvX19ebbLDB0y6Q
value: 2.35
status: COMPLETED
- metric_output_id: 01JCQR9A1BRSUWVXYZ12345678
metric_id: mymKvEg6ZA65srXbTX5wSM
value: positive
status: COMPLETED
- metric_output_id: 01JCQR9B2CRTUVWXYZ12345678
metric_id: fstokU4ev5UmT8sUBexiwV
value: resolved
status: COMPLETED
'404':
$ref: '#/components/responses/NotFound'
'400':
$ref: '#/components/responses/InvalidArgument'
'401':
$ref: '#/components/responses/Unauthenticated'
'500':
$ref: '#/components/responses/InternalError'
/conversations/{conversation_id}/metrics/{metric_output_id}:
get:
tags:
- Conversations
summary: Get conversation metric output(s)
description: "Retrieve metric output(s) for a conversation by ID. The path segment\naccepts two ID types and returns different response shapes:\n\n- **26-char MetricOutput ULID** (e.g. `01JCQR8Z9PQSTNVWXY12345678`):\n returns a single metric output as `{ \"metric\": {...} }`.\n- **22-char Metric definition ID** (e.g. `29BlkepvvX19ebbLDB0y6Q`):\n returns every output for that metric on the conversation as\n `{ \"metric_outputs\": [...] }`.\n\nClients should branch on the
# --- truncated at 32 KB (71 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/coval/refs/heads/main/openapi/coval-conversations-api-openapi.yml