OmniStream Docs
  • Dokumentasi
  • Developer
  • API Reference
Information
Auth
    Login with email and passwordpostRequest a password-reset code (agent)postSet a new password with a reset code (agent)postGet current agent profilegetLogout (clears cookie)postAdvertise available SSO login methodsgetBegin Google SSO logingetGoogle SSO callback (OIDC redirect URI)getDiscover company SSO availability for an emailpostBegin company SSO login (ticket from /discover)getCompany SSO callback (OIDC redirect URI)getBegin a passkey (WebAuthn) login ceremonypostComplete a passkey loginpostBegin passkey registration for the current agentpostComplete passkey registrationpostList the current agent's passkeysgetDelete one of the current agent's passkeysdeleteList company SSO providersgetCreate a company SSO providerpostUpdate a company SSO providerputDelete a company SSO providerdeleteIssue a fresh JWT for the current sessiongetRegister a new tenant organizationpost
Conversations
    List conversationsgetGet a single conversationgetAssign or unassign an agentpatchAdd an assignee (human agent or AI agent) to a conversationpostRemove an assignee (human agent or AI agent) from a conversationdeleteUpdate conversation statuspatchMark conversation as readpostExpire stale conversationspostUpdate conversation tagspatchTakeover a conversationpostBulk conversation actionspost
Messages
    List messages in a conversationgetSend an outbound messagepostSend a WhatsApp template message in one callpostSearch messages across conversationsget
Contacts
    List contactsgetImport contacts from a CSV filepostPreview a CSV before importing (wizard step 1)postImport contacts from CSV with explicit column mapping (wizard step 2)postGet a contact by IDgetUpdate a contactpatchList conversations for a contactget
Outgoing Webhooks
    List outgoing webhooksgetCreate an outgoing webhookpostList available webhook event typesgetAggregated delivery statisticsgetBulk-replay deliveries by idpostReplay all dead-lettered deliveriespostReplay a single deliverypostDelete an outgoing webhookdeleteUpdate an outgoing webhookpatchList deliveries for a webhookgetSend a test event to the webhookpostStart a signing-secret rotationpostComplete a pending secret rotationpostCancel a pending secret rotationpost
WA Templates
    List WhatsApp message templatesgetCreate a WhatsApp message templatepostSync templates from MetapostGet a WhatsApp template by IDgetEdit a template (status-aware; re-submits to Meta)putDelete a WhatsApp template (Meta-first)deleteBulk-send an approved template to a list of contactspostUpdate template header media URLpatch
Schemas
OmniStream CRM API
OmniStream CRM API

Conversations

Endpoint

Conversation management


List conversations

GET
https://api-chat.misindo.id
/api/conversations

Agents see only their own and unassigned conversations. Supervisors and admins see all conversations.

List conversations › query Parameters

status
​string · enum

The complete set of conversation states. Mirrors ConversationStatus in crates/omni-common/src/models/conversation.rs. pending and expired were removed by migrations/20260326000039_simplify_conversation_statuses.sql (pending → open, expired → resolved) and snoozed was added by migrations/20260519000012_conversation_snooze.sql. Passing a removed value as a status filter is rejected with 400 before the handler runs, because the query struct deserializes straight into this enum. A snoozed conversation is hidden from the inbox until snoozed_until passes, at which point it reopens automatically.

Enum values:
open
snoozed
resolved
assigned_agent_id
​string · uuid
page
​integer · min: 1
Default: 1
per_page
​integer · min: 1 · max: 100
Default: 20

List conversations › Responses

200

List of conversations with contact info

​object[]
id
​string · uuid · required
contact_id
​string · uuid · required
status
​string · enum · required

The complete set of conversation states. Mirrors ConversationStatus in crates/omni-common/src/models/conversation.rs. pending and expired were removed by migrations/20260326000039_simplify_conversation_statuses.sql (pending → open, expired → resolved) and snoozed was added by migrations/20260519000012_conversation_snooze.sql. Passing a removed value as a status filter is rejected with 400 before the handler runs, because the query struct deserializes straight into this enum. A snoozed conversation is hidden from the inbox until snoozed_until passes, at which point it reopens automatically.

