Sending
Send over HTTP
Send email with a single authenticated POST request — no SDK required. Works from any language or runtime that can make an HTTP call.
The @deckle/sdk is just a thin wrapper around one endpoint. If you’d rather call the API directly — from a language we don’t ship an SDK for, or from a shell script — everything you need is a Bearer token and a JSON body.
The endpoint#
All sends go through a single endpoint. Send a POST request with your JSON body and authenticate with your secret API key in the Authorization header.
/api/v1/sendPOST https://app.getdeckle.com/api/v1/send
Authorization: Bearer sk_live_...
Content-Type: application/jsonThe base URL is https://app.getdeckle.com/api/v1. Create a key in the dashboard under Developers → API keys — the full sk_live_... value is shown once at creation, so store it somewhere safe. See API keys for details.
Test vs. live keys
Ask_test_ key can only send to the AWS SES simulator (for example success@simulator.amazonses.com) or your own verified domains. Swap in a sk_live_ key to reach real inboxes.Send a request#
The body is JSON with snake_case fields. to, from, and subject are required, plus either html or template. The from address must be on a domain you’ve verified.
curl -X POST https://app.getdeckle.com/api/v1/send \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <hello@acme.com>",
"to": "jane@example.com",
"subject": "Welcome to Acme 👋",
"html": "<h1>Hey Jane</h1><p>Thanks for joining.</p>"
}'You can pass cc, bcc, reply_to (a string or array), a plain-text text alternative, and attachments in the same body. For the full field list, see the emails API reference.
The response#
A successful send returns 200 with a JSON object describing the queued email. The id is Deckle’s email log id (prefixed email_) — use it to look up status later.
{
"id": "email_2Nc8Kx1mQvRz",
"status": "queued",
"messageId": "0100019200000000-11111111-2222-3333-4444-555555555555-000000@eu-west-1.amazonses.com"
}Not sending yet?
If your project doesn’t have delivery configured, the request returns202 and the email is accepted and queued rather than sent immediately. Verify a domain to start delivering.Using a template#
Instead of raw html, pass a template id and a variables object. Deckle renders the stored template with your values, injects a plain-text alternative, and — unlike raw HTML sends — automatically adds open and click tracking.
{
"from": "Acme <hello@acme.com>",
"to": "jane@example.com",
"subject": "Your Acme receipt",
"template": "tmpl_welcome",
"variables": {
"first_name": "Jane",
"plan": "Pro"
}
}Placeholders in the template use {{variable}} syntax, with an optional fallback like {{first_name | "there"}}. The subject can be overridden per send, as shown above. See Templates and Variables & personalization for more.
Errors#
Errors return the appropriate HTTP status and a JSON body of the shape { "error": "message" }. The most common ones:
| Status | Meaning |
|---|---|
401 | Missing or invalid API key. Check the Authorization header and that the key hasn’t been revoked. |
422 | The request was understood but couldn’t be processed — a missing required field, an unverified from domain, or a suppressed recipient. |
429 | Rate limited. You’ve exceeded 120 requests per minute for this project; retry after the number of seconds in the Retry-After header. |
Idempotent sends
Add anIdempotency-Key header to safely retry a send. A repeat with the same key returns the first result with idempotent: true instead of sending again. See Idempotency.