Bolrach Send API
Transactional and campaign email from your own domains: one key, one POST, delivered from Bolrach's own IPs with your DKIM.
Quick start
Base URL: https://api.bolrach.com/send/v1
Mint a key on the API keys page, add and verify a domain under Domains, then:
curl -X POST https://api.bolrach.com/send/v1/messages \
-H "Authorization: Bearer $BOLRACH_SEND_KEY" \
-H "Content-Type: application/json" \
-d '{"stream":"transactional","from":{"email":"[email protected]","name":"Example"},"to":"[email protected]","subject":"Your receipt","text":"Thanks for your order."}'
const r = await fetch("https://api.bolrach.com/send/v1/messages", {
method: "POST",
headers: { authorization: `Bearer ${process.env.BOLRACH_SEND_KEY}`, "content-type": "application/json" },
body: JSON.stringify({
stream: "transactional",
from: { email: "[email protected]", name: "Example" },
to: "[email protected]",
subject: "Your receipt",
html: "<p>Thanks for your order.</p>",
idempotency_key: "order-8123-receipt",
}),
});
const message = await r.json(); // 202 { accepted, id, status, message_id }
Inside the estate, apps use @empire/send-client: sendMail({ stream, from, to, subject, html }) with SEND_API_URL and SEND_API_KEY in the service environment.
Authentication
Every request carries Authorization: Bearer snd_live_… (or snd_test_… for a sandbox key that records but does not deliver). Keys are scoped per workspace, can be locked to named From domains, and are shown once at creation. Older mtz_live_ keys keep working.
Streams
A message names its stream and the engine routes it accordingly. transactional and security go out from the transactional IP and always flow. subscribed is marketing: only confirmed contacts receive it, List-Unsubscribe headers are added, it leaves from the campaign IP, and it pauses automatically when the workspace's bounce rate passes 15% or complaint rate passes 0.5%. repermission is the one message you may send an unconfirmed contact, asking them to confirm.
Errors and retries
A send answers 202 when accepted. 400 names the field. 401 is a missing or revoked key. 403 is a From domain the key is not allowed to use, or a domain that is not verified. 429 carries Retry-After. Retry 5xx with the same idempotency_key; the original result comes back and nothing sends twice.
Endpoints
Queue one transactional or campaign message. stream is required: transactional, security, subscribed (marketing, confirmed contacts only) or repermission. The From domain must be verified in your workspace and allowed on the key.
Idempotent. Send idempotency_key (or an Idempotency-Key header) and a retry returns the original message instead of sending twice.
curl -X POST https://api.bolrach.com/send/v1/messages \
-H "Authorization: Bearer snd_live_..." -H "Content-Type: application/json" \
-d '{
"stream": "transactional",
"from": { "email": "[email protected]", "name": "Example" },
"to": "[email protected]",
"subject": "Your receipt",
"html": "<p>Thanks for your order.</p>",
"idempotency_key": "order-8123-receipt"
}'
# 202 { "accepted": true, "stream": "transactional", "id": "...", "status": "sent", "message_id": "<[email protected]>" }
Status, timestamps and the delivery route of one message.
Register a domain you control. The answer lists the DNS records to publish: the DKIM selector, the SPF include spf.bolrach.email, and a DMARC suggestion.
{ "domain": "example.com" }
Every sending domain in the workspace with its verification state.
The domain's records and whether SPF and DKIM currently verify.
Check the published records straight away instead of waiting for the hourly pass.
A contact added through the API or a form is consented at source; an import is unconfirmed until the person confirms.
{ "email": "[email protected]", "consent_source": "api" }
Bulk import. Imported contacts stay unconfirmed and cannot receive the subscribed stream until they confirm.
{ "contacts": [ { "email": "[email protected]" }, { "email": "[email protected]" } ] }
Send the reconfirmation message to every unconfirmed contact.
Filter with ?status=confirmed|unconfirmed|unsubscribed.
Consent state and history for one address.
Records the unsubscribe; the address never receives the subscribed stream again.
A campaign goes to confirmed contacts only, on the subscribed stream, with List-Unsubscribe headers added for you.
{ "name": "October news", "subject": "What is new", "html": "<p>...</p>", "from_email": "[email protected]" }
Counts of sent and blocked recipients.
Refused while the workspace's marketing is paused by the reputation gate.
Variables render server-side when a message names template_id and variables.
{ "name": "receipt", "subject": "Receipt {{order}}", "html": "<p>Order {{order}}</p>" }
Events: accepted, sent, delivered, bounced, failed, suppressed. Every delivery is signed with the whsec_ secret returned once at creation.
{ "url": "https://example.com/hooks/send", "events": ["delivered", "bounced"] }
Delivers a signed test event to the endpoint.
Syntax, MX and free-provider checks for one address before you send to it.
{ "email": "[email protected]" }
{ "emails": ["[email protected]", "[email protected]"] }
Sent, delivered, bounced and failed for the workspace, by day.
Messages this month against the plan cap.
Whether marketing is paused by the reputation gate, and the recent bounce and complaint rates.