agentlyleads docs
Chat API

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_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Query parameters

ParameterRequiredDescription
statusNoWhich queue: waiting, open, closed, spam, trash or all. See below
handlerNoWho is answering: AI, HUMAN or WAITING. Case-insensitive
assigneeIdNoOnly conversations owned by this user. Pass none for unassigned ones
siteIdNoOnly conversations from this chat site
sinceNoISO 8601 datetime. Only conversations with a message at or after this time. updatedSince works too
limitNoPage size, 1 to 1000. Default 100
cursorNoThe nextCursor from the previous page

Queues

status uses the same queues as the Chat screen in the app:

statusWhat it returns
waitingA visitor is waiting for a person and nobody has picked it up. The app calls this "Needs a human"
openEverything not closed
closedHandled
spamThe Spam folder
trashThe Trash folder
allEvery 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.

On this page