Reading data
Everything here is a read, and needs the key's read permission.
GET List accounts
/accounts · needs read
Every account you've connected, on every channel. status is connected, needs_attention or disconnected whatever the channel calls it. GET /accounts/{id} returns one.
{
"accounts": [
{
"id": "01a115a8-…",
"channel": "whatsapp",
"name": "Test WhatsApp",
"identifier": "+15559990000",
"status": "connected",
"canSend": true,
"capabilities": {
"contacts": true,
"startConversation": true,
"requiresSubject": false,
"asyncSend": false,
"maxMessagesPerRead": 100,
"maxTextLength": 10000,
"createAndAuthenticate": false,
"embed": false,
"attachments": false,
"maxAttachmentBytes": 0,
"adoptExisting": false,
"searchMessages": false,
"updateCredentials": false,
"topics": false,
"resolveConversation": false,
"webhooks": true
},
"createdAt": "2026-10-07T09:19:08+00:00"
}
]
}GET List conversations
/accounts/{id}/conversations?limit=50 · needs read
Most recent activity first, up to limit (1–100). There's no paging for conversations. On WhatsApp one person is always one conversation, even if they have two identities.
{
"conversations": [
{
"id": "15551230001@c.us",
"name": "Ada Lovelace",
"isGroup": false,
"lastMessage": { "text": "message number 30", "at": "2026-10-07T09:18:53+00:00", "fromMe": false },
"unreadCount": 2
}
]
}GET Resolve a recipient
/accounts/{id}/resolve?to= · needs read
Telegram only. Turns what a person would type to address someone — @ada, ada, https://t.me/ada, or a phone number with a leading + — into the conversation id the conversation and message routes use for them, so you can open a chat knowing only a username. It sends nothing, spends no credit and creates no chat. A bare numeric chat id is returned as it is. to can be up to 64 characters.
curl "https://messengeragent.dev/api/v1/accounts/ACCOUNT_ID/resolve?to=@ada" -H "Authorization: Bearer $API_KEY"
# → { "conversationId": "777000123", "name": "Ada Lovelace", "username": "ada" }
# Then read the chat with the id you were given.
curl "https://messengeragent.dev/api/v1/accounts/ACCOUNT_ID/conversations/777000123/messages" -H "Authorization: Bearer $API_KEY"404 not_found— "No such Telegram user." Nothing is remembered about a miss, so asking again later works.400 invalid_request—tois missing, blank or too long.422 unsupported_operation— the account's channel cannot do this; checkcapabilities.resolveConversation.429 rate_limited— Telegram asked for a pause; waitRetry-Afterseconds. Lookups have a lower limit than other reads (20 a minute per key) because each one reaches Telegram; a person found is remembered for about ten minutes.
GET List a forum's topics
/accounts/{id}/conversations/{conversationId}/topics · needs read
Telegram only. A forum is a supergroup split into topics: the conversation has isForum: true and no messages of its own, and each topic does. A topic's id is a conversation id like any other, so read it and send into it with the ordinary conversation routes. Pinned topics first, then newest activity first. A conversation that isn't a forum is a 422 unsupported_operation; an account's capabilities.topics says whether its channel has topics at all.
curl "https://messengeragent.dev/api/v1/accounts/ACCOUNT_ID/conversations?limit=50" -H "Authorization: Bearer $API_KEY"
# → { "conversations": [ { "id": "-1001919633522", "name": "Flow Dev", "isGroup": true, "isForum": true, … } ] }
curl "https://messengeragent.dev/api/v1/accounts/ACCOUNT_ID/conversations/-1001919633522/topics" -H "Authorization: Bearer $API_KEY"
# → { "topics": [ { "id": "-1001919633522_1", "name": "General", "isGeneral": true, "isPinned": false, "isClosed": false, "unreadCount": 3, "lastMessage": { … } },
# { "id": "-1001919633522_5968", "name": "News", … } ] }
# A topic's id is a conversation id: read it, and send into it, like any other.
curl "https://messengeragent.dev/api/v1/accounts/ACCOUNT_ID/conversations/-1001919633522_5968/messages" -H "Authorization: Bearer $API_KEY"GET List messages
/accounts/{id}/conversations/{conversationId}/messages?limit=30&before= · needs read
Newest first. type is one of text, image, video, audio, document, sticker, contact, poll, location, other. status is the channel's own delivery state in lower case (sent, delivered, read, failed; on LinkedIn also queued, sending). Attachments are listed, not downloaded, in v1.
{
"messages": [
{
"id": "M30",
"conversationId": "15551230001@c.us",
"direction": "inbound",
"fromMe": false,
"type": "text",
"text": "message number 30",
"subject": null,
"sender": { "name": "Ada Lovelace" },
"status": "delivered",
"at": "2026-10-07T09:18:53+00:00",
"attachments": []
}
],
"hasMore": true,
"nextBefore": "M21"
}GET List contacts
/accounts/{id}/contacts?search=&limit=50&offset=0 · needs read
WhatsApp and LinkedIn. conversationId opens the conversation with that person.
{
"total": 124,
"offset": 0,
"limit": 50,
"contacts": [
{ "id": "01a1…", "name": "Ada Lovelace", "identifier": "+15551230001", "conversationId": "15551230001@c.us", "updatedAt": "2026-10-01T10:00:00+00:00" }
]
}Pagination
Messages page backwards by message, not by time: pass nextBefore from one page as before on the next. Because a cursor is a message id, messages sent in the same second are never skipped at a page boundary. When hasMore is false you've reached the oldest message that's reachable. A before that's no longer reachable is a 422, not a silent restart. Contacts page with limit and offset.
# First page, newest first
curl "https://messengeragent.dev/api/v1/accounts/ACCOUNT_ID/conversations/CONVERSATION_ID/messages?limit=10" ...
# → "hasMore": true, "nextBefore": "M21"
# Older: pass nextBefore as "before"
curl "https://messengeragent.dev/api/v1/accounts/ACCOUNT_ID/conversations/CONVERSATION_ID/messages?limit=10&before=M21" ...