Sending Emails
Send transactional emails one at a time or in batches, and query your message history.
Send an email
Send a single transactional email.
Request body
| Field | Type | Description | |
|---|---|---|---|
to | required | string or string[] | Recipient email address(es). Maximum 50 total recipients (to + cc + bcc). |
starterTemplate | required* | string | Slug of a starter template (e.g. welcome, otp). See Starter templates for the full list. Exactly one of starterTemplate, templateId, or html must be provided. |
templateId | required* | UUID | ID of a custom saved template. Available on free plan and above (preview keys cannot use this). |
html | required* | string | Raw HTML body. Available on free plan and above (preview keys cannot use this). |
variables | optional | object | Key-value pairs substituted into the template. See each template’s variable list in Starter templates. |
subject | optional | string | Email subject line (max 998 chars). Required when sending raw html; starter templates have built-in subjects. |
fromName | optional | string | Sender display name (max 1024 chars). |
from | optional | string | Override sender email. Must be a verified sender on your account. On free plans, this field is currently ignored — every send uses your default sender. To send from a different verified sender, change the Default in Settings → Email Setup. |
cc | optional | string[] | Carbon copy recipients. |
bcc | optional | string[] | Blind carbon copy recipients. |
replyTo | optional | string | Reply-to address. |
brandName | optional | string | Brand name injected into template rendering (max 128 chars). |
logoUrl | optional | string | Logo URL injected into template rendering (max 2048 chars). |
attachments | optional | Attachment[] | Up to 10 attachments. Max 5 MB per file, 10 MB total. See below. |
Attachment object
Max 10 attachments per message. Each file must not exceed 5 MB; the total across all attachments must not exceed 10 MB.
| Field | Type | Description | |
|---|---|---|---|
filename | required | string | File name shown to recipient (1–255 chars). |
contentType | required | string | MIME type. Allowed: application/pdf, text/csv, text/plain, text/calendar, common image and Office document types. |
content | required | string | Base64-encoded file bytes. |
inline | optional | boolean | Set true to use Content-Disposition: inline. Requires contentId. |
contentId | optional | string | CID for inline embedding (e.g. reference as cid:logo in HTML). |
Response
{
"messageId": "fd92bd3f-969a-4ff6-87dc-a8b0a16e0297",
"status": "queued",
"from": "your-default-sender@yourbrand.com"
}
messageId is a UUID. Use it with Get a message to look up delivery status. from is the address the email was sent from — for bx_preview_ keys this is noreply@brixus365.dev; for bx_live_ keys it’s your default sender.
Example
1curl -X POST https://app.brixus365.com/api/v1/emails \
2-H "X-API-Key: bx_live_your_key_here" \
3-H "Content-Type: application/json" \
4-d '{
5 "to": "customer@example.com",
6 "starterTemplate": "password_reset",
7 "variables": {
8 "reset_url": "https://app.example.com/reset?token=abc123",
9 "expiry_minutes": 30
10 }
11}'For 8 more languages (PHP, .NET, Java, Go, Rust, Ruby, Elixir, Swift) see Code examples.
Errors
| Status | Code | Description |
|---|---|---|
| 400 | missing_field | None of starterTemplate / templateId / html provided |
| 400 | multiple_modes | More than one of starterTemplate / templateId / html provided |
| 400 | invalid_recipient | Recipient address is invalid or has no MX records |
| 400 | recipient_suppressed | Address has previously bounced or complained — removed from sending |
| 400 | recipient_limit_exceeded | More than 50 recipients (to + cc + bcc) |
| 400 | attachment_type_not_allowed | Content type not in the allowlist |
| 400 | attachment_too_large | Single file exceeds 5 MB or total exceeds 10 MB |
| 400 | too_many_attachments | More than 10 attachments |
| 401 | missing_api_key | X-API-Key header not present |
| 401 | invalid_api_key | Key invalid or revoked |
| 403 | scope_required | Key lacks emails:send permission. Re-create the key with the Send emails (transactional) preset. |
| 403 | no_verified_sender | No sender marked as Default. Open Settings → Email Setup and set one. See Before you send. |
| 403 | upgrade_required | templateId or html not available on preview keys — response includes upgrade_url. Upgrade to a free signup for these. |
| 404 | template_not_found | Unknown starterTemplate slug |
| 409 | idempotency_key_mismatch | Same Idempotency-Key reused with a different request body |
| 422 | validation_failed | Body shape invalid — see error.details.errors[] |
| 429 | rate_limit_exceeded | Per-minute rate exceeded — see error.details.limit_per_minute |
| 429 | daily_limit_exceeded | Daily quota exhausted |
| 429 | monthly_limit_exceeded | Monthly quota exhausted |
Send a batch
Send up to 100 emails in a single request. Each message is processed independently — a failure on one doesn’t affect the others. Available on free plan and above (preview keys can’t use batch).
Request body
| Field | Type | Description | |
|---|---|---|---|
messages | required | SendEmailRequest[] | 1–100 message objects. Each has the same shape as POST /v1/emails. Total recipients across all messages must not exceed 1,000. |
Response
{
"results": [
{
"idx": 0,
"messageId": "c2bb8f70-9ae9-4e7a-a8d1-d84a222e0849",
"status": "queued",
"from": "your-default-sender@yourbrand.com",
"error": null
},
{
"idx": 1,
"messageId": null,
"status": null,
"from": null,
"error": {
"code": "recipient_suppressed",
"message": "This address has previously bounced.",
"type": "invalid_request_error"
}
}
]
}
idx corresponds to the zero-based position in your messages array. Always check error on each result.
Errors
| Status | Code | Description |
|---|---|---|
| 400 | batch_limit_exceeded | More than 100 messages or 1,000 total recipients |
| 403 | upgrade_required | Preview keys can’t use batch send. Sign up free for a bx_live_ key. |
List messages
Returns a paginated list of messages sent via API.
Query parameters
| Parameter | Type | Description | |
|---|---|---|---|
from | optional | ISO 8601 | Filter to messages created at or after this timestamp. |
to | optional | ISO 8601 | Filter to messages created before this timestamp. |
status | optional | string | One of: pending, sent, delivered, bounced, complained, failed. |
skip | optional | integer | Pagination offset. Default 0. |
limit | optional | integer | Results per page. Default 50, max 100. |
sortBy | optional | string | Sort column. One of: created_at (default), updated_at, status. Always descending. |
Response
{
"items": [
{
"messageId": "dceaaa96-a806-43d2-ac2d-8396bbd3188a",
"recipientEmail": "customer@example.com",
"subject": "Welcome to Acme",
"status": "sent",
"createdAt": "2026-05-04T10:45:26+00:00",
"updatedAt": "2026-05-04T10:45:26+00:00",
"errorMessage": null
}
],
"total": 8,
"skip": 0,
"limit": 50
}
Get a message
Look up a single message by its ID.
Path parameters
| Parameter | Type | Description | |
|---|---|---|---|
message_id | required | UUID | The messageId returned by POST /v1/emails. |
Response
{
"messageId": "dceaaa96-a806-43d2-ac2d-8396bbd3188a",
"status": "sent",
"recipientEmail": "customer@example.com",
"subject": "Welcome to Acme",
"fromName": null,
"providerMessageId": "0109019df17b973a-...-000000",
"errorMessage": null,
"createdAt": "2026-05-04T10:45:26+00:00",
"updatedAt": "2026-05-04T10:45:26+00:00"
}
providerMessageId is the upstream delivery provider’s tracking ID. Useful when investigating delivery issues with our support team.
Errors
| Status | Code | Description |
|---|---|---|
| 404 | message_not_found | ID doesn’t exist or belongs to a different account |
Analytics
Aggregate delivery metrics for a time window.
Query parameters
| Parameter | Type | Description | |
|---|---|---|---|
from | required | ISO 8601 | Window start (inclusive). |
to | required | ISO 8601 | Window end (exclusive). Must be after from. |
bucket | optional | string | Time granularity: hour or day (default). |
Response
{
"totalMessages": 8,
"deliveryRate": 1.0,
"bounceRate": 0.0,
"complaintRate": 0.0,
"windowStart": "2026-05-03T00:00:00+00:00",
"windowEnd": "2026-05-04T23:59:59+00:00",
"bucket": "day",
"volume": [
{
"timestamp": "2026-05-04T00:00:00+00:00",
"count": 8,
"sent": 8,
"delivered": 7,
"bounced": 0,
"complained": 0,
"failed": 1
}
],
"topErrors": []
}
Per-message delivery webhooks (instant notification when a message is delivered, bounced, or complained) are coming soon. Until then, poll Get a message or use this analytics endpoint for aggregate delivery health.