Messages

Send raw or templated mail, in singles or batches, then follow every message through queueing, delivery attempts, opens and clicks.

Send a message

POST /api/v2/server/messages
{
  "from": {"email": "billing@yourdomain.com", "name": "Acme Billing" },
  "to": ["customer@example.com"],
  "cc": [], "bcc": [], "reply_to": [],
  "subject": "Your receipt",
  "text_body": "Thanks! You paid €49.00.",
  "html_body": "<p>Thanks!</p>",
  "headers": {"X-PM-Tag": "anything" },
  "attachments": [{"name": "invoice.pdf", "content_type": "application/pdf", "data_base64": "…" }],
  "tag": "receipt",
  "metadata": { "order_id": 1042 },
  "stream": "transactional"
}
FieldNotes
fromAddress object or plain string; the domain must be a verified sending domain of the server
to / cc / bccOne message is queued per accepted recipient; each gets its own id and token
tagFree-form label for filtering and stats
metadataArbitrary JSON, returned with the message and in webhooks
streamMessage-stream permalink; defaults to the server's default stream

Send with a stored template

POST /api/v2/server/messages/with_template
{
  "from": "hello@yourdomain.com",
  "to": ["ada@example.com"],
  "template": "welcome",
  "template_model": {"name": "Ada", "product": "Acme" }
}

Renders the template's subject/HTML/text against template_model, then sends. Fields you set directly (e.g. subject) override the rendered ones. See template syntax.

Batches

For spikes, wrap requests in a batch. Each entry gets its own result, and a partial failure doesn't abort the rest:

POST /api/v2/server/messages/batch                 { messages: [SendRequest, …] }
POST /api/v2/server/messages/with_template/batch   one template, many models

Query messages

# search what you sent (or received: scope=incoming)
GET /api/v2/server/messages?scope=outgoing&query=receipt&per_page=50

# one message, its attempts, engagement, and the raw source
GET /api/v2/server/messages/{id}
GET /api/v2/server/messages/{id}/deliveries
GET /api/v2/server/messages/{id}/opens
GET /api/v2/server/messages/{id}/clicks
GET /api/v2/server/messages/{id}/raw

Stats & bounces

GET /api/v2/server/stats              # counters for dashboards
GET /api/v2/server/stats/deliveries   # delivery outcomes over time
GET /api/v2/server/bounces            # bounce messages received

Inbound

Incoming mail (routes → your endpoints) is queryable too, with retry/bypass controls for stuck messages:

GET  /api/v2/server/inbound
GET  /api/v2/server/inbound/{id}
POST /api/v2/server/inbound/{id}/retry
POST /api/v2/server/inbound/{id}/bypass
Response shapes for every endpoint are in the OpenAPI spec. The envelope is always { status, time, data | error }.