curl --request POST \
--url https://api.paigeme.dev/v1/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"conversationId": "<string>",
"phone": "<string>",
"bsuid": "<string>",
"content": "<unknown>"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
conversationId: '<string>',
phone: '<string>',
bsuid: '<string>',
content: '<unknown>'
})
};
fetch('https://api.paigeme.dev/v1/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.paigeme.dev/v1/messages"
payload = {
"conversationId": "<string>",
"phone": "<string>",
"bsuid": "<string>",
"content": "<unknown>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"success": true,
"data": {
"id": "<string>",
"status": "<string>"
}
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}Send a message (session, template, or interactive)
Dispatch by type. Session types (text|image|video|audio|document|location) and interactive (button/list/carousel) are gated by the 24h customer-service window (closed → 409 outside_24h_window); template is exempt. Supports the optional Idempotency-Key header (safe retries — a completed key replays the stored response). Reserves 1 unit of the daily send quota.
What you must send. Beyond type, the required fields are conditional, so they cannot all be marked required in the schema below:
- Session and
interactivetypes need exactly one recipient —conversationIdorphone(E.164, e.g.+27821234567) orbsuid— pluscontent. Fortext,contentis the message body; for media types it is the URL or media id; forinteractiveit is the button/list/carousel payload. Omit the recipient →400 missing_recipient. templateneeds a recipient spelledtoorphone(an E.164 number —conversationId/bsuidare not accepted on this branch), plus a template name and a language.- Template name and language each accept two spellings —
nameortemplateName, andlanguageorlanguageCode— because the endpoint takes both the friendly and the strict form. Send one of each; if both are present the friendly spelling (name/language) wins. Missing →400 missing_template_name/400 missing_language. - Template variables go in either raw Meta
componentsor the structuredheader/body/footer/buttonsform. If you send both, rawcomponentstakes precedence and the structured form is ignored. A variable count that disagrees with the approved template is400 template_variable_mismatch.
Required scope: messages:send
curl --request POST \
--url https://api.paigeme.dev/v1/messages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"conversationId": "<string>",
"phone": "<string>",
"bsuid": "<string>",
"content": "<unknown>"
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
conversationId: '<string>',
phone: '<string>',
bsuid: '<string>',
content: '<unknown>'
})
};
fetch('https://api.paigeme.dev/v1/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.paigeme.dev/v1/messages"
payload = {
"conversationId": "<string>",
"phone": "<string>",
"bsuid": "<string>",
"content": "<unknown>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"success": true,
"data": {
"id": "<string>",
"status": "<string>"
}
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}{
"success": false,
"error": {
"code": "invalid_request",
"message": "Invalid request body",
"details": {}
},
"request_id": "<string>"
}Authorizations
Project API key issued in Settings → API keys. Send it as Authorization: Bearer pk_live_….
Headers
Opt-in idempotency key for safe retries of this send.
255Target project id, for an MCP OAuth bearer (mcp_at_…) attached to more than one project — get ids from GET /v1/projects. Matched case-insensitively.
Omit it and a READ falls back to the connection's default project; a mutation (any non-GET) on a connection with 2+ projects is rejected with 400 project_required — a write is never defaulted to a guessed project. A connection with exactly one project never needs the header.
Scopes are checked against the SELECTED project only, never a union across the connection.
For a pk_ API key the header selects nothing — one key is one project's context — but it IS validated: omit it and the key's own project is used, send it and it must name that project, otherwise the call is rejected with 403 project_not_attached (a blank value is 400 invalid_project_header, as above).
Body
Was this page helpful?
