API reference
Everything SendSlice does, and the shortest path from nothing to an email in your inbox.
- five minutes, start to inbox
- authentication
- when something is wrong
- endpoints
- plans and what they allow
Five minutes, start to inbox
Three calls. The first two you do once.
# 1. make an account. the key comes back once — keep it. curl -X POST https://api.sendslice.com/signup -H 'content-type: application/json' \ -d '{ "email": "you@example.com" }' # 2. click the link in the email we just sent you. # 3. send. curl -X POST https://api.sendslice.com/send \ -H 'authorization: Bearer ss_live_...' \ -H 'content-type: application/json' \ -d '{ "to": "you@example.com", "subject": "Hello", "template_id": "welcome", "data": { "first_name": "Sam" } }'
There is no HTML in step 3, and there never will be. How the message looks is set once in the builder and applies to every send after it.
A new account is in the sandbox: mail goes from our domain with a visible test banner, and only to addresses you have confirmed. That is why step 3 sends to you. Verify a domain to lift it.
Authentication
Every authenticated call takes your key either way:
authorization: Bearer ss_live_...
or
x-api-key: ss_live_...
We store a hash of your key, not the key. That means nobody who steals our database can send as you — and also that we cannot read it back to you if you lose it. Treat anything done with your key as done by you.
When something is wrong
Every failure is the same shape, with a stable code to branch on and a request_id to quote at us.
{
"error": {
"code": "send_cap",
"message": "This account has sent its 50 emails for the month. The allowance resets on the 1st.",
"details": { "plan": "sandbox", "sends_allowed": 50, "window": "month" },
"request_id": "req_8c1f..."
}
}
| Code | Status | What it means |
|---|---|---|
| validation_error | 400 | The body did not match the schema. details names the field. |
| unauthorized | 401 | Missing or unrecognised API key. |
| send_cap | 403 | The month's allowance is spent. It resets on the 1st. |
| unverified_recipient | 403 | Sandbox account sending to an address it has not confirmed. |
| recipient_cap | 403 | Sandbox account is at its limit of confirmed addresses. |
| suppressed | 403 | That address bounced or complained. We will not mail it again. |
| not_found | 404 | No such route or resource. |
| rate_limited | 429 | Too many requests. Back off and retry. |
Endpoints
Create an account. The API key comes back once and is never retrievable again — we store only a hash of it. A brand kit can be set in the same call.
curl -X POST https://api.sendslice.com/signup \
-H 'content-type: application/json' \
-d '{ "email": "you@example.com", "name": "Your app" }'
{
"customer_id": "cus_9f2c...",
"api_key": "ss_live_...", // shown once
"plan": "sandbox",
"message": "Check you@example.com and click the confirmation link."
}
The link in the confirmation email. Until it is clicked the account cannot send. Lost it? POST /confirm/resend with your key.
Send one email. Give exactly one of template_id or html — both, or neither, is a 400. data merges into a template and is meaningless alongside raw html.
curl -X POST https://api.sendslice.com/send \
-H 'authorization: Bearer ss_live_...' \
-H 'content-type: application/json' \
-d '{
"to": "sam@example.com",
"subject": "Reset your password",
"template_id": "password-reset",
"data": { "first_name": "Sam", "reset_url": "https://your.app/r/abc" }
}'
{ "send_id": "snd_4a81...", "status": "sent" }
Optional: reply_to. The look of the message is not in this call and never will be — it comes from your brand kit.
Your send history: recipient, subject, template, time, status and any error. Message bodies are not stored, so they are not here.
Set how your email looks. One flavour sets every knob at once; any individual field you also pass wins over the flavour.
curl -X POST https://api.sendslice.com/brand-kit \
-H 'authorization: Bearer ss_live_...' \
-H 'content-type: application/json' \
-d '{ "flavor": "pecan", "logo_url": "https://your.app/logo.png" }'
Flavours: blueberry apple cherry pecan key-lime lemon-meringue pumpkin. Or open the builder and click through them.
What is currently saved. Returns the documented defaults if you never set one.
Claim a sending domain. Returns the DNS records to publish. Calling it twice for the same domain is safe and tells you the second call created nothing.
curl -X POST https://api.sendslice.com/domains \
-H 'authorization: Bearer ss_live_...' \
-H 'content-type: application/json' \
-d '{ "domain": "mail.your.app" }'
Publish the records, then poll GET /domains. Once one verifies, the test banner stops and you can send to anyone.
Every domain you have claimed and whether it has verified yet.
Addresses that hard-bounced or reported your mail as spam. Sends to them are refused automatically — this endpoint tells you which and why.
The templates and the fields each one takes: welcome password-reset alert generic-message.
Every value a brand kit accepts — flavours, corner styles, border styles and font pairings — so a UI can be built against it without hardcoding a list.
Liveness, with the deployed revision. /ready also checks storage.
Plans and what they allow
Every plan is metered by the calendar month and resets on the 1st. A send past the allowance is refused, not billed.
| Plan | Month | Sends | Sends from | Sends to |
|---|---|---|---|---|
| Whiff | Free | 50 | SendSlice domain, test banner | 5 confirmed addresses |
| Taste | $9 | 5,000 | Your own domain | Anyone |
| Slice | $19 | 25,000 | Your own domain | Anyone |
| Whole pie | $99 | 250,000 | Your own domain | Anyone |
Sandbox is not a trial that expires — it is a mode. It exists so nobody has to touch DNS before seeing a real branded email arrive.