Last updated: 2026-03-035 min read

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

FieldTypeRequiredDescription
tostring | string[]YesRecipient address(es)
fromstringYesVerified sender address
subjectstringYesEmail subject
htmlstringOne of html/textHTML body
textstringOne of html/textPlain text body
reply_tostringNoReply-To address
attachmentsAttachment[]NoFile attachments
headersobjectNoCustom 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

StatusCodeDescription
400invalid_payloadMissing required fields or malformed JSON
400invalid_addressMalformed email address
401invalid_api_keyMissing or invalid Authorization header
403domain_not_verifiedFrom address domain is not verified
429rate_limit_exceededTier limit reached. Includes retry_after
500transient_failureTransient 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

ReasonDescription
mailbox_fullRecipient mailbox over quota
mailbox_does_not_existAddress not found on recipient server
no_mx_recordNo MX record for recipient domain
connection_timeoutRecipient server unreachable

Rejection reasons

ReasonDescription
suppression_listAddress on global or account suppression list
invalid_addressAddress failed syntax or MX validation
domain_not_verifiedSending domain not verified in your account
POST /v1/send | Truncus Manual