REST API (White-Label Email)
Use the Smailor API to integrate white-label email into your product:
- Let your members create mailboxes on your hosted domain(s)
- Send outbound email from verified domains
- Protect domain and IP reputation with automatic safety checks
Messages count toward your account plan limits.
Base URL
Use your app origin:
https://smailor.com(production)http://localhost:5173(local development)
Authentication
Send your API key on every request:
Authorization: Bearer <your_key>- or
X-API-Key: <your_key>
The full key is shown only once in Settings -> API.
White-Label Flow (Recommended)
- Add and verify a custom domain (DNS + DKIM/SPF/DMARC)
- Call
GET /api/v1/domainsto confirm domain status and reputation - Create member mailboxes with
POST /api/v1/mailboxes - Send emails with
POST /api/v1/send - Continuously monitor bounce/complaint rates per domain
Endpoint: List Domains + Reputation
GET /api/v1/domains
Returns all custom domains in your account with:
- Verification state (
verified) - 30-day sends, bounces, complaints
- Reputation status (
healthy,watch,blocked) - Recommendation message
Example
curl "https://smailor.com/api/v1/domains" \
-H "Authorization: Bearer sk_smailor_..."Endpoint: Create Mailbox (White-Label)
POST /api/v1/mailboxes
Content-Type: application/json
JSON body
| Field | Type | Required | Notes |
|---|---|---|---|
localPart |
string | yes | Mailbox local part, example john-doe |
domain |
string | yes | Must be a verified custom domain in your account |
displayName |
string | no | Sender display name |
Example
curl -X POST "https://smailor.com/api/v1/mailboxes" \
-H "Authorization: Bearer sk_smailor_..." \
-H "Content-Type: application/json" \
-d '{
"localPart": "john-doe",
"domain": "mailer.yourhost.com",
"displayName": "John Doe"
}'Reputation Guard
Mailbox creation is automatically blocked when domain reputation is too risky:
blockedstatus => API returns409 domain_reputation_blocked- Prevents large-scale onboarding on unhealthy domains
- Helps protect IP/domain reputation for all tenants
Endpoint: Send Email
POST /api/v1/send
Content-Type: application/json
JSON body
| Field | Type | Required | Notes |
|---|---|---|---|
to |
string | yes | Recipient email |
from |
string | yes | Must be an active address on a verified custom domain |
subject |
string | yes | Subject line |
text |
string | one of text/html |
Plain text body |
html |
string | one of text/html |
HTML body (sanitized server-side) |
At least one of text or html must be non-empty.
Example
curl -X POST "https://smailor.com/api/v1/send" \
-H "Authorization: Bearer sk_smailor_..." \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"from": "[email protected]",
"subject": "Welcome",
"text": "Your mailbox is now active."
}'Endpoint: Contact Widget Submit
POST /api/widget/submit
Content-Type: application/json
Powers the embeddable contact forms generated in Settings -> Widgets. A website visitor fills in a form, and the message lands in your Smailor inbox as a new ticket from that visitor.
Unlike /api/v1/send, this endpoint delivers inbound to your own inbox, so to only has to be an active address on your account — a verified custom domain is not required.
JSON body
| Field | Type | Required | Notes |
|---|---|---|---|
to |
string | yes | Must be one of your active Smailor addresses |
from |
string | yes | Visitor's email; appears as the sender in your inbox |
name |
string | no | Visitor display name, max 255 chars |
subject |
string | yes | 1–998 chars |
message |
string | yes | Plain text, 1–100000 chars. The HTML body is generated and sanitized server-side |
Example
curl -X POST "https://smailor.com/api/widget/submit" \
-H "Authorization: Bearer sk_smailor_..." \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"from": "[email protected]",
"name": "Jane Doe",
"subject": "Question about pricing",
"message": "Hi, do you offer annual billing?"
}'Success response
{ "ok": true, "messageId": "" }Errors
| Status | Error | Meaning |
|---|---|---|
400 |
invalid_body |
Schema validation failed (details holds the field errors) |
400 |
invalid_to |
The to address is not an active address on your account |
401 |
unauthorized |
Missing or invalid API key |
503 |
service_unavailable |
Message queue temporarily unavailable — retry |
500 |
internal_error |
Temporary server issue |
CORS
The endpoint answers OPTIONS preflight and allows cross-origin POST, so it can be called from your website's front-end. Restrict the allowed origins with the API_CORS_ORIGIN or API_CORS_ALLOWLIST environment variables (default: *).
Keep your API key server-side
Your API key grants full access to your account, not just widget submissions. Pasting it into front-end JavaScript makes it readable by any visitor via page source or the network tab, and reusable to send mail in your name.
For production, put the key behind your own server and have the browser call your endpoint instead:
// your-server/contact → proxies to Smailor with the key from an env var
const upstream = await fetch('https://smailor.com/api/widget/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.SMAILOR_API_KEY}`,
},
body: JSON.stringify({ to: RECIPIENT, from: visitorEmail, subject, message }),
});Set the recipient (to) on your server too — never from the request body — otherwise the endpoint lets anyone send mail to any of your addresses.
Common Errors
Applies to /api/v1 endpoints.
| Status | Error | Meaning |
|---|---|---|
400 |
invalid_body, domain_not_verified |
Validation or domain verification issue |
401 |
unauthorized |
Missing or invalid API key |
403 |
forbidden, card_not_verified |
Plan/billing restrictions |
409 |
address_taken, domain_reputation_blocked |
Conflict or safety guard triggered |
429 |
too_many_requests |
Send frequency limit hit |
5xx |
internal_error |
Temporary server issue |
Best Practices for Reputation Safety
- Use double opt-in for new senders
- Warm up new domains gradually
- Stop onboarding when bounce/complaint rates increase
- Separate transactional and marketing traffic per domain
- Monitor domain-level events daily
Reply Templates (Web Session API)
These routes power the in-app template editor and ticket composer. They authenticate with the same session as the dashboard (browser cookies after login), not with Authorization: Bearer sk_… keys used for /api/v1.
Use cases: building automation around your own logged-in browser session, internal tools same-origin with Smailor, or understanding what the UI calls.
| Method | Path | Purpose |
|---|---|---|
GET |
/api/templates |
List your templates. Optional query: ?groupId= (UUID) or ?ticketId= (UUID) to scope suggestions like the ticket reply UI. |
POST |
/api/templates |
Create a template (JSON body below). Max 50 templates per account. |
GET |
/api/templates/{id} |
Load one template (owner only). |
PATCH |
/api/templates/{id} |
Update fields (name, description, subject, body_html, body_text, is_default, group_ids). |
DELETE |
/api/templates/{id} |
Delete template. |
POST |
/api/templates/{id}/preview |
Body: { "ticketId": "<uuid>" } — returns rendered subject, html, text for that ticket. |
POST |
/api/templates/{id}/use |
Fire-and-forget use counter (called when a template is inserted in the UI). |
Create template (POST /api/templates)
Content-Type: application/json
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string | yes | Display name |
description |
string | no | Short note |
subject |
string | yes | Can include {{placeholders}} |
body_html |
string | yes | HTML body, min length 10 |
body_text |
string | no | Plain text; if omitted, derived from HTML |
is_default |
boolean | no | Mark as default |
group_ids |
string[] (UUID) | no | Restrict template to groups; omit or empty = all groups |
Placeholders
Subject and HTML may use {{variable}} tokens. Common keys: customer_name, customer_email, ticket_id, subject, group_name, sender_name, company_name, date. Unknown keys are left unchanged at render time.
Example (session required — copy your logged-in Cookie header from the browser on your own origin)
curl -X POST "https://smailor.com/api/templates" \
-H "Content-Type: application/json" \
-H "Cookie: " \
-d '{
"name": "Thanks",
"subject": "Re: {{subject}}",
"body_html": "Hi {{customer_name}},
Thanks for your message.
"
}'Errors mirror other JSON APIs: 401 when not signed in, 400 for validation or template quota, 403/404 when listing with ticketId you cannot access.