agentlyleads docs
Chat API

Replying and triage

Every action here is a POST (or DELETE for removing a tag) on one conversation, requires the write:chat scope (or * for full access), and returns the conversation after the change:

{ "chat": { "id": "cmq5chat0alk34567890", "status": "CLOSED", "handler": "HUMAN" } }

Each action does exactly what the same button does in the app, so both always agree.

Acting as a rep

An API key belongs to the workspace, not to a person. When an action is done in someone's name, you say who with one of these fields in the JSON body:

FieldDescription
asUserIdA workspace user ID
asUserEmailThat user's login email

The user must be an active member of the key's workspace. A user from another workspace, or one who has been deactivated, is refused with 400.

ActionActor
Reply, take over, hand backRequired. The visitor sees this person's name
Close, reopen, assignOptional. Defaults to the workspace owner
Tags, spamNot used

Reply

POST /api/v1/chats/{id}/reply

Sends a message to the visitor. They see it in the chat widget straight away.

FieldRequiredDescription
bodyYesThe message, up to 2,000 characters. Leading and trailing spaces are trimmed
asUserId or asUserEmailYesThe rep replying
curl -s -X POST https://agentlyleads.com/api/v1/chats/cmq5chat0alk34567890/reply \
  -H "Authorization: Bearer $AL_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Yes, we ship to Canada. Most orders arrive in 3 to 5 business days.",
    "asUserEmail": "kevin@example.com"
  }'

Returns 201 with the new message and the conversation:

{
  "message": {
    "id": "cmq6msg02alk34567890",
    "role": "USER",
    "userId": "cmq1user0alk34567890",
    "userName": "Kevin Rep",
    "body": "Yes, we ship to Canada. Most orders arrive in 3 to 5 business days.",
    "createdAt": "2026-09-27T14:03:10.000Z"
  },
  "chat": { "id": "cmq5chat0alk34567890", "handler": "HUMAN" }
}

Only the rep handling a conversation can write into it. If the rep you name is not already handling it, the reply takes it over first, as described next. A body that is empty or only spaces is refused before anything changes hands.

Take over

POST /api/v1/chats/{id}/take-over

A rep picks the conversation up from the AI agent or the waiting queue. It becomes HUMAN, is assigned to that rep, and the visitor sees "Kevin joined the conversation". From then on the AI agent does not answer.

curl -s -X POST https://agentlyleads.com/api/v1/chats/cmq5chat0alk34567890/take-over \
  -H "Authorization: Bearer $AL_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "asUserId": "cmq1user0alk34567890" }'

You rarely need this before replying, since a reply takes over on its own. Use it to claim a conversation before you have something to say.

Hand back

POST /api/v1/chats/{id}/hand-back

The rep steps out. The conversation is unassigned and the visitor sees "Kevin left the conversation". Where it goes next depends on the chat site's settings:

  • Inside the site's team hours it goes back to WAITING and the team is notified.
  • Outside them the AI agent picks it up and answers the visitor.

Only the rep handling the conversation, or a workspace owner, can hand it back:

{ "error": "Only the person handling this chat can hand it back." }

Close and reopen

POST /api/v1/chats/{id}/close and POST /api/v1/chats/{id}/reopen

Closing marks the conversation handled for the whole team. If the visitor is linked to a contact or lead, the transcript is saved onto that record as a chat communication. Closing again later, after a reopen, updates that same entry instead of adding a second copy.

Both take an optional asUserId or asUserEmail for who did it. The body can be left out entirely:

curl -s -X POST https://agentlyleads.com/api/v1/chats/cmq5chat0alk34567890/close \
  -H "Authorization: Bearer $AL_KEY"

Closing does not change handler. A visitor who writes again after a conversation is closed starts a new conversation.

Assign

POST /api/v1/chats/{id}/assign

Sets the conversation's owner in the team queue, or clears it.

FieldRequiredDescription
assigneeIdYesAn active workspace user, or null to unassign
asUserId or asUserEmailNoWho made the change. Defaults to the workspace owner
curl -s -X POST https://agentlyleads.com/api/v1/chats/cmq5chat0alk34567890/assign \
  -H "Authorization: Bearer $AL_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "assigneeId": "cmq1user1alk34567890" }'

The new owner is notified, the same as when a teammate assigns them a conversation in the app. Assigning changes ownership only: it does not change who is typing to the visitor. To do both, take over as that person instead.

Tags

POST /api/v1/chats/{id}/tags adds one tag. DELETE /api/v1/chats/{id}/tags removes one.

To add, send tagId for an existing workspace tag, or name to find the tag by name and create it if your workspace has not used it yet:

curl -s -X POST https://agentlyleads.com/api/v1/chats/cmq5chat0alk34567890/tags \
  -H "Authorization: Bearer $AL_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Pricing" }'

To remove, pass tagId or name as a query parameter. Names match case-insensitively. Removing a tag from a conversation never deletes the tag itself.

curl -s -X DELETE "https://agentlyleads.com/api/v1/chats/cmq5chat0alk34567890/tags?name=pricing" \
  -H "Authorization: Bearer $AL_KEY"

Tags are shared with the rest of the CRM, so "Pricing" on a chat is the same tag as "Pricing" on a deal.

Spam

POST /api/v1/chats/{id}/spam

FieldRequiredDescription
spamYestrue to mark as spam, false to undo

Marking a conversation as spam moves it to the Spam folder and blocks the visitor on that chat site for 30 days, so the same browser cannot start a new conversation. spam: false takes it back out of Spam and lifts the block straight away.

curl -s -X POST https://agentlyleads.com/api/v1/chats/cmq5chat0alk34567890/spam \
  -H "Authorization: Bearer $AL_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "spam": true }'

The conversation's visitor.blocked and visitor.blockedUntil show the block.

The block is per browser and per site. It stops a visitor from reopening the chat after you mark them as spam, but someone who clears their browser storage can start again, so treat it as a way to keep junk out of the queue rather than as a security control.

On this page