// reference

API reference.

Every endpoint VoltMail exposes. All requests speak JSON over HTTPS. Base URL https://api.voltmail.dev.

// send

Send email

Send a single email. Returns a queued ID; the actual delivery happens asynchronously.

POST/v1/emails

// parameters

NameInTypeDescription
from*bodystringVerified sending address. Must use a verified domain.
to*bodystring[]Up to 50 recipients. Each will receive an individual delivery.
subject*bodystringEmail subject line. UTF-8, ≤998 bytes.
htmlbodystringHTML body. Either html or text is required.
textbodystringPlaintext body. Either html or text is required.
reply_tobodystringReply-To header.
tagsbodystring[]Up to 10 tags for filtering and analytics.
curlcurl https://api.voltmail.dev/v1/emails \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "from": "noreply@receipts.acme.dev", "to": ["jane@example.com"], "subject": "Your receipt", "html": "<p>Thanks for your order.</p>", "text": "Thanks for your order."}'
request body{
  "from": "noreply@receipts.acme.dev",
  "to": ["jane@example.com"],
  "subject": "Your receipt",
  "html": "<p>Thanks for your order.</p>",
  "text": "Thanks for your order."
}

// responses

202Email accepted and queued.
400Bad request — missing required field or malformed JSON.
401Missing or invalid API key.
422Sender domain not verified, or recipient count exceeds 50.
example response{
  "id": "em_01HV9X3Q8K2BM0F7Z8E5T6Y9N3",
  "status": "queued",
  "created_at": "2026-05-01T12:00:00Z"
}

Send batch

Submit up to 100 messages in a single request. Each is queued independently.

POST/v1/emails/batch

// parameters

NameInTypeDescription
messages*bodyobject[]Array of message objects. Same shape as POST /v1/emails. Max 100.
curlcurl https://api.voltmail.dev/v1/emails/batch \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d @batch.json
request body{
  "messages": [
    { "from": "noreply@acme.dev", "to": ["a@example.com"], "subject": "Hi", "text": "Hello A" },
    { "from": "noreply@acme.dev", "to": ["b@example.com"], "subject": "Hi", "text": "Hello B" }
  ]
}

// responses

202All messages accepted.
207Partial success — some messages rejected.
413Batch exceeded 100 messages.
example response{
  "accepted": 2,
  "ids": ["em_01HV9X3Q8K2BM0F7Z8E5T6Y9N3", "em_01HV9X3Q8K2BM0F7Z8E5T6Y9N4"]
}

Retrieve email

Look up a single email by ID — returns delivery status and timeline.

GET/v1/emails/{id}

// parameters

NameInTypeDescription
id*pathstringEmail ID returned from POST /v1/emails.
curlcurl https://api.voltmail.dev/v1/emails/em_01HV9X3Q8K2BM0F7Z8E5T6Y9N3 \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY"

// responses

200Email record with status timeline.
404No email with that ID.

// domains

Add sending domain

Register a new sending domain. Returns the DNS records you need to publish.

POST/v1/domains

// parameters

NameInTypeDescription
domain*bodystringThe hostname you want to send from. Use a subdomain — e.g. receipts.acme.dev.
regionbodystringus-east-1 (default), eu-west-1, or ap-south-1.
curlcurl https://api.voltmail.dev/v1/domains \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "receipts.acme.dev", "region": "us-east-1"}'
request body{
  "domain": "receipts.acme.dev",
  "region": "us-east-1"
}

// responses

201Domain created. Publish the records and call verify.
409Domain already exists in this account.
example response{
  "id": "dom_01HV9X4P0N2A8B6C5D4E3F2G1H",
  "domain": "receipts.acme.dev",
  "status": "pending",
  "records": [
    { "type": "TXT", "name": "@", "value": "v=spf1 include:_spf.voltmail.dev -all" },
    { "type": "TXT", "name": "voltmail._domainkey", "value": "v=DKIM1; k=rsa; p=…" },
    { "type": "CNAME", "name": "_dmarc", "value": "_dmarc.voltmail.dev" }
  ]
}

Get domain status

Check the verification status. Each DNS record reports verified | pending | failed.

GET/v1/domains/{id}

// parameters

NameInTypeDescription
id*pathstringDomain ID.
curlcurl https://api.voltmail.dev/v1/domains/dom_01HV9X4P0N2A8B6C5D4E3F2G1H \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY"

// responses

200Domain object with per-record check results.
404No domain with that ID.

List domains

Return all domains in this account, paginated.

GET/v1/domains

// parameters

NameInTypeDescription
limitqueryintegerPage size, default 25, max 100.
cursorquerystringPagination cursor from a previous response.
curlcurl 'https://api.voltmail.dev/v1/domains?limit=50' \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY"

// responses

200Paginated array of domain objects.

Remove domain

Remove a domain from your account. In-flight messages still complete; new sends are rejected.

DELETE/v1/domains/{id}

// parameters

NameInTypeDescription
id*pathstringDomain ID.
curlcurl -X DELETE https://api.voltmail.dev/v1/domains/dom_01HV9X4P0N2A8B6C5D4E3F2G1H \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY"

// responses

204Removed.
404Domain not found.

// api keys

Create API key

Mint a new API key. The plaintext key is shown once — store it immediately.

POST/v1/api-keys

// parameters

NameInTypeDescription
name*bodystringHuman-readable label, e.g. "Staging server".
scopebodystringsend_only | full_access. Default full_access.
curlcurl https://api.voltmail.dev/v1/api-keys \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Production server", "scope": "send_only"}'
request body{
  "name": "Production server",
  "scope": "send_only"
}

// responses

201Key created. Plaintext appears only on this response.
403Caller lacks permission to mint keys.
example response{
  "id": "key_01HV9X5R6T7U8V9W0X1Y2Z3A4B",
  "name": "Production server",
  "key": "vm_live_8K2BM0F7Z8E5T6Y9N3J4Q5R6",
  "scope": "send_only",
  "created_at": "2026-05-01T12:00:00Z"
}

List API keys

Return key metadata. Plaintext is never re-displayed.

GET/v1/api-keys

// parameters

// no parameters

curlcurl https://api.voltmail.dev/v1/api-keys \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY"

// responses

200Array of key metadata records.

Revoke API key

Immediately revoke a key. In-flight requests using it will fail with 401.

DELETE/v1/api-keys/{id}

// parameters

NameInTypeDescription
id*pathstringAPI key ID.
curlcurl -X DELETE https://api.voltmail.dev/v1/api-keys/key_01HV9X5R6T7U8V9W0X1Y2Z3A4B \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY"

// responses

204Revoked.

// audiences

Create contact

Add a contact to an audience. Idempotent on (audience_id, email).

POST/v1/contacts

// parameters

NameInTypeDescription
email*bodystringRecipient email address.
audience_id*bodystringTarget audience.
first_namebodystringOptional first name.
last_namebodystringOptional last name.
curlcurl https://api.voltmail.dev/v1/contacts \
  -H "Authorization: Bearer $VOLTMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "jane@example.com", "first_name": "Jane", "last_name": "Doe", "audience_id": "aud_01HV9X6S7T8U9V0W1X2Y3Z4A5B"}'
request body{
  "email": "jane@example.com",
  "first_name": "Jane",
  "last_name": "Doe",
  "audience_id": "aud_01HV9X6S7T8U9V0W1X2Y3Z4A5B"
}

// responses

201Contact created.
200Contact already exists — returns the existing record.