Enum values:
open
snoozed
resolved
last_message_at
​string · date-time · required
unread_count
​integer · required
created_at
​string · date-time · required
updated_at
​string · date-time · required
contact_channel
​string · required

whatsapp, instagram, or email

assigned_agent_id
​string · uuid
assigned_agent_name
​string

Full name of the assigned agent (null when unassigned)

contact_name
​string
contact_phone
​string
​object[]

All co-assignees (human agents and/or AI agent) attached to this conversation via the conversation_assignees junction, ordered by assignment time. assigned_agent_id remains the denormalized primary.

GET/api/conversations
curl --request GET \ --url https://api-chat.misindo.id/api/conversations
shell
Example Responses
[ { "id": "00000000-0000-0000-0000-000000000000", "contact_id": "00000000-0000-0000-0000-000000000000", "assigned_agent_id": "00000000-0000-0000-0000-000000000000", "assigned_agent_name": "assigned_agent_name", "status": "open", "last_message_at": "2024-08-25T15:00:00Z", "unread_count": 0, "created_at": "2024-08-25T15:00:00Z", "updated_at": "2024-08-25T15:00:00Z", "contact_name": "contact_name", "contact_phone": "contact_phone", "contact_channel": "contact_channel", "assignees": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "ai_agent_id": "00000000-0000-0000-0000-000000000000", "name": "name", "kind": "human" } ] } ]
json
application/json

Get a single conversation

GET
https://api-chat.misindo.id
/api/conversations/{id}

Get a single conversation › path Parameters

id
​string · uuid · required

Get a single conversation › Responses

Conversation details

id
​string · uuid · required
contact_id
​string · uuid · required
status
​string · enum · required

The complete set of conversation states. Mirrors ConversationStatus in crates/omni-common/src/models/conversation.rs. pending and expired were removed by migrations/20260326000039_simplify_conversation_statuses.sql (pending → open, expired → resolved) and snoozed was added by migrations/20260519000012_conversation_snooze.sql. Passing a removed value as a status filter is rejected with 400 before the handler runs, because the query struct deserializes straight into this enum. A snoozed conversation is hidden from the inbox until snoozed_until passes, at which point it reopens automatically.

Enum values:
open
snoozed
resolved
last_message_at
​string · date-time · required
unread_count
​integer · required
created_at
​string · date-time · required
updated_at
​string · date-time · required
contact_channel
​string · required

whatsapp, instagram, or email

assigned_agent_id
​string · uuid
assigned_agent_name
​string

Full name of the assigned agent (null when unassigned)

contact_name
​string
contact_phone
​string
​object[]

All co-assignees (human agents and/or AI agent) attached to this conversation via the conversation_assignees junction, ordered by assignment time. assigned_agent_id remains the denormalized primary.

GET/api/conversations/{id}
curl --request GET \ --url https://api-chat.misindo.id/api/conversations/:id
shell
Example Responses
{ "id": "00000000-0000-0000-0000-000000000000", "contact_id": "00000000-0000-0000-0000-000000000000", "assigned_agent_id": "00000000-0000-0000-0000-000000000000", "assigned_agent_name": "assigned_agent_name", "status": "open", "last_message_at": "2024-08-25T15:00:00Z", "unread_count": 0, "created_at": "2024-08-25T15:00:00Z", "updated_at": "2024-08-25T15:00:00Z", "contact_name": "contact_name", "contact_phone": "contact_phone", "contact_channel": "contact_channel", "assignees": [ { "agent_id": "00000000-0000-0000-0000-000000000000", "ai_agent_id": "00000000-0000-0000-0000-000000000000", "name": "name", "kind": "human" } ] }
json
application/json

Assign or unassign an agent

PATCH
https://api-chat.misindo.id
/api/conversations/{id}/assign

Supervisor or admin only. Set agent_id to null to unassign.

Assign or unassign an agent › path Parameters

id
​string · uuid · required

Assign or unassign an agent › Request Body

agent_id
​string · uuid

Set to null to unassign

Assign or unassign an agent › Responses

Agent assigned

