Read conversations, messages, and media
List Waaru Developer API conversations, paginate message history, read delivery status, and download permitted media using number-bound API keys.
Reviewed
Use messages:read to inspect conversations and messages belonging to the key's WhatsApp number. Use media:read to download a permitted attachment. The number must remain connected with Developer API handling enabled, including for read requests.
List conversations
curl --fail-with-body 'https://api.waaru.app/v1/conversations?limit=10' \
--header "Authorization: Bearer $WAARU_API_KEY" \
--header 'Accept: application/json'The response contains items and nextCursor. Each item contains id, contactId, phoneNumber, contactName, lastMessageAt, humanOwned, and lastMessage (a message object or null). Results are ordered by latest message, newest first.
humanOwned: true means the conversation is assigned, taken over, or paused for a person. Your server must not attempt to bypass that state. An authorized teammate can use Release to API in Inbox when appropriate.
Paginate without offsets
Both list endpoints accept limit from 1 to 100 and default to 50. Their cursor parameter names differ:
| Endpoint | Send the returned nextCursor as |
|---|---|
GET /v1/conversations | after |
GET /v1/conversations/:conversationId/messages | before |
A null cursor means there is no next page. Treat each cursor as opaque, preserve it exactly, and URL-encode it. Do not construct one from an ID, reuse it for a different list, or send unsupported search, page, or offset parameters.
For the next page of conversations, set WAARU_CURSOR to the returned cursor:
curl --get --fail-with-body 'https://api.waaru.app/v1/conversations' \
--header "Authorization: Bearer $WAARU_API_KEY" \
--data-urlencode 'limit=10' \
--data-urlencode "after=$WAARU_CURSOR"Read message history
Replace conversation_example with a returned conversation ID:
curl --fail-with-body 'https://api.waaru.app/v1/conversations/conversation_example/messages?limit=20' \
--header "Authorization: Bearer $WAARU_API_KEY" \
--header 'Accept: application/json'This returns items and nextCursor, newest message first. Pass nextCursor as before to read older messages. Store message IDs so your client can reconcile results without rendering duplicates.
Read one message or its delivery status
curl --fail-with-body 'https://api.waaru.app/v1/messages/message_example' \
--header "Authorization: Bearer $WAARU_API_KEY" \
--header 'Accept: application/json'Example response:
{
"message": {
"id": "message_example",
"conversationId": "conversation_example",
"contactId": "contact_example",
"direction": "outbound",
"status": "delivered",
"type": "text",
"text": { "body": "Thanks. Your enquiry reached the team." },
"occurredAt": "2026-09-06T09:00:00.000Z"
}
}The same message shape appears in history and lastMessage. Inbound messages use direction: "inbound" and status: "received". Outbound statuses are queued, sent, delivered, read, and failed; failures may include failureCode. Content fields depend on type. Do not assume every inbound message contains text.body, or that all provider-specific interactive fields are returned.
Interpret interactive replies and non-text content
An inbound reply-button selection can include this content within the message object:
{
"type": "interactive",
"interactive": {
"type": "INTERACTIVE_RESPONSE",
"mode": "BUTTON",
"optionId": "track_order",
"label": "Track order",
"value": "track_order"
}
}Response modes are BUTTON, LIST and TEMPLATE_QUICK_REPLY. Use the returned selection identifier and mode to match the choice your application offered. Do not parse the visible label as though it were a free-form customer command.
Read payloads do not always mirror send payloads:
- Outbound API media normally preserves its submitted
image,video,audioordocumentobject withlinkand supported caption/filename fields. - Downloadable inbound media uses the separate
mediaavailability projection described below. - Inbound contact cards use entries with
nameas a string andphonesandemailsas string arrays. API-sent contact cards preserve the submitted structured contact-card fields. - Unsupported content can use
type: "unsupported". Keep a readable fallback instead of assumingtext.bodyexists.
Download an attachment
An available attachment includes media.availability: "ready", its media.id, and a downloadPath such as /v1/media/media_example. Other availability values include pending, failed, and unavailable. Wait or handle the unavailable state instead of guessing a download URL.
curl --fail-with-body 'https://api.waaru.app/v1/media/media_example' \
--header "Authorization: Bearer $WAARU_API_KEY" \
--output attachment.binA successful API-key request streams bytes with Content-Type, Content-Disposition, and Cache-Control: private, no-store. It does not return a JSON URL or redirect to storage. Read the content headers when choosing how to save or display the file. Permission, number scope, and media availability are checked again when downloading.
Limit concurrent downloads. The current limit is eight active streams per key and number. A 429 with media_concurrency_exceeded means too many downloads are active. Release existing streams before retrying. The external API has no media upload endpoint; outbound media uses a public HTTPS link.
Choose a WhatsApp API message format
Build Waaru Developer API payloads for text, templates, linked media, interactive buttons and lists, locations, and one contact card with the supported field limits.
Receive and verify Developer API webhooks
Configure a Waaru callback URL, select message events, verify signed raw requests in Node.js, deduplicate delivery, and recover paused or failing webhooks.