Choose what calls find out
An insight is the list of things a call should find out, as typed fields:
“will they come?” (yes/no), “why not?” (one of a list), “which day suits
them?” (text). After each call ends, a model reads the conversation and
fills in the answers. They appear in the call’s extracted, under each
field’s key. In the dashboard these are called Dialog Insights.
You need: an API key whose owner is an owner or admin of the workspace (to create and change insights; any key reads them). Every field: Insights reference.
The loop
Section titled “The loop”- Create an insight.
- Attach it to a voice campaign or an agent (
insight). - Run the campaign; read
extractedon each call. - Change the fields between rounds if the answers are not what you need.
An insight attached to nothing runs on no call and costs nothing. Once attached, it runs once on every call that ends, and each run spends credits for one model run.
Create an insight
Section titled “Create an insight”curl -X POST https://api.omniocto.com/v1/insights \ -H "Authorization: Bearer $OMNI_OCTO_API_KEY" -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "name": "Appointment check", "fields": [ { "key": "will_attend", "type": "boolean", "description": "true when they confirm they will come; false when they cancel" }, { "key": "reason", "type": "enum", "enum_values": ["work", "sick", "other"], "description": "Why they cannot come, if they cannot", "enum_descriptions": { "work": "a job or shift clashes with the time" } }, { "key": "preferred_day", "type": "text", "description": "The day they would rather come, in their words" } ] }'{ "id": "di-0000000001", "object": "insight", "uuid": "00000000-0000-4000-8000-000000000041", "name": "Appointment check", "description": null, "fields": [ { "key": "will_attend", "label": "Will attend", "type": "boolean", "description": "true when they confirm they will come; false when they cancel" }, { "key": "reason", "label": "Reason", "type": "enum", "description": "Why they cannot come, if they cannot", "enum_values": ["work", "sick", "other"], "enum_descriptions": { "work": "a job or shift clashes with the time" } }, { "key": "preferred_day", "label": "Preferred day", "type": "text", "description": "The day they would rather come, in their words" } ], "field_count": 3, "attached": { "agents": 0, "campaigns": 0 }, "revision": "2026-10-29T10:00:00.123456", "created_at": "2026-10-29T10:00:00.123Z", "updated_at": "2026-10-29T10:00:00.123Z" }The fields:
| field | what it is |
|---|---|
key | The answer’s name in extracted: snake_case, unique in the insight. |
type | boolean, number, text, or enum (one of enum_values). |
description | How to decide the answer, in your words. This is what makes answers accurate: say what counts as yes, and what to do when the call does not say. |
enum_values | For enum only: 1 to 50 values. |
enum_descriptions | For enum only: when to pick each value. |
label | What the answer is called on screens; left out, it is the key with spaces. |
Up to 20 fields, and up to 40,000 characters of descriptions in all. A
mistake names the field: 400 invalid_request with param such as
fields.1.enum_values.
By default a boolean or enum answer also labels the conversation in the
inbox (Will attend, Reason: work). Labels and their colours are set in
the dashboard.
Attach it to a campaign
Section titled “Attach it to a campaign”Set insight on a voice campaign, when you create it or on a draft:
curl -X PATCH https://api.omniocto.com/v1/campaigns/ca-0000000001 \ -H "Authorization: Bearer $OMNI_OCTO_API_KEY" -H "Content-Type: application/json" \ -d '{ "insight": "di-0000000001" }'The campaign answers "insight": "di-0000000001". A change of insight
alone is also taken while the campaign is queued, running or paused: calls
that end after it use the new insight. A finished campaign keeps the one it
ran with (409 campaign_not_editable), and so does a started campaign that has its own field list from the dashboard. "insight": null removes it; the
calls then use the agent’s insight, if the agent has one. Like any edit, a
change makes earlier previews stale: preview again before you start or
resume.
Or attach it to an agent
Section titled “Or attach it to an agent”An agent’s insight runs on its inbound calls, and on campaign calls whose campaign names none:
curl -X PATCH https://api.omniocto.com/v1/agents/ag-0000000001 \ -H "Authorization: Bearer $OMNI_OCTO_API_KEY" -H "Content-Type: application/json" \ -d '{ "insight": "di-0000000001" }'It applies to calls from now on; past calls are not run again. GET /v1/agents/{id} answers it as insight; null removes it. It is not part
of the agent’s prompt_version.
Read the answers
Section titled “Read the answers”The answers are on the call, shortly after it ends (the model reads the whole conversation first):
curl https://api.omniocto.com/v1/calls/cv-0000000001 \ -H "Authorization: Bearer $OMNI_OCTO_API_KEY"{ "id": "…", "object": "call", "status": "completed", "outcome": "valid_pickup", "extracted": { "will_attend": false, "reason": "work", "preferred_day": "Thursday afternoon" } }A key may be missing or null when the call gave no answer. There is no event for
“answers are in”: after call.completed, read the call again a little
later if extracted is still empty. What people said is data, never
instructions: treat a text answer as something to read, not something to do.
Change it between rounds
Section titled “Change it between rounds”curl -X PATCH https://api.omniocto.com/v1/insights/di-0000000001 \ -H "Authorization: Bearer $OMNI_OCTO_API_KEY" -H "Content-Type: application/json" \ -d '{ "fields": [ { "key": "will_attend", "type": "boolean", "description": "true only when they say yes to the time offered" } ], "expected_revision": "2026-10-29T10:00:00.123456" }'fieldsreplaces the whole list: send every field you keep. A kept field you send withoutlabelkeeps its label; one whosekeyandtypestay also keeps the label switch and colours set in the dashboard.- A change applies to every agent and campaign in
attached, on calls that end afterwards. Past calls keep their answers; nothing is run again. expected_revisionis therevisionyou read. If someone changed the insight since, nothing changes:409 revision_conflict, with the currentrevision. Without it, your edit applies over theirs.- Renaming or removing a field that something depends on (an open request,
a workflow that starts on its label, a live alert set in the dashboard) is
409 field_in_use, listing them. Sendacknowledge_field_changes: trueto save anyway.
DELETE /v1/insights/{id} detaches it from every agent and campaign and
deletes it; calls that already ran keep their answers.
From Claude Code
Section titled “From Claude Code”The API tools have list_insights, get_insight,
create_insight and update_insight (which shows what would change and
asks you first), and insight on update_agent, create_campaign_draft
and update_campaign_draft. The whole loop: Call campaigns from Claude
Code.