Transactional Send
Send one message that a person's own action asked for, such as a password reset, a receipt or a confirmation code. It goes to one to five recipients. For anything bulk, use a campaign.
POST /api/v1/send
Needs a bearer API key (see API Overview).
{
"to": "ada@example.com",
"subject": "Your receipt",
"html": "<p>Thanks for your order.</p>",
"text": "Thanks for your order.",
"replyTo": "support@example.com"
}
| Field | Notes |
|---|---|
to | Required. One address or an array of up to 5. Duplicates are removed. Any invalid address rejects the request |
subject | Required. Control characters are stripped and the subject is cut at 500 characters |
html | The HTML body. Send html, text, or both |
text | The plain text body. If you send only text, it is wrapped in a minimal HTML page |
replyTo | Optional address. Defaults to the workspace reply-to, if one is set |
The message comes from your workspace's sending address: your verified custom domain if you have one, otherwise the shared Flomailr address, with your workspace's from name.
Response
{ "data": { "sent": 1, "failed": 0, "blocked": [] } }
blocked lists recipients that were skipped and why, as { "email": "...", "reason": "..." }. Reasons are SUPPRESSED_HARD_BOUNCE, SUPPRESSED_COMPLAINT, SUPPRESSED_MANUAL and BLOCKED_DOMAIN.
If every recipient is blocked the request returns 422. If every send attempt fails it returns 502.
How it differs from campaign mail
Transactional mail follows different rules on purpose:
- No unsubscribe footer, no
List-Unsubscribeheader, and no postal address requirement. - No open or click tracking is added.
- A marketing unsubscribe does not block it. Someone who left your newsletter can still get a password reset.
- Quiet hours and the daily send cap do not apply.
These still apply:
- Addresses suppressed for a hard bounce, a spam complaint or a manual block are skipped.
- Domains in your blocked-domains list are skipped.
- The workspace must not be suspended, and the guardrails master switch must be on (otherwise
403). - The message counts toward your monthly sending limit. A send that would pass it returns
402with codeQUOTA_EXCEEDED.
See Compliance for where the line between transactional and marketing mail sits.
Idempotency
Send an Idempotency-Key header to make retries safe:
curl -X POST https://flomailr.com/api/v1/send \
-H "Authorization: Bearer $FLOMAILR_KEY" \
-H "Idempotency-Key: receipt-1042" \
-H "Content-Type: application/json" \
-d '{"to":"ada@example.com","subject":"Your receipt","text":"Thanks for your order."}'
- A repeat with the same key and the same request returns the original result without sending again, and the response includes
"replayed": true. - The same key with a different request returns
409with codeCONFLICT. - The same key while the first request is still running returns
409.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | VALIDATION_ERROR | The body is not valid JSON |
| 422 | VALIDATION_ERROR | Missing or invalid recipients, subject or body, or all blocked |
| 402 | QUOTA_EXCEEDED | The send would pass the monthly limit |
| 403 | FORBIDDEN | The workspace is suspended or guardrails are off |
| 409 | CONFLICT | Idempotency-Key reused with a different request, or still running |
| 502 | INTERNAL_ERROR | Every recipient failed to send |