API Reference
The API contract is published as four OpenAPI 3.0 documents, one per functional area, each at version 1.0.0:
| Document |
Tags |
Operations |
| Email.yaml |
Email, OTP, Messages |
7 |
| Contacts.yaml |
Contacts, Lists & Segments, Suppressions, Custom Fields |
32 |
| Campaigns.yaml |
Templates, Assets, Campaigns, Automations |
31 |
| Account.yaml |
Domains, Senders, Webhooks, Billing, Reports, Auth |
26 |
| Total |
|
96 |
Open any of the files in an OpenAPI viewer, such as Swagger UI or ReDoc, to browse request parameters, request bodies, response schemas and error responses for each operation.
All paths on this page are relative to the base URL:
https://emails.routeon.io/api/v1
Authentication
Every request carries an API key of your account as a bearer token:
Authorization: Bearer <API_KEY>
Create and revoke API keys in the customer portal at https://emails.routeon.io, under "API keys". The full key is shown only once, when you create it; store it in your secret manager. A key only ever sees and acts on the data of the account it belongs to.
curl https://emails.routeon.io/api/v1/me
-H "Authorization: Bearer <API_KEY>"
GET /me accepts any valid key and is a quick way to check that a key works.
A missing or malformed Authorization header, or an unknown or revoked key, answers 401 with meta.reason: UNAUTHORIZED and meta.details.code set to missing_authorization_header or api_key_unknown.
Scopes
Each key is created with one or more scopes. The key must hold every scope an operation requires; each operation lists its required scopes in the security section of its YAML document.
| Scope |
Grants |
domains:read |
Read sending domains, DNS records, warmup progress, sender profiles and sender routes |
domains:write |
Register, verify, re-provision and remove domains; control warmup; create, change and delete sender profiles and routes |
contacts:read |
Read contacts, contact exports, import jobs, lists, segments, suppressions and custom fields |
contacts:write |
Create, change, erase and delete contacts; import contacts; record custom events; manage lists, segments, suppressions and custom fields |
templates:read |
Read templates, template versions, per-link check results and stored assets |
templates:write |
Create, edit and archive templates; preview, render and verify them; upload, confirm and delete assets |
campaigns:read |
Read campaigns and their time series, automation enrollments and the reports overview |
campaigns:write |
Create, edit, preview, pause, resume, cancel and delete campaigns; create recipient uploads; enroll contacts into automations |
email:send |
Send transactional email (single and batch), cancel a scheduled transactional email, schedule and launch campaigns |
otp:send |
Request one-time passcodes |
otp:verify |
Verify one-time passcodes |
messages:read |
Query messages and read a message’s status and events |
webhooks:read |
List and read webhook subscriptions |
webhooks:write |
Create, update and delete webhook subscriptions |
billing:read |
Read the credit balance, invoices and credit activity; download billing statements |
POST /templates/{id}/test-send sends a real email, so it requires both templates:write and email:send.
A request made with a key that lacks a required scope, or a request to a route that is not part of the API-key surface (for example, a customer-portal-only route), answers 403 with meta.reason: FORBIDDEN and no meta.details.code. A 403 that does carry a code (such as domain_not_verified or recipient_suppressed) is a business rule refusal, not a permissions problem.
Response envelope & errors
Every JSON response, success or error, uses the same envelope. http_code always equals the HTTP status of the response. A successful send:
{
"status": "success",
"http_code": 202,
"payload": {
"message_id": "b3b6b0f0-2f0e-4b8a-9c7e-6b6b1f0a0e2d",
"send_at": null
},
"meta": {}
}
An error keeps the same shape. payload is always an empty array and the machine-readable reason is in meta. For example, POST /transactional/send with an invalid to address:
{
"status": "error",
"http_code": 422,
"payload": [],
"meta": {
"reason": "VALIDATION_ERROR",
"validation_error": [
{ "field": "to", "message": "Invalid email" }
]
}
}
meta fields you will encounter:
| Field |
Appears on |
Meaning |
reason |
errors |
Machine-readable error class: VALIDATION_ERROR, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, GONE, RATE_LIMITED, INSUFFICIENT_CREDITS, CREDIT_PROTECTION, PAYLOAD_TOO_LARGE, DAILY_LIMIT_EXCEEDED, INTERNAL_ERROR |
validation_error[] |
422 validation errors |
One { field, message } entry per failed rule. An empty field means the message applies to the request as a whole; show it as-is |
details |
some errors |
A more specific machine-readable cause in details.code (for example credit_protection, otp_expired, invalid_state, transactional_daily_limit_exceeded), sometimes with numeric context such as a limit. Branch on details.code when it is present |
per_page |
cursor-paginated lists |
The page size applied to this response |
cursor |
cursor-paginated lists |
Opaque token for the next page. It is omitted on the last page, so its absence ends the walk. Pass it back as the cursor query parameter |
Cursor-paginated lists (domains, contacts, messages, campaigns and others) always return per_page and return cursor only when a next page exists. Lists that are not paginated, such as suppressions, custom fields, templates, webhooks and GET /contacts/{id}/lists, return the whole list with an empty meta: {}. No list returns page numbers or total counts.
Two operations do not return a JSON envelope on success:
DELETE /webhooks/{id} answers 204 No Content with an empty body.
GET /billing/statement returns a text/csv file with a Content-Disposition: attachment header. Its errors, such as a period that is too long (statement_period_too_long) or too many rows (statement_too_large), are ordinary error envelopes.
Every authenticated request is subject to rate limiting. A throttled request answers 429 with meta.reason: RATE_LIMITED, meta.details.code: rate_limited, a Retry-After header, and X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers. The limits themselves are described in Limits, and the full list of error codes in Errors.
Endpoints by tag
Email.yaml (7 operations)
Email
| Method |
Path |
Summary |
| POST |
/transactional/send |
Send a transactional email |
| DELETE |
/transactional/{message_id} |
Cancel a scheduled transactional email |
| POST |
/transactional/send-batch |
Send a batch of transactional emails |
OTP
| Method |
Path |
Summary |
| POST |
/otp/request |
Request a one-time passcode |
| POST |
/otp/verify |
Verify a one-time passcode |
Messages
| Method |
Path |
Summary |
| GET |
/messages |
Query messages |
| GET |
/messages/{id} |
Get message delivery status and events |
Contacts
| Method |
Path |
Summary |
| GET |
/contacts |
List/search contacts |
| POST |
/contacts |
Create a contact |
| GET |
/contacts/{id} |
Get a contact |
| PATCH |
/contacts/{id} |
Update a contact |
| DELETE |
/contacts/{id} |
Permanently delete a contact |
| POST |
/contacts/{id}/erase |
GDPR-erase a contact (anonymize and permanently suppress the address) |
| GET |
/contacts/{id}/lists |
List the static lists this contact belongs to |
| GET |
/contacts/{id}/export |
Export everything held about one contact (GDPR access request) |
| POST |
/contacts/import |
Bulk import contacts (async job) |
| GET |
/contacts/import/{job_id} |
Get import job status and summary |
| POST |
/events |
Record a custom event for a contact |
Lists & Segments
| Method |
Path |
Summary |
| GET |
/lists |
List static lists |
| POST |
/lists |
Create a static list |
| POST |
/lists/{id}/members |
Add/remove list members |
| GET |
/lists/{id} |
Get a single static list |
| DELETE |
/lists/{id} |
Soft-delete a static list |
| POST |
/lists/{id}/delete-with-contacts |
Delete a static list and hard-delete its exclusive members (async) |
| GET |
/lists/delete-jobs/{job_id} |
Get the status of a list-deletion job |
| GET |
/segments |
List segments |
| POST |
/segments |
Create a segment (filter) |
| GET |
/segments/{id}/preview |
Preview matching count + sample |
| GET |
/segments/{id} |
Get a single dynamic segment |
| PATCH |
/segments/{id} |
Update a dynamic segment (name and/or filter) |
| DELETE |
/segments/{id} |
Soft-delete a dynamic segment |
| POST |
/segments/preview |
Preview a filter without saving |
Suppressions
| Method |
Path |
Summary |
| GET |
/suppressions |
List suppression entries |
| POST |
/suppressions |
Add a suppression entry |
| DELETE |
/suppressions/{id} |
Remove a suppression entry |
Custom Fields
| Method |
Path |
Summary |
| GET |
/custom-fields |
List custom fields |
| POST |
/custom-fields |
Define a custom field |
| PATCH |
/custom-fields/{id} |
Update a custom field’s label |
| DELETE |
/custom-fields/{id} |
Delete a custom field |
Campaigns.yaml (31 operations)
Templates
| Method |
Path |
Summary |
| GET |
/templates |
List templates |
| POST |
/templates |
Create a template |
| GET |
/templates/{id} |
Get a template (latest version) |
| PATCH |
/templates/{id} |
Edit a template (creates a new version) |
| DELETE |
/templates/{id} |
Archive a template |
| POST |
/templates/{id}/test-send |
Send a test email |
| POST |
/templates/preview-source |
Preview unsaved template source |
| GET |
/templates/{id}/versions |
List template versions |
| GET |
/templates/{id}/versions/{version}/links |
Per-link anti-fraud results for one template version |
| POST |
/templates/{id}/render |
Render a template version with sample/contact data |
| POST |
/templates/{id}/verify |
Read the moderation verdict for one template version |
Assets
| Method |
Path |
Summary |
| GET |
/assets |
List this tenant’s stored email assets |
| POST |
/assets/presign |
Reserve an asset and get a direct-upload URL |
| POST |
/assets/{id}/confirm |
Validate an uploaded asset and publish its CDN URL |
| DELETE |
/assets/{id} |
Delete an unreferenced asset |
Campaigns
| Method |
Path |
Summary |
| GET |
/campaigns |
List campaigns |
| POST |
/campaigns |
Create a campaign |
| POST |
/campaigns/uploads |
Create an ephemeral recipient upload |
| GET |
/campaigns/{id} |
Get a campaign + stats |
| PATCH |
/campaigns/{id} |
Edit a draft campaign |
| DELETE |
/campaigns/{id} |
Permanently delete a draft campaign |
| GET |
/campaigns/{id}/series |
Time-series for a single campaign (per-day status + engagement counters) |
| POST |
/campaigns/{id}/preview |
Preview audience size and sample recipients |
| POST |
/campaigns/{id}/conflicts |
Detect recipients receiving >1 email on the campaign’s target send-day |
| POST |
/campaigns/{id}/schedule |
Schedule a blast |
| POST |
/campaigns/{id}/send |
Launch a campaign now |
| POST |
/campaigns/{id}/pause |
Pause a campaign |
| POST |
/campaigns/{id}/resume |
Resume a campaign |
| POST |
/campaigns/{id}/cancel |
Cancel a campaign |
Automations
| Method |
Path |
Summary |
| POST |
/automations/{id}/enroll |
Enroll a contact into an automation |
| GET |
/automations/{id}/enrollments |
List enrollments for an automation |
Account.yaml (26 operations)
Domains
| Method |
Path |
Summary |
| GET |
/domains |
List sending domains |
| POST |
/domains |
Register a sending domain |
| GET |
/domains/{id} |
Get domain detail + required DNS records |
| DELETE |
/domains/{id} |
Remove a domain (soft delete) |
| POST |
/domains/{id}/verify |
Trigger DNS verification |
| POST |
/domains/{id}/provider |
Change (or re-provision) the domain’s mail provider |
| GET |
/domains/{id}/warmup |
Get warmup schedule & progress |
| PATCH |
/domains/{id}/warmup |
Pause/resume/override warmup |
Senders
| Method |
Path |
Summary |
| GET |
/senders |
List sender profiles |
| POST |
/senders |
Create a sender profile |
| GET |
/senders/routes |
List source-type routes |
| PUT |
/senders/routes |
Replace the full route table |
| PATCH |
/senders/{id} |
Update a sender profile |
| DELETE |
/senders/{id} |
Delete a sender profile |
Webhooks
| Method |
Path |
Summary |
| GET |
/webhooks |
List webhook subscriptions |
| POST |
/webhooks |
Create a webhook subscription |
| GET |
/webhooks/{id} |
Get a webhook subscription |
| PATCH |
/webhooks/{id} |
Update a webhook subscription |
| DELETE |
/webhooks/{id} |
Delete a webhook subscription |
Billing
| Method |
Path |
Summary |
| GET |
/billing/balance |
Get credit balance |
| GET |
/billing/invoices |
List invoices |
| GET |
/billing/activity |
Credit activity feed |
| GET |
/billing/activity/messages |
Messages behind one activity group |
| GET |
/billing/statement |
Download a CSV billing statement |
Reports
| Method |
Path |
Summary |
| GET |
/reports/overview |
Get tenant-wide email reports overview |
Auth
| Method |
Path |
Summary |
| GET |
/me |
Current principal |
Where to go next