Send with the API
If you have a developer, the send API is the direct way to fire a custom event from your website or app. This page is the one place in these docs written for that developer.
Create an API key
API keys live under Transactional, on the API keys tab. A key belongs to one brand and only works for that brand, so nothing in a request can make it send another brand's email.
- Pick your brand and click Generate key.
- Give it a Name so you remember what it is for, like "Production server".
- Under What can this key do?, check Send transactional emails. (A key can also be scoped to add subscribers via the API.)
- Click Create key.
The key starts with sm_live_ and is shown once. Copy it immediately and store it somewhere safe; the list only ever shows a masked version afterwards, along with the key's scopes, creation date, and when it was last used.
To revoke a key, click the delete button on its row. Any code still using it stops working immediately, and this cannot be undone.
The request
POST https://smartmailing.io/api/v1/transactional/send
Authorization: Bearer sm_live_xxxxx
Content-Type: application/json
{
"type": "order_confirmation",
"data": {
"order_number": "1234",
"total": "€49",
"items": [
{ "name": "Sticker pack", "price": "€19" },
{ "name": "T-shirt", "price": "€30" }
]
},
}
| Field | Required | Meaning |
|---|---|---|
to | yes | The recipient's email address. |
type | yes | The event key of the event to send. |
data | if the event has variables | An object whose fields fill the template's placeholders. Arrays feed #each loops. |
replyTo | no | A reply-to address for this send. |
language | no | A language hint. The event's own language setting takes precedence when set. |
Field names in data are matched case-insensitively against the template's variables; keep your template placeholders lowercase to be safe. brand_name and view_url are supplied automatically.
Retries without duplicates (idempotency)
If your request times out, you do not know whether the email went out, and blindly retrying could send a customer the same receipt twice. To make retries safe, send an Idempotency-Key header: any unique string (up to 200 characters) that identifies this one logical email, like order-1234-confirmation.
POST https://smartmailing.io/api/v1/transactional/send
Authorization: Bearer sm_live_xxxxx
Idempotency-Key: order-1234-confirmation
Content-Type: application/json
Retrying with the same key never sends twice:
- If the first request finished, you get its original response back, with
"replayed": trueadded, whether it succeeded or failed. - If the first request is still in flight, you get HTTP 409 with the code
request_in_progress. Wait a moment and retry. - Rejections that are about your account rather than the request itself (rate limits, plan gates, an unverified sending domain) release the key, so the same key works again once the condition clears.
Keys are remembered for 24 hours, and are scoped to your brand. Use a fresh key for each logical email; reusing order-1234-confirmation for a different order would replay the old response instead of sending.
Responses
Success returns HTTP 200:
{ "ok": true, "id": "…", "messageId": "…" }
Errors return a JSON body with an error code. The ones you are most likely to see:
| Code | Status | Meaning |
|---|---|---|
missing_api_key / invalid_api_key | 401 | No or bad Authorization header. |
insufficient_scope | 403 | The key lacks the transactional:send scope. |
invalid_to / type_required | 400 | Bad recipient address or no event key. |
event_not_found | 404 | No event with that key for this brand. |
event_inactive | 403 | The event is switched off in the dashboard. |
missing_variables | 422 | Required variables were not in data; the response lists them in missing. |
recipient_suppressed | 422 | The recipient previously hard-bounced or complained; the send was skipped. |
transactional_not_enabled | 403 | Your plan does not include transactional sending. |
transactional_stream_not_ready | 409 | The brand's transactional sending domain is not verified yet. |
request_in_progress | 409 | A request with the same Idempotency-Key is still in flight. Retry shortly. |
invalid_idempotency_key | 400 | The Idempotency-Key header is longer than 200 characters. |
rate_limited / daily_cap_reached | 429 | See below. |
Rate limits and daily caps
To bound the damage a leaked key could do, sends are rate limited per brand, per API key, and per trigger, and each brand has a daily transactional send cap. Legitimate bursts fit comfortably within the limits. When a limit is hit, the response is HTTP 429 with a Retry-After header (in seconds); wait that long and retry.
Every attempt, successful or not, is recorded in the send log. See Triggers and the send log.