Conversations
Open conversations, exchange messages with the agent, hand off to a human and reply from your own system.
Use the conversations API to build the chat with your own interface. Nevox takes care of the answers, the agent's rules and the history.
Lifecycle
| Status | What it means |
|---|---|
active | The agent is replying |
handoff | The agent asked for a human and the conversation is waiting for someone on your team |
human | Someone on your team took over. The agent doesn't reply until the conversation is handed back to it. |
closed | Closed |
Conversations opened through the API use the api channel. WhatsApp, website chat, SMS and voice conversations also show up here: you can read them, hand them off to a human, hand them back, close them and reply as staff (the reply goes out through the original channel), but customer messages in them arrive only through that channel. Email inbox conversations don't show up in the API yet.
Open a conversation
POST /v1/conversations · scope conversations:write
curl https://api.nevox.ai/v1/conversations \
-H "Authorization: Bearer $NEVOX_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6c1f0e2a-1b8e-4f0e-9d0a-1d2c3b4a5e6f" \
-d '{
"agent_id": "agt_8f2k1x",
"contact": { "external_id": "patient_1042", "name": "Mary Smith" },
"channel": "api",
"metadata": { "screen": "my-appointments" }
}'{
"id": "conv_7mk2p9",
"agent_id": "agt_8f2k1x",
"contact_id": "ctc_4hq81",
"channel": "api",
"status": "active",
"metadata": { "screen": "my-appointments" },
"created_at": "2026-11-03T14:30:00Z",
"updated_at": "2026-11-03T14:30:00Z"
}If the contact doesn't exist, it is created with the given external_id. The contact fields follow the same format as contacts.
Send a user message
POST /v1/conversations/{id}/messages · scope conversations:write
curl https://api.nevox.ai/v1/conversations/conv_7mk2p9/messages \
-H "Authorization: Bearer $NEVOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "content": "I want to reschedule my Thursday appointment" }'{
"user_message": {
"id": "msg_a1",
"role": "user",
"content": "I want to reschedule my Thursday appointment",
"created_at": "2026-11-03T14:30:05Z"
},
"agent_message": {
"id": "msg_a2",
"role": "agent",
"content": "Of course, Mary. I have these openings with Dr. Lee: Friday at 10 AM or Monday at 3 PM. Which do you prefer?",
"actions_called": [
{ "name": "available_slots", "status": "succeeded" }
],
"created_at": "2026-11-03T14:30:07Z"
},
"conversation_status": "active"
}When the conversation is in handoff or human, the agent doesn't reply: agent_message comes back as null. The actions_called field lists the actions the agent called to write the reply, with the status of each one (succeeded, failed, timeout, refused or confirm, when it asked for confirmation).
API conversations count toward the plan's conversation allowance (a conversation counts in the month the agent replies). Once the allowance runs out, a message in a new conversation gets 429 monthly_quota_exceeded. Conversations from a test key don't count.
Real-time reply (streaming)
Send "stream": true to receive the reply bit by bit, as Server-Sent Events:
curl -N https://api.nevox.ai/v1/conversations/conv_7mk2p9/messages \
-H "Authorization: Bearer $NEVOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "content": "What times do you have tomorrow?", "stream": true }'event: message.started
data: {"id":"msg_a4"}
event: action.called
data: {"name":"available_slots","status":"succeeded"}
event: message.delta
data: {"delta":"Tomorrow I have "}
event: message.delta
data: {"delta":"10 AM and 2 PM open."}
event: message.completed
data: {"id":"msg_a4","content":"Tomorrow I have 10 AM and 2 PM open.","conversation_status":"active"}Other possible events: handoff (the agent handed off to a human) and error. The text arrives in chunks, one sentence at a time.
List and read
| Endpoint | Description |
|---|---|
GET /v1/conversations | Lists conversations. Filters: agent_id, contact_external_id, status, channel, created_after, created_before |
GET /v1/conversations/{id} | A single conversation, with the AI-generated summary |
GET /v1/conversations/{id}/messages | Messages, oldest to newest |
Scope conversations:read. Lists use cursor pagination.
Hand off to a human
The agent hands off to a human on its own when there's a complaint, a refund, a special request or a topic you flagged in the dashboard. You can also force it:
POST /v1/conversations/{id}/handoff
{ "reason": "Patient asked to speak with the front desk" }The conversation moves to handoff and Nevox sends the conversation.handoff webhook, with the reason. The conversation summary (summary) is generated by the AI right after and shows up in GET /v1/conversations/{id}.
When the agent is the one handing off, the reason comes in handoff_reason: complaint, refund_request, special_request, forbidden_topic, user_asked_human, low_confidence or action_failed. Through the endpoint above, manual.
Reply as a staff member
When someone on your team replies from your system, send the message with role: "staff":
curl https://api.nevox.ai/v1/conversations/conv_7mk2p9/messages \
-H "Authorization: Bearer $NEVOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "staff",
"content": "Hi Mary, this is Carla from the front desk. I already took care of the refund.",
"author": { "id": "emp_33", "name": "Carla" }
}'The first staff message changes the status to human. If the conversation came from WhatsApp or SMS, Nevox delivers the reply on the original channel (with a production key; a test key gets 409 test_key_channel). In the website chat, the visitor sees the reply in the chat.
Hand back to the agent
POST /v1/conversations/{id}/resume: goes back to active, and the agent resumes the conversation.
Close
POST /v1/conversations/{id}/close
{ "resolution": "resolved" }resolution values: resolved, unresolved, spam. Closing sends the conversation.closed webhook. API conversations with no messages for 24 hours are closed automatically with resolution: "inactive". A closed channel conversation becomes active again when the customer sends a new message.
What the agent never does
The rules configured in the dashboard also apply to the API. The agent:
- doesn't make up prices, times or information;
- doesn't ask for card numbers, passwords or documents;
- doesn't give medical, legal or financial advice;
- doesn't talk about topics you've forbidden.