POST /v1/send
Send a transactional email. Returns a terminal delivery state.
Request
POST https://truncus.co/api/v1/emails/send
Authorization: Bearer tr_live_...
Content-Type: application/json
Idempotency-Key: your-idempotency-key (optional)
Body
{
"to": "user@example.com",
"from": "hello@yourdomain.com",
"subject": "Invoice ready",
"html": "<p>Your invoice is attached.</p>",
"text": "Your invoice is attached.",
"reply_to": "support@yourdomain.com",
"attachments": [
{
"filename": "invoice.pdf",
"content": "base64-encoded-content"
}
],
"headers": {
"X-Entity-Ref-ID": "your-internal-id"
}
}
Fields
| Field | Type | Required | Description |
to | string | string[] | Yes | Recipient address(es) |
from | string | Yes | Verified sender address |
subject | string | Yes | Email subject |
html | string | One of html/text | HTML body |
text | string | One of html/text | Plain text body |
reply_to | string | No | Reply-To address |
attachments | Attachment[] | No | File attachments |
headers | object | No | Custom email headers |
Response
200 — delivered
{
"status": "delivered",
"message_id": "msg_8f21a3b4"
}
200 — bounced
{
"status": "bounced",
"message_id": "msg_9b44c1e2",
"reason": "mailbox_full"
}
200 — rejected
{
"status": "rejected",
"message_id": "msg_a2f7e8d1",
"reason": "suppression_list"
}
Error responses
| Status | Code | Description |
| 400 | invalid_payload | Missing required fields or malformed JSON |
| 400 | invalid_address | Malformed email address |
| 401 | invalid_api_key | Missing or invalid Authorization header |
| 403 | domain_not_verified | From address domain is not verified |
| 429 | rate_limit_exceeded | Tier limit reached. Includes retry_after |
| 500 | transient_failure | Transient infrastructure error. Safe to retry. |
Error shape
{
"error": "rate_limit_exceeded",
"message": "Tier limit exceeded. Retry after 60 seconds.",
"retry_after": 60
}
SDK example
import { Truncus } from '@truncus/node'
const truncus = new Truncus({ apiKey: process.env.TRUNCUS_API_KEY })
const response = await truncus.emails.send({
to: 'user@example.com',
from: 'billing@yourdomain.com',
subject: 'Invoice ready',
html: '<p>Your invoice is ready.</p>'
})
if (response.status === 'delivered') {
// record delivery
} else if (response.status === 'bounced') {
// update contact record — response.reason has detail
} else if (response.status === 'rejected') {
// do not retry — suppressed or invalid address
}
Bounce reasons
| Reason | Description |
mailbox_full | Recipient mailbox over quota |
mailbox_does_not_exist | Address not found on recipient server |
no_mx_record | No MX record for recipient domain |
connection_timeout | Recipient server unreachable |
Rejection reasons
| Reason | Description |
suppression_list | Address on global or account suppression list |
invalid_address | Address failed syntax or MX validation |
domain_not_verified | Sending domain not verified in your account |