Agents Live
Agents are the team members who handle conversations. Every agent has a role (admin, supervisor, agent), a channel scope, and zero or more department memberships. This API covers invite, edit, and deactivate. There is no direct-create or hard-delete endpoint.
List agents
Cursor-paginated list of agents in the workspace. Optional filters by role, status, and departmentId.
Code samples
curl 'https://app.message.com/api/v1/agents' \
-H 'Authorization: Bearer YOUR_WORKSPACE_JWT'const res = await fetch('https://app.message.com/api/v1/agents', {
headers: { Authorization: 'Bearer ' + token }
});
const { agents } = await res.json();import requests
r = requests.get(
"https://app.message.com/api/v1/agents",
headers={"Authorization": f"Bearer {token}"},
)
agents = r.json()["agents"]require "net/http"
require "json"
uri = URI("https://app.message.com/api/v1/agents")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
http.request(req)
end
agents = JSON.parse(res.body)["agents"]<?php
$ctx = stream_context_create([
"http" => ["method" => "GET", "header" => "Authorization: Bearer $token"]
]);
$agents = json_decode(file_get_contents("https://app.message.com/api/v1/agents", false, $ctx), true)["agents"];Get one agent
{
"id": "uuid",
"email": "[email protected]",
"name": "Alex Lee",
"role": "agent",
"status": "available",
"channels": ["chats", "tickets"],
"groups": [{ "id": "uuid-billing", "name": "Billing" }],
"groupIds": ["uuid-billing"],
"avatarUrl": "https://...",
"hasPassword": true,
"inviteStatus": "joined",
"createdAt": "2026-01-04T12:00:00Z"
}Invite an agent
There is no direct-create endpoint. Agents always join by email invite: this sends an invitation email containing a one-time /join/{code} link the recipient uses to set their password. Pending invites count against the seat cap. Admin-only.
| Field | Type | Description |
|---|---|---|
| emailrequired | string | Invitee email. Must be unique across the workspace. |
| namerequired | string | Display name. Pre-fills the invitee's profile. |
| rolerequired | enum | One of admin, supervisor, agent. |
| channelsoptional | string[] | Subset of chats, tickets, calls. Omit to inherit the default (admins get all three, others get chats). Admins always see all channels regardless of this field. |
| groupIdsoptional | uuid[] | Initial department memberships. |
{
"email": "[email protected]",
"name": "Alex Lee",
"role": "agent",
"channels": ["chats", "tickets"],
"groupIds": ["uuid-billing"]
}Update an agent
Change role, channels, department memberships (groupIds or departments, both accepted), or display name. Admins can edit anyone; supervisors can edit only their own department members; agents can edit only themselves (and only name + avatar).
Set status
Sets the calling agent's availability. Drives routing (only available agents receive new assignments) and presence indicators in the inbox.
{ "status": "away" }Allowed values: available, away, offline.
Deactivate an agent
There is no dedicated /suspend action. DELETE is the suspend: it soft-deactivates the agent (status: "offline", role: "agent", password cleared, JWT invalidated) rather than deleting the row. Their assigned conversations fall back to their department or the workspace queue. Admin-only, and you cannot deactivate yourself or the workspace owner (the oldest admin).
Reinstate a deactivated agent
There is no direct reinstate action either. A deactivated agent's password was cleared, so they look unjoined again: resending their invite and having them redeem it (the same /join/{code} flow as a first-time invite) reactivates the account.
Errors on delete
You cannot deactivate the last admin, yourself, or the workspace owner. The API returns 400 cannot_deactivate_self or 400 cannot_deactivate_owner.
Errors
| Code | When |
|---|---|
400 invalid_body | Payload validation failed. |
400 last_admin | PATCH tried to demote the last remaining admin. |
400 cannot_demote_owner | PATCH tried to change the workspace owner's (oldest admin's) role. |
400 cannot_deactivate_self | DELETE tried to deactivate the calling agent. |
400 cannot_deactivate_owner | DELETE tried to deactivate the workspace owner. |
403 admin_required | Caller is not an admin (invite, update, resend-invite, and delete are all admin-only). |
404 not_found | Agent does not exist in this workspace. |
409 email_already_exists | Invite or update used an email another agent in this workspace already has. |
409 already_joined | Resend-invite was called on an agent who already set a password. |
Common pitfalls
- Setting
channelsfor admins. Ignored. Admins always see all channels. - Looking for a create-agent endpoint. There isn't one. Every agent starts as an invite (
POST /api/v1/agents/invite); they exist in a pending state until they set a password. - Looking for a
passwordfield on invite. Passwords are set by the invitee via the invite link, not passed by the inviting admin.