Quickstart: send your first email
By the end you will have sent one transactional email through the API and confirmed its delivery status through the API. Time: about 5 minutes.
Prerequisites
- An account and an API key with at least the scopes
domains:read,email:sendandmessages:read. Create the key in the customer portal athttps://emails.routeon.iounder "API keys". The examples below show it as<API_KEY>. - A verified sending domain. If you don’t have one yet, follow Verify a sending domain first.
- An active transactional template. The template must have
message_class: transactional, pass Verify, and be activated — see Templates and Send a transactional email. Note its id; the examples show it as<TEMPLATE_ID>. - Credits on your account. Each transactional email uses one credit — see Billing and credits.
All requests go to the production base URL https://emails.routeon.io/api/v1.
1. Check your API key
curl -s https://emails.routeon.io/api/v1/me
-H "Authorization: Bearer <API_KEY>"
Expected response:
{
"status": "success",
"http_code": 200,
"payload": {
"tenant_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"scopes": ["domains:read", "email:send", "messages:read"],
"auth_type": "api_key",
"email": null,
"allowed_providers": ["ses"]
},
"meta": {}
}
Make sure scopes contains the three scopes above. A request to an endpoint whose scope the key lacks is answered 403 with no meta.details.code. A 401 means the key itself was not accepted.
2. Find your verified sending domain
curl -s https://emails.routeon.io/api/v1/domains
-H "Authorization: Bearer <API_KEY>"
Expected response (abridged to the fields used here):
{
"status": "success",
"http_code": 200,
"payload": [
{
"id": "7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"domain": "mail.example.com",
"status": "verified",
"provider": "ses",
"warmup_enabled": true,
"verified_at": "2026-09-20T09:00:00Z",
"created_at": "2026-09-18T09:00:00Z"
}
],
"meta": { "per_page": 50 }
}
Note the id of a domain with "status": "verified" — you pass it as domain_id in the next step. If no domain is verified, finish Verify a sending domain first: sending from any other domain is refused with 403 domain_not_verified.
3. Send a transactional email
curl -s -X POST https://emails.routeon.io/api/v1/transactional/send
-H "Authorization: Bearer <API_KEY>"
-H "Content-Type: application/json"
-H "Idempotency-Key: quickstart-0001"
-d '{
"domain_id": "7c1e2d3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"to": "recipient@example.com",
"template_id": "<TEMPLATE_ID>",
"variables": { "first_name": "Alex" },
"tags": ["quickstart"],
"metadata": { "order_id": "1001" }
}'
Expected response (202 Accepted):
{
"status": "success",
"http_code": 202,
"payload": {
"message_id": "0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b",
"send_at": null
},
"meta": {}
}
Save message_id for the next step. send_at: null means the email goes out now. The From address is <local_part>@mail.example.com, taken from the sender profile set up for transactional sends or your default sender profile; pass "from": "Name <local_part@mail.example.com>" to override it for one call. variables must match what your template expects. tags and metadata are optional: they are stored on the message and returned in its lookups and webhooks.
The Idempotency-Key makes the call safe to retry: repeating it with the same key and body within 24 hours returns the same message_id and sends nothing new. Use a new key for each new email.
If the call is refused, meta.reason and meta.details.code (or meta.validation_error) tell you why. The most common first-send causes:
| Response | Code | What to do |
|---|---|---|
403 |
none | The key lacks email:send. Create a key with that scope. |
403 |
domain_not_verified |
Use the id of a verified domain. |
403 |
recipient_suppressed |
The address is on your suppression list. Send to another address. |
422 |
template_not_active |
The template is not active, or the id is wrong. Verify and activate it. |
422 |
template_class_mismatch |
The template’s message_class is not transactional. Use a transactional template. |
422 |
content_moderation_rejected |
The active template version was rejected by content verification. Edit, verify and activate a new version. |
409 |
content_moderation_pending |
The content verdict is not ready yet. Retry shortly. |
422 |
sender_not_configured |
No sender profile applies. Create one under "Senders" in the portal, or pass from. |
402 |
insufficient_credits |
Top up your credits. |
See Errors for the full list.
4. Confirm the result
Look the message up by its id:
curl -s https://emails.routeon.io/api/v1/messages/0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b
-H "Authorization: Bearer <API_KEY>"
Expected response once the recipient’s mail server has accepted the email:
{
"status": "success",
"http_code": 200,
"payload": {
"id": "0192a3b4-c5d6-7e8f-9a0b-1c2d3e4f5a6b",
"campaign_id": null,
"to_email": "recipient@example.com",
"status": "delivered",
"provider_message_id": "0107019a2b3c4d5e-6f7a8b9c-0d1e-4f2a-9b3c-4d5e6f7a8b9c-000000",
"error_message": null,
"send_at": null,
"template_id": "<TEMPLATE_ID>",
"source_type": "transactional",
"journey_step_id": null,
"tags": ["quickstart"],
"metadata": { "order_id": "1001" },
"created_at": "2026-09-28T10:00:00Z",
"events": [
{ "type": "delivery", "at": "2026-09-28T10:00:03Z" }
]
},
"meta": {}
}
"status": "delivered" with a delivery event confirms your first email arrived. Right after sending you may still see queued, sending or sent; wait a few seconds and query again. Other outcomes are deferred (a temporary refusal that is retried), bounced, complained, failed, suppressed and canceled; error_message explains a failure or deferral. You can also list everything from this quickstart with GET /messages?tag=quickstart.
Where to go next
- Send a transactional email — scheduled sends, batches of up to 100, cancelation and sender overrides.
- Receive webhooks — get delivery and engagement events pushed to you instead of polling.
- Send OTP codes — one-time passcodes for login and verification.
- Send your first campaign — sending to a list or segment instead of one recipient.
- Messages — statuses, events, tags and metadata in detail.
- Limits — rate limits and daily sending limits.