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:send and messages:read. Create the key in the customer portal at https://emails.routeon.io under "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