API Reference
Chat Conversations API
💬Get free consultation

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 URLhttps://app.chatty.net
Auth headerX-Api-Key: <your key>
FormatJSON 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.

RuleDetail
Formatsk_ followed by 32 hex characters
TitleRequired, up to 50 characters — name it after the integration that will use it
LimitUp to 5 active keys per store
VisibilityShown 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. Pass nextCursor back as the cursor query parameter to fetch the next page. nextCursor: null means 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" } }
StatusCodeMeaning
400INVALID_PARAMSInvalid parameter or body
401UNAUTHENTICATED / INVALID_API_KEYMissing, unknown, or revoked key
404NOT_FOUNDResource does not exist, or belongs to another store
409CHANNEL_UNAVAILABLEThe channel can't deliver this message right now
429RATE_LIMITEDRate 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

LimitValue
Per API key120 requests/min
Per source IP300 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

MethodPathReturns
GET/chat/conversationsList, newest activity first
GET/chat/conversations/{id}Full conversation detail
GET/chat/conversations/{id}/relatedOther conversations from the same customer. limit default 6, max 50.
GET/chat/conversations/{id}/browsed-pagesPages the visitor viewed in this session
GET/chat/conversations/{id}/summaryAI summary of a resolved conversation
POST/chat/conversations/{id}/stateResolve or reopen
POST/chat/conversations/{id}/assignAssign to a team member. {"memberId": "..."}
POST/chat/conversations/{id}/readMark read on the agent side
POST/chat/conversations/{id}/typingAgent typing indicator. {"memberId": "...", "active": true}. Clears itself after 10 seconds.

List filters

ParamExampleDescription
statusopenopen or resolved
channelwhatsapponline_store, email, facebook, instagram, whatsapp
assigneeIdunassignedMember id, or unassigned
isReadfalseRead state on the agent side
tagpre-saleRepeatable
customerUuidc_abc123One customer's conversations
emaila@shop.comCustomer email
limit20Default 20, max 100
cursoreyJ...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

MethodPathNotes
GET/chat/conversations/{id}/messageslimit (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}/messagesSend 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

MethodPathNotes
GET/chat/tagsYour 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}/notesChecklist note, text up to 150 characters
PUT / DELETE/chat/conversations/{id}/notes/{noteId}Update / remove
GET/chat/conversations/{id}/attributesCustom 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

MethodPathReturns
GET/chat/customers/{customerUuid}Contact profile: identity, location, device, order stats, tags, custom attributes
GET/chat/customers/{customerUuid}/conversationsThat customer's conversations
GET/chat/membersTeam 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.

MethodPath
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_UNAVAILABLE on 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-pages is session-scoped, capped at the 50 most recent pages, and kept for about 24 hours. Older conversations return an empty list.
  • summary returns 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.