Conversations
Threads between a contact and your team on one channel — routing, assignment, lifecycle stage and closing.
/conversationsAvailableGET/conversations/{conversation_id}AvailablePOST/conversations/{conversation_id}/assignAvailablePOST/conversations/{conversation_id}/closeAvailablePOST/conversations/{conversation_id}/reopenAvailablePUT/conversations/{conversation_id}/stageAvailablePOST/conversations/{conversation_id}/handoverBetaPOST/conversations/{conversation_id}/snoozeComing soonPOST/conversations/{conversation_id}/notesAvailableList conversations
Section titled “List conversations”/v1/conversationsAvailableMost recent activity first.
Query parameters
| Field | Type | Description |
|---|---|---|
status |
“open” | “closed” | |
assignee_id |
string | Only conversations assigned to this user. Use none for unassigned. |
channel_type |
“whatsapp” | “instagram” | “messenger” | “sms” | “email” | “webchat” | |
stage_id |
string | |
tag |
string | |
contact_id |
string | |
q |
string | Search contact name |
limit |
integer | |
cursor |
string | The next_cursor from the previous page. |
curl "https://api.waasl.io/v1/conversations" \ -H "Authorization: Bearer $WAASL_API_KEY"const res = await fetch("https://api.waasl.io/v1/conversations", { headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}` },});if (!res.ok) throw new Error((await res.json()).code);const data = await res.json();import osimport requests
r = requests.get( "https://api.waasl.io/v1/conversations", headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"},)r.raise_for_status()print(r.json())Response 200 — A page of conversations
{ "data": [ { "id": "cv_3PzA91", "contact_id": "string", "channel_id": "string", "channel_type": "whatsapp", "status": "open", "stage_id": "string", "assignee_id": "string", "team_id": "string", "controller": "human", "unread_count": 0, "tags": [ "string" ], "last_customer_at": "2026-10-01T08:15:00Z", "last_message_at": "2026-10-01T08:15:00Z", "window_expires_at": "2026-10-01T08:15:00Z", "contact_name": "string", "contact_handle": "string" } ], "next_cursor": "MjAyNi0xMC0wMVQwODoxNTowMC4wMDBafGN2XzNQekE5MQ", "has_more": true}Retrieve a conversation
Section titled “Retrieve a conversation”/v1/conversations/{conversation_id}AvailablePath parameters
| Field | Type | Description |
|---|---|---|
conversation_id required |
string |
curl "https://api.waasl.io/v1/conversations/cv_3PzA91" \ -H "Authorization: Bearer $WAASL_API_KEY"const res = await fetch("https://api.waasl.io/v1/conversations/cv_3PzA91", { headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}` },});if (!res.ok) throw new Error((await res.json()).code);const data = await res.json();import osimport requests
r = requests.get( "https://api.waasl.io/v1/conversations/cv_3PzA91", headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"},)r.raise_for_status()print(r.json())Response 200 — The conversation
{ "id": "cv_3PzA91", "contact_id": "string", "channel_id": "string", "channel_type": "whatsapp", "status": "open", "stage_id": "string", "assignee_id": "string", "team_id": "string", "controller": "human", "unread_count": 0, "tags": [ "string" ], "last_customer_at": "2026-10-01T08:15:00Z", "last_message_at": "2026-10-01T08:15:00Z", "window_expires_at": "2026-10-01T08:15:00Z", "contact_name": "string", "contact_handle": "string"}Errors: 404 Not found in this workspace
Assign a conversation
Section titled “Assign a conversation”/v1/conversations/{conversation_id}/assignAvailableAssign to a user, or pass null to unassign. Assigning to a team is coming soon.
Path parameters
| Field | Type | Description |
|---|---|---|
conversation_id required |
string |
Request body
| Field | Type | Description |
|---|---|---|
assignee_id |
string | null | |
team_id |
string | null | Coming soon. |
curl -X POST "https://api.waasl.io/v1/conversations/cv_3PzA91/assign" \ -H "Authorization: Bearer $WAASL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "assignee_id": "usr_4hT9qP", "team_id": "string"}'const res = await fetch("https://api.waasl.io/v1/conversations/cv_3PzA91/assign", { method: "POST", headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "assignee_id": "usr_4hT9qP", "team_id": "string" }),});if (!res.ok) throw new Error((await res.json()).code);const data = await res.json();import osimport requests
r = requests.post( "https://api.waasl.io/v1/conversations/cv_3PzA91/assign", headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"}, json={ "assignee_id": "usr_4hT9qP", "team_id": "string" },)r.raise_for_status()print(r.json())Response 200 — Updated conversation
{ "id": "cv_3PzA91", "contact_id": "string", "channel_id": "string", "channel_type": "whatsapp", "status": "open", "stage_id": "string", "assignee_id": "string", "team_id": "string", "controller": "human", "unread_count": 0, "tags": [ "string" ], "last_customer_at": "2026-10-01T08:15:00Z", "last_message_at": "2026-10-01T08:15:00Z", "window_expires_at": "2026-10-01T08:15:00Z", "contact_name": "string", "contact_handle": "string"}Close a conversation
Section titled “Close a conversation”/v1/conversations/{conversation_id}/closeAvailablePath parameters
| Field | Type | Description |
|---|---|---|
conversation_id required |
string |
Request body
| Field | Type | Description |
|---|---|---|
category_id |
string | Closing reason. |
summary |
string | |
send_csat |
boolean | Send a satisfaction survey (coming soon). |
curl -X POST "https://api.waasl.io/v1/conversations/cv_3PzA91/close" \ -H "Authorization: Bearer $WAASL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "category_id": "resolved", "summary": "Plan renewed for 30 days"}'const res = await fetch("https://api.waasl.io/v1/conversations/cv_3PzA91/close", { method: "POST", headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "category_id": "resolved", "summary": "Plan renewed for 30 days" }),});if (!res.ok) throw new Error((await res.json()).code);const data = await res.json();import osimport requests
r = requests.post( "https://api.waasl.io/v1/conversations/cv_3PzA91/close", headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"}, json={ "category_id": "resolved", "summary": "Plan renewed for 30 days" },)r.raise_for_status()print(r.json())Response 200 — Closed conversation
{ "id": "cv_3PzA91", "contact_id": "string", "channel_id": "string", "channel_type": "whatsapp", "status": "open", "stage_id": "string", "assignee_id": "string", "team_id": "string", "controller": "human", "unread_count": 0, "tags": [ "string" ], "last_customer_at": "2026-10-01T08:15:00Z", "last_message_at": "2026-10-01T08:15:00Z", "window_expires_at": "2026-10-01T08:15:00Z", "contact_name": "string", "contact_handle": "string"}Reopen a conversation
Section titled “Reopen a conversation”/v1/conversations/{conversation_id}/reopenAvailablePath parameters
| Field | Type | Description |
|---|---|---|
conversation_id required |
string |
curl -X POST "https://api.waasl.io/v1/conversations/cv_3PzA91/reopen" \ -H "Authorization: Bearer $WAASL_API_KEY"const res = await fetch("https://api.waasl.io/v1/conversations/cv_3PzA91/reopen", { method: "POST", headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}` },});if (!res.ok) throw new Error((await res.json()).code);const data = await res.json();import osimport requests
r = requests.post( "https://api.waasl.io/v1/conversations/cv_3PzA91/reopen", headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"},)r.raise_for_status()print(r.json())Response 200 — Reopened conversation
{ "id": "cv_3PzA91", "contact_id": "string", "channel_id": "string", "channel_type": "whatsapp", "status": "open", "stage_id": "string", "assignee_id": "string", "team_id": "string", "controller": "human", "unread_count": 0, "tags": [ "string" ], "last_customer_at": "2026-10-01T08:15:00Z", "last_message_at": "2026-10-01T08:15:00Z", "window_expires_at": "2026-10-01T08:15:00Z", "contact_name": "string", "contact_handle": "string"}Set the lifecycle stage
Section titled “Set the lifecycle stage”/v1/conversations/{conversation_id}/stageAvailablePath parameters
| Field | Type | Description |
|---|---|---|
conversation_id required |
string |
Request body
| Field | Type | Description |
|---|---|---|
stage_id |
string | null |
curl -X PUT "https://api.waasl.io/v1/conversations/cv_3PzA91/stage" \ -H "Authorization: Bearer $WAASL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "stage_id": "payment"}'const res = await fetch("https://api.waasl.io/v1/conversations/cv_3PzA91/stage", { method: "PUT", headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "stage_id": "payment" }),});if (!res.ok) throw new Error((await res.json()).code);const data = await res.json();import osimport requests
r = requests.put( "https://api.waasl.io/v1/conversations/cv_3PzA91/stage", headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"}, json={ "stage_id": "payment" },)r.raise_for_status()print(r.json())Response 200 — Updated conversation
{ "id": "cv_3PzA91", "contact_id": "string", "channel_id": "string", "channel_type": "whatsapp", "status": "open", "stage_id": "string", "assignee_id": "string", "team_id": "string", "controller": "human", "unread_count": 0, "tags": [ "string" ], "last_customer_at": "2026-10-01T08:15:00Z", "last_message_at": "2026-10-01T08:15:00Z", "window_expires_at": "2026-10-01T08:15:00Z", "contact_name": "string", "contact_handle": "string"}Hand over between bot and human
Section titled “Hand over between bot and human”/v1/conversations/{conversation_id}/handoverBetato: human takes the conversation away from an AI agent or workflow so agents can
reply; to: bot gives it back. While a bot controls a conversation, sending as a user
fails with bot_in_control.
Path parameters
| Field | Type | Description |
|---|---|---|
conversation_id required |
string |
Request body
| Field | Type | Description |
|---|---|---|
to required |
“human” | “bot” | |
ai_agent_id |
string | Which AI agent, when to is bot. |
curl -X POST "https://api.waasl.io/v1/conversations/cv_3PzA91/handover" \ -H "Authorization: Bearer $WAASL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": "human", "ai_agent_id": "string"}'const res = await fetch("https://api.waasl.io/v1/conversations/cv_3PzA91/handover", { method: "POST", headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "to": "human", "ai_agent_id": "string" }),});if (!res.ok) throw new Error((await res.json()).code);const data = await res.json();import osimport requests
r = requests.post( "https://api.waasl.io/v1/conversations/cv_3PzA91/handover", headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"}, json={ "to": "human", "ai_agent_id": "string" },)r.raise_for_status()print(r.json())Response 200 — Updated conversation
{ "id": "cv_3PzA91", "contact_id": "string", "channel_id": "string", "channel_type": "whatsapp", "status": "open", "stage_id": "string", "assignee_id": "string", "team_id": "string", "controller": "human", "unread_count": 0, "tags": [ "string" ], "last_customer_at": "2026-10-01T08:15:00Z", "last_message_at": "2026-10-01T08:15:00Z", "window_expires_at": "2026-10-01T08:15:00Z", "contact_name": "string", "contact_handle": "string"}Snooze a conversation
Section titled “Snooze a conversation”/v1/conversations/{conversation_id}/snoozeComing soonHides the conversation until until, or until the contact writes again.
Path parameters
| Field | Type | Description |
|---|---|---|
conversation_id required |
string |
Request body
| Field | Type | Description |
|---|---|---|
until required |
string (date-time) |
curl -X POST "https://api.waasl.io/v1/conversations/cv_3PzA91/snooze" \ -H "Authorization: Bearer $WAASL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "until": "2026-10-01T08:15:00Z"}'const res = await fetch("https://api.waasl.io/v1/conversations/cv_3PzA91/snooze", { method: "POST", headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "until": "2026-10-01T08:15:00Z" }),});if (!res.ok) throw new Error((await res.json()).code);const data = await res.json();import osimport requests
r = requests.post( "https://api.waasl.io/v1/conversations/cv_3PzA91/snooze", headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"}, json={ "until": "2026-10-01T08:15:00Z" },)r.raise_for_status()print(r.json())Response 200 — Snoozed conversation
{ "id": "cv_3PzA91", "contact_id": "string", "channel_id": "string", "channel_type": "whatsapp", "status": "open", "stage_id": "string", "assignee_id": "string", "team_id": "string", "controller": "human", "unread_count": 0, "tags": [ "string" ], "last_customer_at": "2026-10-01T08:15:00Z", "last_message_at": "2026-10-01T08:15:00Z", "window_expires_at": "2026-10-01T08:15:00Z", "contact_name": "string", "contact_handle": "string"}Add an internal note
Section titled “Add an internal note”/v1/conversations/{conversation_id}/notesAvailableNotes are visible to your team only and never reach the contact. @FirstName mentions notify that teammate.
Path parameters
| Field | Type | Description |
|---|---|---|
conversation_id required |
string |
Request body
| Field | Type | Description |
|---|---|---|
body required |
string |
curl -X POST "https://api.waasl.io/v1/conversations/cv_3PzA91/notes" \ -H "Authorization: Bearer $WAASL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "body": "Order #4821 refunded in Shopify — @Omar please confirm with the customer."}'const res = await fetch("https://api.waasl.io/v1/conversations/cv_3PzA91/notes", { method: "POST", headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "body": "Order #4821 refunded in Shopify — @Omar please confirm with the customer." }),});if (!res.ok) throw new Error((await res.json()).code);const data = await res.json();import osimport requests
r = requests.post( "https://api.waasl.io/v1/conversations/cv_3PzA91/notes", headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"}, json={ "body": "Order #4821 refunded in Shopify — @Omar please confirm with the customer." },)r.raise_for_status()print(r.json())Response 201 — The note (a message with kind: note)
{ "id": "msg_Vb3kQ9xP", "conversation_id": "string", "direction": "in", "kind": "text", "body": "string", "caption": "string", "media_id": "string", "filename": "string", "mime": "string", "size_bytes": 0, "reply_to_id": "string", "actor_kind": "contact", "actor_id": "string", "status": "queued", "error": "Re-engagement message (131047)", "created_at": "2026-10-01T08:15:00Z"}