Messaging API

Send email, SMS and WhatsApp through your own provider accounts, read the delivery log and manage templates and suppressions.

Messaging sends email, SMS and WhatsApp messages through the provider accounts your workspace has connected (for example SendGrid, Twilio or WhatsApp Cloud). AxisIQ does not send for you: the sending, billing and reputation are your provider's. This API sends messages, reads the delivery log, and manages templates and the do-not-contact list.

Connecting a provider account involves secrets, so it is done in the app (Messaging › Channels). The secrets are never returned by the API.

If the Messaging app is switched off in Settings › Apps, these routes answer 404 NOT_FOUND.

Endpoints

Connections and messages are checked against the connection (its key is the resource), so a role can be limited to one mailbox or number. Templates and the do-not-contact list are workspace-wide: they need comms:read or comms:manage on all connections (*).

Method Path Permission What it does
GET /orgs/{orgId}/comms/connections comms:read List connections
GET /orgs/{orgId}/comms/connections/{connId} comms:read Get a connection
GET /orgs/{orgId}/comms/providers comms:read Supported providers and the fields each needs
GET /orgs/{orgId}/comms/connections/{connId}/templates comms:manage Read the provider's own approved templates
POST /orgs/{orgId}/comms/messages comms:send Send a message
GET /orgs/{orgId}/comms/messages comms:read The delivery log
GET /orgs/{orgId}/comms/messages/{msgId} comms:read One message
GET /orgs/{orgId}/comms/templates comms:read List templates (?channel=)
GET /orgs/{orgId}/comms/templates/{tmplId} comms:read Get a template
POST · PUT · DELETE /orgs/{orgId}/comms/templates[/{tmplId}] comms:manage Manage templates
GET /orgs/{orgId}/comms/suppressions comms:read The do-not-contact list
POST /orgs/{orgId}/comms/suppressions comms:manage Add an address
DELETE /orgs/{orgId}/comms/suppressions/{supId} comms:manage Remove an address

Connections can also be created (POST, comms:connect), edited (PUT), tested (POST …/{connId}/test) and deleted (DELETE, answers 204) with comms:manage. List endpoints return a plain array in data.

Connections

{
  "id": "0190fa00-…",
  "channel": "email",
  "provider": "sendgrid",
  "provider_label": "SendGrid",
  "name": "Billing mail",
  "key": "billing-mail",
  "from_address": "billing@example.com",
  "from_name": "Example Billing",
  "enabled": true,
  "status": "ok"
}

channel is email, sms or whatsapp. A connection also carries its non-secret config, capabilities, last_checked_at and last_error. Use id when sending through the REST API; the Functions SDK addresses connections by key.

POST /orgs/{orgId}/comms/messages

Queue one message. Permission: comms:send on the connection.

Field Type Required Notes
connection_id string Yes The connection to send through
to string One of to or record_id An email address or phone number
record_type, record_id, to_field string Take the recipient from a field of a record, and fill the template from it. You need to be able to read the record
template_id string One of a template or a body A saved template. Its channel must match the connection's
subject, body_text, body_html string A message written inline instead of using a template
data object No Extra values for the template
vars array of strings No Ordered values for providers whose templates take positional variables (WhatsApp)
curl -s -X POST https://axisiq.co/api/v1/orgs/$ORG/comms/messages \
  -H "Authorization: Bearer $AXIS_KEY" -H "Content-Type: application/json" \
  -d '{"connection_id": "0190fa00-…", "to": "asha@example.com", "subject": "Your invoice", "body_text": "Hi Asha, invoice INV-1001 is ready."}'

Response 202 Accepted. The message is queued and sent in the background, so the call never waits on the provider.

{
  "data": {
    "id": "0190fa10-…",
    "connection_id": "0190fa00-…",
    "channel": "email",
    "provider": "sendgrid",
    "direction": "outbound",
    "to": "asha@example.com",
    "from": "billing@example.com",
    "subject": "Your invoice",
    "status": "queued",
    "created_at": "2026-10-04T09:30:00Z"
  }
}

Message statuses

Status Meaning
queued Accepted, waiting to be sent
sending Being handed to the provider
sent The provider accepted it
delivered The provider confirmed delivery
read The recipient opened or read it (where the provider reports it)
bounced The address could not be reached
complained The recipient reported it as spam
failed The provider refused it. error says why
suppressed Not sent because the address is on the do-not-contact list

Later statuses arrive from the provider's callbacks, and a status only moves forward: a late delivered never overwrites a bounced. Some providers (SMTP) report nothing back, so their messages stop at sent. To receive callbacks, open the connection in the app and paste the webhook address it shows into your provider's dashboard.

Errors

Status Code When
400 VALIDATION_ERROR No recipient, no body or template, template and connection channels differ, connection disabled, bad ids
403 FORBIDDEN The role lacks comms:send on this connection
404 NOT_FOUND No such connection, template or record

A message to a do-not-contact address is still accepted (202): the returned message has status suppressed.

GET /orgs/{orgId}/comms/messages

Newest first. Returns an array of message objects.

Parameter Notes
channel email, sms or whatsapp
status One of the statuses above
connection_id, record_id Filters
limit Default 50, maximum 200 (a value above 200 falls back to 50)
cursor The id of the last message of the previous page

Message objects also carry body_text, body_html, template_id, record_type, record_id, provider_message_id, error, sent_at and delivered_at where they apply.

Templates

A template is a reusable message. Email templates have a subject, body_html and body_text; SMS has body_text; WhatsApp templates are the ones your provider has approved, linked by provider_ref. The text uses the same template language as PDF documents, with record values filled in from record_id, and data for anything extra. HTML values are escaped, so a value from a form cannot inject markup.

POST and PUT take key, name, channel, subject, body_html, body_text, object_type (the record type it is written for), provider_ref, provider_status and language. DELETE answers 204.

The do-not-contact list

Bounces, spam complaints and unsubscribes are added to this list automatically. A message to a listed address is never sent: it is logged with status suppressed, whichever route, flow or function asked for it. POST /comms/suppressions takes channel, address and an optional reason, and answers 204. GET takes channel, limit (default 200, maximum 500) and cursor, and answers an array. DELETE …/suppressions/{supId} answers 204.

A recipient who follows an unsubscribe link from one of your messages sees a confirmation page, and is added to the list when they confirm.