message
​string
conversation_id
​string · uuid
assigned_agent_id
​string · uuid
PATCH/api/conversations/{id}/assign
curl --request PATCH \ --url https://api-chat.misindo.id/api/conversations/:id/assign \ --header 'Content-Type: application/json' \ --data ' { "agent_id": "00000000-0000-0000-0000-000000000000" } '
shell
Example Request Body
{ "agent_id": "00000000-0000-0000-0000-000000000000" }
json
Example Responses
{ "message": "message", "conversation_id": "00000000-0000-0000-0000-000000000000", "assigned_agent_id": "00000000-0000-0000-0000-000000000000" }
json
application/json

Add an assignee (human agent or AI agent) to a conversation

POST
https://api-chat.misindo.id
/api/conversations/{id}/assignees

Adds a co-assignee to a conversation. A conversation may have multiple human assignees at once, tracked in the conversation_assignees junction table; the earliest human is kept as the denormalized primary (assigned_agent_id) for capacity routing and WebSocket targeting. Supervisors/admins may add any agent; regular agents may only add themselves. Exactly one of agent_id or ai_agent_id must be set.

Handing off to AI (ai_agent_id) is mutually exclusive with human assignees: it clears all human assignees, sets assigned_agent_id to null, marks the conversation ai_handled, and activates the AI conversation state. Adding a human agent while AI is active pauses AI (deactivates the AI state and unlinks the AI agent).

Add an assignee (human agent or AI agent) to a conversation › path Parameters

id
​string · uuid · required

Add an assignee (human agent or AI agent) to a conversation › Request Body

Exactly one of agent_id or ai_agent_id must be provided. Providing ai_agent_id hands the conversation off to AI and clears human assignees.
agent_id
​string · uuid

Human agent to add as co-assignee

ai_agent_id
​string · uuid

AI agent to hand the conversation off to

Add an assignee (human agent or AI agent) to a conversation › Responses

Assignee added

message
​string
POST/api/conversations/{id}/assignees
curl --request POST \ --url https://api-chat.misindo.id/api/conversations/:id/assignees \ --header 'Content-Type: application/json' \ --data ' { "agent_id": "00000000-0000-0000-0000-000000000000", "ai_agent_id": "00000000-0000-0000-0000-000000000000" } '
shell
Example Request Body
{ "agent_id": "00000000-0000-0000-0000-000000000000", "ai_agent_id": "00000000-0000-0000-0000-000000000000" }
json
Example Responses
{ "message": "message" }
json
application/json

Remove an assignee (human agent or AI agent) from a conversation

DELETE
https://api-chat.misindo.id
/api/conversations/{id}/assignees

Removes a co-assignee. Pass agent_id to remove a human assignee (the primary assigned_agent_id is then re-synced to the earliest remaining human, or null if none remain), or ai=true to hand AI off / deactivate the AI conversation state. Supervisors/admins may remove any agent; regular agents may only remove themselves. Exactly one selector is required.

Remove an assignee (human agent or AI agent) from a conversation › path Parameters

id
​string · uuid · required

Remove an assignee (human agent or AI agent) from a conversation › query Parameters

agent_id
​string · uuid

Human agent to remove. Mutually exclusive with ai.

ai
​boolean

Set true to remove/deactivate the AI assignee.

Remove an assignee (human agent or AI agent) from a conversation › Responses

Assignee removed

message
​string
DELETE/api/conversations/{id}/assignees
curl --request DELETE \ --url https://api-chat.misindo.id/api/conversations/:id/assignees
shell
Example Responses
{ "message": "message" }
json
application/json

Update conversation status

PATCH
https://api-chat.misindo.id
/api/conversations/{id}/status

Update conversation status › path Parameters

id
​string · uuid · required

Update conversation status › Request Body

status
​string · enum · required

The complete set of conversation states. Mirrors ConversationStatus in crates/omni-common/src/models/conversation.rs. pending and expired were removed by migrations/20260326000039_simplify_conversation_statuses.sql (pending → open, expired → resolved) and snoozed was added by migrations/20260519000012_conversation_snooze.sql. Passing a removed value as a status filter is rejected with 400 before the handler runs, because the query struct deserializes straight into this enum. A snoozed conversation is hidden from the inbox until snoozed_until passes, at which point it reopens automatically.

