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

Contacts

Endpoint

Contact management


List contacts

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

List contacts › query Parameters

search
​string

Search by name, phone, or email (case-insensitive)

tag
​string

Filter by tag (JSONB containment)

page
​integer · min: 1
Default: 1
per_page
​integer · min: 1 · max: 100
Default: 20

List contacts › Responses

200

Paginated contacts. Note this endpoint wraps its rows in a pagination envelope; it does NOT return a bare array.

Pagination envelope returned by `GET /api/contacts`. Mirrors the server's `PaginatedResponse<Contact>` — see `list_contacts` in `crates/api-gateway/src/routes/contacts.rs`.
​object[] · required
total
​integer · int64 · required

Matching contacts across all pages

page
​integer · int64 · required

1-based page number

per_page
​integer · int64 · required

Page size actually applied, clamped to 100

total_pages
​integer · int64 · required
GET/api/contacts
curl --request GET \ --url https://api-chat.misindo.id/api/contacts
shell
Example Responses
{ "data": [ { "id": "00000000-0000-0000-0000-000000000000", "phone_number": "phone_number", "name": "name", "email": "test@example.com", "channel_source": "channel_source", "tags": [ "string" ], "created_at": "2024-08-25T15:00:00Z", "updated_at": "2024-08-25T15:00:00Z" } ], "total": 0, "page": 0, "per_page": 0, "total_pages": 0 }
json
application/json

Import contacts from a CSV file

POST
https://api-chat.misindo.id
/api/contacts/import

Multipart upload (field name file). Recognized columns (English or Indonesian header names): name, phone_number, email, channel_source, tags. A headerless file is read in that column order. Phone numbers are normalized to bare digits; rows whose phone or email already exists are skipped. Maximum 5000 data rows per request. Requires contacts.manage permission.

Import contacts from a CSV file › Request Body

file
​string · binary · required

CSV file (UTF-8)

Import contacts from a CSV file › Responses

Import summary

imported
​integer

Newly created contacts

skipped
​integer

Rows whose phone/email already existed

errors
​string[]

Per-row failures, "Row N — reason"

POST/api/contacts/import
curl --request POST \ --url https://api-chat.misindo.id/api/contacts/import \ --header 'Content-Type: multipart/form-data' \ --form 'file=<binary>'
shell
Example Request Body
{ "file": "<binary>" }
json
Example Responses
{ "imported": 0, "skipped": 0, "errors": [ "string" ] }
json
application/json

Preview a CSV before importing (wizard step 1)

POST
https://api-chat.misindo.id
/api/contacts/import/preview

Parses raw CSV content and returns headers, up to 5 sample rows, and the total data-row count. Requires contacts.manage permission.

Preview a CSV before importing (wizard step 1) › Request Body

csv_content
​string · required

Raw CSV text

Preview a CSV before importing (wizard step 1) › Responses

200

Parsed preview

headers
​string[]
sample_rows
​array[]
total_rows
​integer
POST/api/contacts/import/preview
curl --request POST \ --url https://api-chat.misindo.id/api/contacts/import/preview \ --header 'Content-Type: application/json' \ --data ' { "csv_content": "csv_content" } '
shell
Example Request Body
{ "csv_content": "csv_content" }
json
Example Responses
{ "headers": [ "string" ], "sample_rows": [ [ "string" ] ], "total_rows": 0 }
json
application/json

Import contacts from CSV with explicit column mapping (wizard step 2)

POST
https://api-chat.misindo.id
/api/contacts/import/execute

column_mapping maps CSV header names to contact fields (name, phone_number, email, channel, tags). Rows with a phone number upsert on it; email-only rows match existing contacts case-insensitively by email. Enforces the tenant contact quota for newly created contacts. Maximum 5000 data rows per request. Requires contacts.manage permission.

Import contacts from CSV with explicit column mapping (wizard step 2) › Request Body

csv_content
​string · required

Raw CSV text (first row must be the header)

​object · required

CSV header name → contact field

file_name
​string

Original file name, echoed into import history

Import contacts from CSV with explicit column mapping (wizard step 2) › Responses

Import summary

imported
​integer

Newly created contacts

updated
​integer

Existing contacts refreshed by upsert

skipped
​integer

Rows without phone or email

errors
​string[]

Per-row failures, "Row N — reason"

POST/api/contacts/import/execute
curl --request POST \ --url https://api-chat.misindo.id/api/contacts/import/execute \ --header 'Content-Type: application/json' \ --data ' { "csv_content": "csv_content", "column_mapping": { "key": "string" }, "file_name": "file_name" } '
shell
Example Request Body
{ "csv_content": "csv_content", "column_mapping": { "key": "string" }, "file_name": "file_name" }
json
Example Responses
{ "imported": 0, "updated": 0, "skipped": 0, "errors": [ "string" ] }
json
application/json

Get a contact by ID

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

Get a contact by ID › path Parameters

id
​string · uuid · required

Get a contact by ID › Responses

Contact details

id
​string · uuid · required
channel_source
​string · required

whatsapp, instagram, or email

tags
​string[] · required

JSON array of tag strings

created_at
​string · date-time · required
updated_at
​string · date-time · required
phone_number
​string
name
​string
email
​string · email
GET/api/contacts/{id}
curl --request GET \ --url https://api-chat.misindo.id/api/contacts/:id
shell
Example Responses
{ "id": "00000000-0000-0000-0000-000000000000", "phone_number": "phone_number", "name": "name", "email": "test@example.com", "channel_source": "channel_source", "tags": [ "string" ], "created_at": "2024-08-25T15:00:00Z", "updated_at": "2024-08-25T15:00:00Z" }
json
application/json

Update a contact

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

Update name, email, or tags. At least one field required.

Update a contact › path Parameters

id
​string · uuid · required

Update a contact › Request Body

At least one field required.
name
​string
email
​string · email
tags
​string[]

Update a contact › Responses

200

Updated contact

id
​string · uuid · required
channel_source
​string · required

whatsapp, instagram, or email

tags
​string[] · required

JSON array of tag strings

created_at
​string · date-time · required
updated_at
​string · date-time · required
phone_number
​string
name
​string
email
​string · email
PATCH/api/contacts/{id}
curl --request PATCH \ --url https://api-chat.misindo.id/api/contacts/:id \ --header 'Content-Type: application/json' \ --data ' { "name": "name", "email": "test@example.com", "tags": [ "string" ] } '
shell
Example Request Body
{ "name": "name", "email": "test@example.com", "tags": [ "string" ] }
json
Example Responses
{ "id": "00000000-0000-0000-0000-000000000000", "phone_number": "phone_number", "name": "name", "email": "test@example.com", "channel_source": "channel_source", "tags": [ "string" ], "created_at": "2024-08-25T15:00:00Z", "updated_at": "2024-08-25T15:00:00Z" }
json
application/json

List conversations for a contact

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

List conversations for a contact › path Parameters

id
​string · uuid · required

List conversations for a contact › query Parameters

page
​integer
Default: 1
per_page
​integer
Default: 20

List conversations for a contact › Responses

200

Conversations for this contact

​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/contacts/{id}/conversations
curl --request GET \ --url https://api-chat.misindo.id/api/contacts/:id/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

MessagesOutgoing Webhooks