List messages in a conversation
GET /api/v1/conversations/{id}/messages/
Scope
messages:read
Paginated message history, inbound and outbound.
Query parameters
| Name | Type | Description |
page | integer | Page number. |
Request
curl -X GET https://api.botpulsar.com/api/v1/conversations/YOUR_ID/messages/ \
-H "Authorization: ApiKey smk_your_prefix_your_secret" \
-H "X-Tenant-ID: YOUR_WORKSPACE_ID"
Response
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "6d1c0b0e-52a4-4b7f-9a55-0a43d6a7c0de",
"client_message_id": "0b5c1a3e-8f6d-4a3e-9c2a-1d9b7f4e6a10",
"direction": "outbound",
"content_type": "text",
"text": "Hi Ada, your order has shipped!",
"delivery_status": "queued",
"provider_message_id": null,
"created_at": "2026-10-11T08:31:02Z",
"...": "..."
}
]
}
Send a text message
POST /api/v1/conversations/{id}/messages/
Scope
messages:write
Free-form text. Only valid inside the 24-hour window.
Request body
| Field | Type | Required | Description |
content_type |
enum |
No |
text (default). |
text |
string |
Yes |
Up to 4,096 characters. |
client_message_id |
uuid |
No |
Your idempotency key. Generated for you if omitted. |
Request
curl -X POST https://api.botpulsar.com/api/v1/conversations/YOUR_ID/messages/ \
-H "Authorization: ApiKey smk_your_prefix_your_secret" \
-H "X-Tenant-ID: YOUR_WORKSPACE_ID" \
-H "Content-Type: application/json" \
-d '{
"content_type": "text",
"text": "Hi Ada, your order has shipped!",
"client_message_id": "0b5c1a3e-8f6d-4a3e-9c2a-1d9b7f4e6a10"
}'
Response
{
"id": "6d1c0b0e-52a4-4b7f-9a55-0a43d6a7c0de",
"client_message_id": "0b5c1a3e-8f6d-4a3e-9c2a-1d9b7f4e6a10",
"direction": "outbound",
"content_type": "text",
"text": "Hi Ada, your order has shipped!",
"delivery_status": "queued",
"provider_message_id": null,
"created_at": "2026-10-11T08:31:02Z",
"...": "..."
}
201 for a new message, 200 when the same client_message_id and body are retried.- Reusing a
client_message_id with a different body is 409 message_idempotency_conflict. - Text outside the 24-hour window is
409 whatsapp_template_required; an opted-out contact is 409 contact_suppressed.
Send a template message
POST /api/v1/conversations/{id}/messages/
Scope
messages:write
Required to start a conversation or after the window closes. Get template_id from the templates endpoint; only approved templates can be sent.
Request body
| Field | Type | Required | Description |
content_type |
enum |
Yes |
template. |
template_id |
uuid |
Yes |
An approved template. |
template_parameters |
object | array |
No |
Variable values: {"1": "Ada"} for numbered variables, or an array in order. |
client_message_id |
uuid |
No |
Your idempotency key. |
Request
curl -X POST https://api.botpulsar.com/api/v1/conversations/YOUR_ID/messages/ \
-H "Authorization: ApiKey smk_your_prefix_your_secret" \
-H "X-Tenant-ID: YOUR_WORKSPACE_ID" \
-H "Content-Type: application/json" \
-d '{
"content_type": "template",
"template_id": "YOUR_APPROVED_TEMPLATE_ID",
"template_parameters": {
"1": "Ada",
"2": "12045"
}
}'
Response
{
"id": "6d1c0b0e-52a4-4b7f-9a55-0a43d6a7c0de",
"client_message_id": "0b5c1a3e-8f6d-4a3e-9c2a-1d9b7f4e6a10",
"direction": "outbound",
"content_type": "template",
"text": "Hi Ada, order 12045 has shipped.",
"delivery_status": "queued",
"provider_message_id": null,
"created_at": "2026-10-11T08:31:02Z",
"...": "..."
}