Enum values:
open
snoozed
resolved

Update conversation status › Responses

200

Status updated

message
​string
conversation_id
​string · uuid
status
​string
PATCH/api/conversations/{id}/status
curl --request PATCH \ --url https://api-chat.misindo.id/api/conversations/:id/status \ --header 'Content-Type: application/json' \ --data ' { "status": "open" } '
shell
Example Request Body
{ "status": "open" }
json
Example Responses
{ "message": "message", "conversation_id": "00000000-0000-0000-0000-000000000000", "status": "status" }
json
application/json

Mark conversation as read

POST
https://api-chat.misindo.id
/api/conversations/{id}/read

Resets the unread_count to 0.

Mark conversation as read › path Parameters

id
​string · uuid · required

Mark conversation as read › Responses

200

Marked as read

message
​string
conversation_id
​string · uuid
unread_count
​integer
POST/api/conversations/{id}/read
curl --request POST \ --url https://api-chat.misindo.id/api/conversations/:id/read
shell
Example Responses
{ "message": "message", "conversation_id": "00000000-0000-0000-0000-000000000000", "unread_count": 0 }
json
application/json

Expire stale conversations

POST
https://api-chat.misindo.id
/api/conversations/expire

Supervisor or admin only. Expires open conversations older than 24 hours.

Expire stale conversations › Responses

Conversations expired

message
​string
expired_count
​integer
POST/api/conversations/expire
curl --request POST \ --url https://api-chat.misindo.id/api/conversations/expire
shell
Example Responses
{ "message": "message", "expired_count": 0 }
json
application/json

Update conversation tags

PATCH
https://api-chat.misindo.id
/api/conversations/{id}/tags

Replaces the entire tags array on the conversation.

Update conversation tags › path Parameters

id
​string · uuid · required

Update conversation tags › Request Body

tags
​string[] · required

Update conversation tags › Responses

Tags updated

message
​string
conversation_id
​string · uuid
tags
​string[]
PATCH/api/conversations/{id}/tags
curl --request PATCH \ --url https://api-chat.misindo.id/api/conversations/:id/tags \ --header 'Content-Type: application/json' \ --data ' { "tags": [ "string" ] } '
shell
Example Request Body
{ "tags": [ "string" ] }
json
Example Responses
{ "message": "message", "conversation_id": "00000000-0000-0000-0000-000000000000", "tags": [ "string" ] }
json
application/json

Takeover a conversation

POST
https://api-chat.misindo.id
/api/conversations/{id}/takeover

Assigns the conversation to the requesting agent.

Takeover a conversation › path Parameters

id
​string · uuid · required

Takeover a conversation › Responses

200

Conversation taken over

message
​string
conversation_id
​string · uuid
assigned_agent_id
​string · uuid
POST/api/conversations/{id}/takeover
curl --request POST \ --url https://api-chat.misindo.id/api/conversations/:id/takeover
shell
Example Responses
{ "message": "message", "conversation_id": "00000000-0000-0000-0000-000000000000", "assigned_agent_id": "00000000-0000-0000-0000-000000000000" }
json
application/json

Bulk conversation actions

POST
https://api-chat.misindo.id
/api/conversations/bulk

Apply bulk actions to multiple conversations: resolve, reopen, assign, add/remove tags. Max 100 conversations per request.

Bulk conversation actions › Request Body

conversation_ids
​string[] · minItems: 1 · maxItems: 100 · required
​required

Bulk conversation actions › Responses

Bulk action applied

message
​string
affected_count
​integer
POST/api/conversations/bulk
curl --request POST \ --url https://api-chat.misindo.id/api/conversations/bulk \ --header 'Content-Type: application/json' \ --data ' { "conversation_ids": [ "00000000-0000-0000-0000-000000000000" ], "action": { "type": "resolve" } } '
shell
Example Request Body
{ "conversation_ids": [ "00000000-0000-0000-0000-000000000000" ], "action": { "type": "resolve" } }
json
Example Responses
{ "message": "message", "affected_count": 0 }
json
application/json

AuthMessages