Skip to main content

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.

  1. Pick your brand and click Generate key.
  2. Give it a Name so you remember what it is for, like "Production server".
  3. Under What can this key do?, check Send transactional emails. (A key can also be scoped to add subscribers via the API.)
  4. 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" }
]
},
"replyTo": "[email protected]"
}
FieldRequiredMeaning
toyesThe recipient's email address.
typeyesThe event key of the event to send.
dataif the event has variablesAn object whose fields fill the template's placeholders. Arrays feed #each loops.
replyTonoA reply-to address for this send.
languagenoA 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": true added, 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:

CodeStatusMeaning
missing_api_key / invalid_api_key401No or bad Authorization header.
insufficient_scope403The key lacks the transactional:send scope.
invalid_to / type_required400Bad recipient address or no event key.
event_not_found404No event with that key for this brand.
event_inactive403The event is switched off in the dashboard.
missing_variables422Required variables were not in data; the response lists them in missing.
recipient_suppressed422The recipient previously hard-bounced or complained; the send was skipped.
transactional_not_enabled403Your plan does not include transactional sending.
transactional_stream_not_ready409The brand's transactional sending domain is not verified yet.
request_in_progress409A request with the same Idempotency-Key is still in flight. Retry shortly.
invalid_idempotency_key400The Idempotency-Key header is longer than 200 characters.
rate_limited / daily_cap_reached429See 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.