GET /api/v1/chats
Returns website chat conversations, newest-started first, one page at a time. Requires the read:chat scope (or * for full access).
Request
GET /api/v1/chats?status=waiting HTTP/1.1
Host: agentlyleads.com
Authorization: Bearer alk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxQuery parameters
| Parameter | Required | Description |
|---|---|---|
status | No | Which queue: waiting, open, closed, spam, trash or all. See below |
handler | No | Who is answering: AI, HUMAN or WAITING. Case-insensitive |
assigneeId | No | Only conversations owned by this user. Pass none for unassigned ones |
siteId | No | Only conversations from this chat site |
since | No | ISO 8601 datetime. Only conversations with a message at or after this time. updatedSince works too |
limit | No | Page size, 1 to 1000. Default 100 |
cursor | No | The nextCursor from the previous page |
Queues
status uses the same queues as the Chat screen in the app:
status | What it returns |
|---|---|
waiting | A visitor is waiting for a person and nobody has picked it up. The app calls this "Needs a human" |
open | Everything not closed |
closed | Handled |
spam | The Spam folder |
trash | The Trash folder |
all | Every conversation, including spam and trash |
| (omitted) | Every conversation that is not in spam or trash |
A conversation in Spam or Trash is left out of waiting, open and closed, so a chat someone binned never reads as waiting.
Response: 200
{
"chats": [
{
"id": "cmq5chat0alk34567890",
"threadKey": "chat:cmq5chat0alk34567890",
"status": "OPEN",
"spam": false,
"trashed": false,
"handler": "WAITING",
"handlerUser": null,
"waitingReason": "TEAM_MODE",
"waitingSince": "2026-09-27T14:01:40.000Z",
"waitingMins": 3,
"live": true,
"hot": false,
"site": { "id": "cmq4site0alk34567890", "name": "Main website" },
"visitor": {
"name": null,
"email": null,
"phone": null,
"pageUrl": "https://example.com/pricing",
"referrer": null,
"locale": "en-CA",
"timezone": "America/Toronto",
"blocked": false,
"blockedUntil": null
},
"contact": null,
"lead": null,
"assignee": null,
"tags": [],
"subject": "Do you ship to Canada?",
"snippet": "Do you ship to Canada?",
"messageCount": 1,
"lastMessageAt": "2026-09-27T14:02:00.000Z",
"lastVisitorAt": "2026-09-27T14:02:00.000Z",
"lastAgentAt": null,
"createdAt": "2026-09-27T14:01:40.000Z"
}
],
"nextCursor": null
}Filters that match nothing return { "chats": [], "nextCursor": null }, not a 404.
Paging
Pass nextCursor back as cursor until it comes back null:
curl -s "https://agentlyleads.com/api/v1/chats?status=closed&limit=50&cursor=cmq5chat0alk34567890" \
-H "Authorization: Bearer $AL_KEY"Pages are ordered by when each conversation started, which does not change, so a conversation that gets a new message while you page is neither repeated nor skipped. To find conversations with recent activity, use since.
Watching the queue
To alert someone when a visitor is waiting, poll the waiting queue:
curl -s "https://agentlyleads.com/api/v1/chats?status=waiting" \
-H "Authorization: Bearer $AL_KEY" | jq '.chats[] | {id, waitingMins, page: .visitor.pageUrl}'The app already notifies the team when a conversation starts waiting, so this is for routing the alert somewhere else, such as a team channel.