Chat Conversations API
Who can use this feature?
- You need the Pro or Plus plan to create and manage API keys.
- Full read and write access: read conversations and messages, send replies, resolve, assign, tag, and annotate.
Overview
The Chat Conversations API lets you work with your store's live chat from your own systems — mirror conversations into a helpdesk, build a custom inbox, run reporting, or reply from a tool your team already uses.
| Base URL | https://app.chatty.net |
| Auth header | X-Api-Key: <your key> |
| Format | JSON in, JSON out (Content-Type: application/json on writes) |
Every request is scoped to your store. You never send a store ID — your key resolves to one store, and every read and write is limited to it automatically.
Get your API key
Go to Settings > General > Manage keys, then click Create key.
| Rule | Detail |
|---|---|
| Format | sk_ followed by 32 hex characters |
| Title | Required, up to 50 characters — name it after the integration that will use it |
| Limit | Up to 5 active keys per store |
| Visibility | Shown once, at creation |
Copy your key right away. We only store a hash of it, so it can never be displayed again. Put it in your secrets manager immediately. If you lose it, delete the key and create a new one.
Create one key per integration so you can revoke them individually. Check that a key works:
curl -s "https://app.chatty.net/chat/conversations?limit=1" \
-H "X-Api-Key: sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"A wrong or revoked key returns 401 INVALID_API_KEY.
Rotating a key: create the new key, deploy it, then delete the old one. Deletion takes effect within about 5 minutes.
Response format
Every successful response carries a data key. Paginated endpoints add paging, and a few reads add meta.
{
"data": [ "..." ],
"paging": { "nextCursor": "eyJ...", "hasMore": true },
"meta": { "source": "postgresql" }
}data— the resource, or an array of resources on list endpoints. Always present.paging— on the paginated endpoints only: conversations list, related, customer conversations, and messages list. PassnextCursorback as thecursorquery parameter to fetch the next page.nextCursor: nullmeans you reached the last page. Cursors are opaque — don't parse them.meta.source— informational only. The response shape never depends on it, so you can ignore it.
Errors
{ "error": { "code": "NOT_FOUND", "message": "Conversation not found" } }| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_PARAMS | Invalid parameter or body |
| 401 | UNAUTHENTICATED / INVALID_API_KEY | Missing, unknown, or revoked key |
| 404 | NOT_FOUND | Resource does not exist, or belongs to another store |
| 409 | CHANNEL_UNAVAILABLE | The channel can't deliver this message right now |
| 429 | RATE_LIMITED | Rate limit exceeded |
Requesting a conversation that belongs to another store returns the same 404 as one that doesn't exist. This is deliberate — it keeps stores from probing each other.
Rate limits
| Limit | Value |
|---|---|
| Per API key | 120 requests/min |
| Per source IP | 300 requests/min |
Every response carries X-RateLimit-Limit and X-RateLimit-Remaining, so you can throttle before you hit the wall. Back off on 429 and retry.
Conversations
| Method | Path | Returns |
|---|---|---|
GET | /chat/conversations | List, newest activity first |
GET | /chat/conversations/{id} | Full conversation detail |
GET | /chat/conversations/{id}/related | Other conversations from the same customer. limit default 6, max 50. |
GET | /chat/conversations/{id}/browsed-pages | Pages the visitor viewed in this session |
GET | /chat/conversations/{id}/summary | AI summary of a resolved conversation |
POST | /chat/conversations/{id}/state | Resolve or reopen |
POST | /chat/conversations/{id}/assign | Assign to a team member. {"memberId": "..."} |
POST | /chat/conversations/{id}/read | Mark read on the agent side |
POST | /chat/conversations/{id}/typing | Agent typing indicator. {"memberId": "...", "active": true}. Clears itself after 10 seconds. |
List filters
| Param | Example | Description |
|---|---|---|
status | open | open or resolved |
channel | whatsapp | online_store, email, facebook, instagram, whatsapp |
assigneeId | unassigned | Member id, or unassigned |
isRead | false | Read state on the agent side |
tag | pre-sale | Repeatable |
customerUuid | c_abc123 | One customer's conversations |
email | a@shop.com | Customer email |
limit | 20 | Default 20, max 100 |
cursor | eyJ... | From paging.nextCursor |
{id} accepts either form of conversation id. The response carries all of them — id, firestoreId, and pgConvoId — so you can match a conversation against records you stored earlier.
Messages
| Method | Path | Notes |
|---|---|---|
GET | /chat/conversations/{id}/messages | limit (default 50, max 100), cursor, order (asc or desc) |
GET | /chat/conversations/{id}/messages/{messageId} | Accepts the numeric id or the message UUID |
POST | /chat/conversations/{id}/messages | Send a reply, an internal note, or a message as the customer. memberId is required unless you pass asCustomer. text up to 5000 characters. Returns 201. |
List endpoints exclude deleted messages. The single-message endpoint returns them with "isDeleted": true, so you can reconcile your own copy.
Editing and deleting messages is not available on this API — those actions stay in the Chatty inbox.
Tags, notes, and attributes
| Method | Path | Notes |
|---|---|---|
GET | /chat/tags | Your store's tag catalog |
POST | /chat/conversations/{id}/tags | {"tags": ["vip"]} — appends, deduped, returns the resulting list. Tags over 100 characters are dropped from the request rather than rejected. |
DELETE | /chat/conversations/{id}/tags/{tag} | URL-encode the tag; idempotent |
POST | /chat/conversations/{id}/notes | Checklist note, text up to 150 characters |
PUT / DELETE | /chat/conversations/{id}/notes/{noteId} | Update / remove |
GET | /chat/conversations/{id}/attributes | Custom key/value pairs |
POST | /chat/conversations/{id}/attributes | {"name": "...", "value": "..."} — upserts by name. name up to 255 characters, value up to 1000. |
PUT / DELETE | /chat/conversations/{id}/attributes/{attributeId} | Update / remove |
Customers and team members
| Method | Path | Returns |
|---|---|---|
GET | /chat/customers/{customerUuid} | Contact profile: identity, location, device, order stats, tags, custom attributes |
GET | /chat/customers/{customerUuid}/conversations | That customer's conversations |
GET | /chat/members | Team members — resolve memberId and assignee ids against this list |
GET | /chat/members/{memberId} | One member |
Member records are sanitized: credentials, tokens, and notification internals are never returned.
Webhooks
Manage subscriptions with the same X-Api-Key.
| Method | Path |
|---|---|
GET | /chat/webhooks |
POST | /chat/webhooks |
PUT | /chat/webhooks/{id} |
DELETE | /chat/webhooks/{id} |
See Webhooks for events, payloads, and signature verification.
Common recipes
List open conversations, then page through
curl -s "https://app.chatty.net/chat/conversations?status=open&limit=50" \
-H "X-Api-Key: $CHATTY_KEY"
curl -s "https://app.chatty.net/chat/conversations?status=open&limit=50&cursor=$NEXT_CURSOR" \
-H "X-Api-Key: $CHATTY_KEY"Read a full thread, oldest first
curl -s "https://app.chatty.net/chat/conversations/$CONVO_ID/messages?order=asc&limit=100" \
-H "X-Api-Key: $CHATTY_KEY"Reply as an agent
curl -s -X POST "https://app.chatty.net/chat/conversations/$CONVO_ID/messages" \
-H "X-Api-Key: $CHATTY_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Your order ships tomorrow.", "memberId": "MEMBER_ID"}'memberId must be an active member from GET /chat/members. The conversation auto-assigns to that member when it is unassigned, and an active AI bot hands off to the human. Delivery to Messenger, Instagram, WhatsApp, or email happens automatically.
Sending a message fires a message.created webhook. If your integration both listens to message.created and replies through this endpoint, it will answer its own reply and loop. Check data.senderType and act only on customer.
Add an internal note
Never delivered to the customer. Works on any channel and in any state, and it doesn't hand the conversation off from the AI. It does mark the conversation as read on the agent side.
curl -s -X POST "https://app.chatty.net/chat/conversations/$CONVO_ID/messages" \
-H "X-Api-Key: $CHATTY_KEY" -H "Content-Type: application/json" \
-d '{"text": "Refund approved by finance.", "memberId": "MEMBER_ID", "isNote": true}'Relay an inbound message as the customer
For example, from your own channel bridge. Send asCustomer: true; memberId and isNote are ignored in that mode.
curl -s -X POST "https://app.chatty.net/chat/conversations/$CONVO_ID/messages" \
-H "X-Api-Key: $CHATTY_KEY" -H "Content-Type: application/json" \
-d '{"text": "Where is my order?", "asCustomer": true}'Resolve a conversation
curl -s -X POST "https://app.chatty.net/chat/conversations/$CONVO_ID/state" \
-H "X-Api-Key: $CHATTY_KEY" -H "Content-Type: application/json" \
-d '{"status": "resolved"}'Tag it
curl -s -X POST "https://app.chatty.net/chat/conversations/$CONVO_ID/tags" \
-H "X-Api-Key: $CHATTY_KEY" -H "Content-Type: application/json" \
-d '{"tags": ["vip", "refund-request"]}'Things worth knowing
- A few older conversations don't appear in the list. They are still reachable by id, but won't show up in
GET /chat/conversations. - Freshness. A read issued milliseconds after a live send may not include the newest message yet. Webhooks are the reliable way to react in real time.
409 CHANNEL_UNAVAILABLEon send means the channel can't deliver: no recipient, no customer email, or you're outside the platform's 24-hour messaging window on Messenger, Instagram, or WhatsApp. An internal note (isNote: true) is always accepted.browsed-pagesis session-scoped, capped at the 50 most recent pages, and kept for about 24 hours. Older conversations return an empty list.summaryreturns 404 until the AI has generated a summary for that conversation. Summaries are normally produced when a conversation is resolved.
Need help?
Contact the Chatty support team from your dashboard. Include the endpoint, the timestamp of a failing request, and the returned error.code.
To read contacts and customer data instead of conversations, see the GraphQL Customer API.
Chatty Help Center