API reference
Base URL https://api-staging.avelto.dev. Every request needs an Authorization header with a bearer key, av_live_… or av_test_…. Bodies and responses are JSON with snake_case fields. Field tables on this page are generated from the same schemas the API validates with.
Authentication
Create keys in the dashboard. The prefix tells you the mode: av_live_ keys send real email, av_test_ keys run the pipeline without sending.
Scopes
A key carries a list of scopes, and a route it does not have one for answers 403 naming the scope it needed. Keys created before scopes existed hold all of them, and a key created without naming any still does — narrowing is the deliberate act, not the default.
| Scope | Covers |
|---|---|
emails:send | Send email |
emails:read | Read the email log |
domains:manage | Add and remove domains |
webhooks:manage | Manage webhook endpoints |
suppressions:manage | Change the suppression list |
templates:manage | Create and edit templates |
account:manage | Export the account's data and erase recipients |
The split worth knowing is emails:send against emails:read. A key that can send and cannot read the log back is the one to put in an application server, and the dashboard offers it as a preset.
The mode is a boundary on reads as well as sends. A test key sees test emails and their events and deliveries; a live email is a 404, and ?mode=live does not change that. It also gets a 403 on the calls that touch live sending: deleting a domain, adding or removing a suppression, exporting the account and erasing a recipient. A live key reads both modes. See Test mode.
curl https://api-staging.avelto.dev/v1/emails \
-H "Authorization: Bearer av_live_..."Pagination
Lists take limit (1 to 100, default 20) and cursor, and return { data, next_cursor }. Pass next_cursor back as cursor; it is null on the last page.
Rate limits
Between 10 and 50 requests a second per key depending on plan (see Plans and limits). Over that, the API returns 429 rate_limited with a Retry-After header. New accounts can send 100 emails a day for their first 7 days.
Emails
Send, fetch, list and cancel emails. The key's mode decides the mode of the emails it creates, and also what it can read: a test key sees test emails only, and a live email is a 404 to it.
/v1/emailsSend an emailSend an Idempotency-Key header to make retries safe. A replay returns the existing id with status 200.
Provide html, text or both. At most 50 recipients across to, cc and bcc.
Errors: 403 domain_not_verified, 403 sandbox_recipient_not_allowed, 403 account_paused, 422 recipient_suppressed, 429 plan_limit, 429 rate_limited.
Request body
| Field | Type | Description |
|---|---|---|
fromrequired | string | Sender. a@b.com or Name <a@b.com>. The domain must be verified on your account, or be your sandbox domain. |
torequired | string | string[] | One recipient or a list. At most 50 recipients across to, cc and bcc. |
ccoptional | string | string[] | Carbon-copy recipients. |
bccoptional | string | string[] | Blind-carbon-copy recipients. |
reply_tooptional | string | Address replies go to. |
subjectoptional | string | Subject line. Line breaks are rejected. |
htmloptional | string | HTML body. Provide html, text or both. |
textoptional | string | Plain-text body. Provide html, text or both. |
headersoptional | object<string, string> | Extra headers. Names reserved for the envelope, MIME structure or signing are rejected. |
tagsoptional | string[] | Up to 10 tags of letters, numbers, _ - : . for filtering and reporting. |
attachmentsoptional | object[] | Up to 10 files, 7 MB in total after decoding. |
attachments[].filenamerequired | string | File name shown to the recipient. No quotes or slashes. |
attachments[].contentoptional | string | File contents, base64-encoded. |
attachments[].urloptional | string (url) | Endpoint to POST events to. Must be https in production. |
attachments[].content_typeoptional | string | MIME type, for example application/pdf. |
template_idoptional | string (uuid) | |
template_slugoptional | string | |
variablesoptional | object<string, string | number | boolean | null> | |
scheduled_atoptional | string (ISO 8601) | Send at this time instead of now. Must be in the future and within 30 days. |
unsubscribe_urloptional | string (url) |
Response 201
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
/v1/emails/batchSend up to 100 emailsEach message is validated, limited and queued exactly as a single send is. results[i] lines up with messages[i].
200 when every message was accepted, 422 when none was, 207 when it was mixed.
An Idempotency-Key makes the whole batch replayable. Each message counts separately against your plan and rate limit.
Request body
| Field | Type | Description |
|---|---|---|
messagesrequired | object[] | |
messages[].fromrequired | string | Sender. a@b.com or Name <a@b.com>. The domain must be verified on your account, or be your sandbox domain. |
messages[].torequired | string | string[] | One recipient or a list. At most 50 recipients across to, cc and bcc. |
messages[].ccoptional | string | string[] | Carbon-copy recipients. |
messages[].bccoptional | string | string[] | Blind-carbon-copy recipients. |
messages[].reply_tooptional | string | Address replies go to. |
messages[].subjectoptional | string | Subject line. Line breaks are rejected. |
messages[].htmloptional | string | HTML body. Provide html, text or both. |
messages[].textoptional | string | Plain-text body. Provide html, text or both. |
messages[].headersoptional | object<string, string> | Extra headers. Names reserved for the envelope, MIME structure or signing are rejected. |
messages[].tagsoptional | string[] | Up to 10 tags of letters, numbers, _ - : . for filtering and reporting. |
messages[].attachmentsoptional | object[] | Up to 10 files, 7 MB in total after decoding. |
messages[].attachments[].filenamerequired | string | File name shown to the recipient. No quotes or slashes. |
messages[].attachments[].contentoptional | string | File contents, base64-encoded. |
messages[].attachments[].urloptional | string (url) | Endpoint to POST events to. Must be https in production. |
messages[].attachments[].content_typeoptional | string | MIME type, for example application/pdf. |
messages[].template_idoptional | string (uuid) | |
messages[].template_slugoptional | string | |
messages[].variablesoptional | object<string, string | number | boolean | null> | |
messages[].scheduled_atoptional | string (ISO 8601) | Send at this time instead of now. Must be in the future and within 30 days. |
messages[].unsubscribe_urloptional | string (url) |
Response 200
| Field | Type | Description |
|---|---|---|
results | discriminatedunion[] | |
accepted | integer | |
failed | integer |
/v1/emailsList emailsNewest first. Pass next_cursor back as cursor for the next page.
Query
| Field | Type | Description |
|---|---|---|
limitoptional | integer | Page size, 1 to 100. Defaults to 20. |
cursoroptional | string | Cursor from a previous page. |
statusoptional | "queued" | "scheduled" | "sent" | "delivered" | "bounced" | "complained" | "failed" | "cancelled" | Only emails in this status. |
tagoptional | string | Only emails carrying this tag. |
modeoptional | "live" | "test" | Filter by mode. A live key defaults to live and may ask for test; a test key always gets test, whatever this says. |
qoptional | string |
Response 200
| Field | Type | Description |
|---|---|---|
data | object[] | Items on this page. |
data[].id | string (uuid) | Unique id. |
data[].mode | "live" | "test" | live or test, taken from the API key that created the email. |
data[].from | string | Sender. a@b.com or Name <a@b.com>. The domain must be verified on your account, or be your sandbox domain. |
data[].to | string[] | One recipient or a list. At most 50 recipients across to, cc and bcc. |
data[].cc | string[] | Carbon-copy recipients. |
data[].bcc | string[] | Blind-carbon-copy recipients. |
data[].reply_to | string | null | Address replies go to. |
data[].subject | string | Subject line. Line breaks are rejected. |
data[].tags | string[] | Up to 10 tags of letters, numbers, _ - : . for filtering and reporting. |
data[].status | "queued" | "scheduled" | "sent" | "delivered" | "bounced" | "complained" | "failed" | "cancelled" | Current state. |
data[].scheduled_at | string (ISO 8601) | null | Send at this time instead of now. Must be in the future and within 30 days. |
data[].created_at | string (ISO 8601) | When the record was created. |
data[].updated_at | string (ISO 8601) | When the record last changed. |
data[].match | object | null | |
data[].match.field | "recipient" | "subject" | "message_id" | "email_id" | |
data[].match.value | string | Record value. |
next_cursor | string | null | Pass as cursor to fetch the next page. Null on the last page. |
/v1/emails/:idGet an emailIncludes the bodies, headers, attachment metadata and every event so far.
Response 200
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
mode | "live" | "test" | live or test, taken from the API key that created the email. |
from | string | Sender. a@b.com or Name <a@b.com>. The domain must be verified on your account, or be your sandbox domain. |
to | string[] | One recipient or a list. At most 50 recipients across to, cc and bcc. |
cc | string[] | Carbon-copy recipients. |
bcc | string[] | Blind-carbon-copy recipients. |
reply_to | string | null | Address replies go to. |
subject | string | Subject line. Line breaks are rejected. |
tags | string[] | Up to 10 tags of letters, numbers, _ - : . for filtering and reporting. |
status | "queued" | "scheduled" | "sent" | "delivered" | "bounced" | "complained" | "failed" | "cancelled" | Current state. |
scheduled_at | string (ISO 8601) | null | Send at this time instead of now. Must be in the future and within 30 days. |
created_at | string (ISO 8601) | When the record was created. |
updated_at | string (ISO 8601) | When the record last changed. |
match | object | null | |
match.field | "recipient" | "subject" | "message_id" | "email_id" | |
match.value | string | Record value. |
html | string | null | HTML body. Provide html, text or both. |
text | string | null | Plain-text body. Provide html, text or both. |
headers | object<string, string> | Extra headers. Names reserved for the envelope, MIME structure or signing are rejected. |
unsubscribe_url | string | null | |
idempotency_key | string | null | |
attachments | object[] | Up to 10 files, 7 MB in total after decoding. |
attachments[].filename | string | File name shown to the recipient. No quotes or slashes. |
attachments[].content_type | string | MIME type, for example application/pdf. |
attachments[].size | integer | Decoded size in bytes. |
domain_id | string (uuid) | null | The verified domain the email was sent from, or null for the sandbox domain. |
ses_message_id | string | null | Provider message id once the email has been handed off. |
error | string | null | Failure reason, when status is failed. |
events | object[] | Every state change for this email, oldest first. |
events[].id | string (uuid) | Unique id. |
events[].type | "email.queued" | "email.scheduled" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.rejected" | "email.failed" | "email.cancelled" | Event type. |
events[].payload | object<string, any> | Event-specific details. |
events[].occurred_at | string (ISO 8601) | When the event happened. |
/v1/emails/:id/cancelCancel a scheduled email409 not_scheduled unless the email's status is scheduled.
Response 200
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
status | "cancelled" | Current state. |
Domains
Sending domains and the DNS records that verify them.
/v1/domainsAdd a domain409 conflict if the domain is already added. 403 plan_limit when your plan's domain limit is reached.
Request body
| Field | Type | Description |
|---|---|---|
namerequired | string | Domain name, for example mail.example.com. |
Response 201
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
name | string | Domain name, for example mail.example.com. |
region | string | Region the domain identity lives in. |
status | "pending" | "verified" | "failed" | Current state. |
dns_records | object[] | Records to publish before the domain can verify. |
dns_records[].type | "CNAME" | "TXT" | "MX" | Event type. |
dns_records[].name | string | Domain name, for example mail.example.com. |
dns_records[].value | string | Record value. |
dns_records[].purpose | "dkim" | "spf" | "dmarc" | What the record is for. |
health | "unknown" | "healthy" | "action_needed" | |
health_changed_at | string (ISO 8601) | null | |
dns_checks | object[] | null | |
dns_checks[].type | "CNAME" | "TXT" | "MX" | Event type. |
dns_checks[].name | string | Domain name, for example mail.example.com. |
dns_checks[].value | string | Record value. |
dns_checks[].purpose | "dkim" | "spf" | "dmarc" | What the record is for. |
dns_checks[].id | string | Unique id. |
dns_checks[].state | "found" | "missing" | "mismatch" | |
dns_checks[].found | string | null | |
dns_checked_at | string (ISO 8601) | null | |
created_at | string (ISO 8601) | When the record was created. |
/v1/domainsList domainsResponse 200
| Field | Type | Description |
|---|---|---|
data | object[] | Items on this page. |
data[].id | string (uuid) | Unique id. |
data[].name | string | Domain name, for example mail.example.com. |
data[].region | string | Region the domain identity lives in. |
data[].status | "pending" | "verified" | "failed" | Current state. |
data[].dns_records | object[] | Records to publish before the domain can verify. |
data[].dns_records[].type | "CNAME" | "TXT" | "MX" | Event type. |
data[].dns_records[].name | string | Domain name, for example mail.example.com. |
data[].dns_records[].value | string | Record value. |
data[].dns_records[].purpose | "dkim" | "spf" | "dmarc" | What the record is for. |
data[].health | "unknown" | "healthy" | "action_needed" | |
data[].health_changed_at | string (ISO 8601) | null | |
data[].dns_checks | object[] | null | |
data[].dns_checks[].type | "CNAME" | "TXT" | "MX" | Event type. |
data[].dns_checks[].name | string | Domain name, for example mail.example.com. |
data[].dns_checks[].value | string | Record value. |
data[].dns_checks[].purpose | "dkim" | "spf" | "dmarc" | What the record is for. |
data[].dns_checks[].id | string | Unique id. |
data[].dns_checks[].state | "found" | "missing" | "mismatch" | |
data[].dns_checks[].found | string | null | |
data[].dns_checked_at | string (ISO 8601) | null | |
data[].created_at | string (ISO 8601) | When the record was created. |
/v1/domains/:idGet a domainRe-checks the DNS records on every call and updates status.
Response 200
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
name | string | Domain name, for example mail.example.com. |
region | string | Region the domain identity lives in. |
status | "pending" | "verified" | "failed" | Current state. |
dns_records | object[] | Records to publish before the domain can verify. |
dns_records[].type | "CNAME" | "TXT" | "MX" | Event type. |
dns_records[].name | string | Domain name, for example mail.example.com. |
dns_records[].value | string | Record value. |
dns_records[].purpose | "dkim" | "spf" | "dmarc" | What the record is for. |
health | "unknown" | "healthy" | "action_needed" | |
health_changed_at | string (ISO 8601) | null | |
dns_checks | object[] | null | |
dns_checks[].type | "CNAME" | "TXT" | "MX" | Event type. |
dns_checks[].name | string | Domain name, for example mail.example.com. |
dns_checks[].value | string | Record value. |
dns_checks[].purpose | "dkim" | "spf" | "dmarc" | What the record is for. |
dns_checks[].id | string | Unique id. |
dns_checks[].state | "found" | "missing" | "mismatch" | |
dns_checks[].found | string | null | |
dns_checked_at | string (ISO 8601) | null | |
created_at | string (ISO 8601) | When the record was created. |
/v1/domains/:idRemove a domainResponse 204
Empty body.
Templates
A stored subject and body with {{variables}} in them. Send one by passing template_id or template_slug instead of a body. Needs the templates:manage scope.
/v1/templatesCreate a templateThe slug is derived from the name unless you set one. 409 conflict if a slug you chose is taken.
Request body
| Field | Type | Description |
|---|---|---|
namerequired | string | Domain name, for example mail.example.com. |
subjectrequired | string | Subject line. Line breaks are rejected. |
htmloptional | string | HTML body. Provide html, text or both. |
textoptional | string | Plain-text body. Provide html, text or both. |
slugoptional | string |
Response 201
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
name | string | Domain name, for example mail.example.com. |
slug | string | |
subject | string | Subject line. Line breaks are rejected. |
html | string | null | HTML body. Provide html, text or both. |
text | string | null | Plain-text body. Provide html, text or both. |
variables | string[] | |
version | integer | |
created_at | string (ISO 8601) | When the record was created. |
updated_at | string (ISO 8601) | When the record last changed. |
/v1/templatesList templatesResponse 200
| Field | Type | Description |
|---|---|---|
data | object[] | Items on this page. |
data[].id | string (uuid) | Unique id. |
data[].name | string | Domain name, for example mail.example.com. |
data[].slug | string | |
data[].subject | string | Subject line. Line breaks are rejected. |
data[].html | string | null | HTML body. Provide html, text or both. |
data[].text | string | null | Plain-text body. Provide html, text or both. |
data[].variables | string[] | |
data[].version | integer | |
data[].created_at | string (ISO 8601) | When the record was created. |
data[].updated_at | string (ISO 8601) | When the record last changed. |
/v1/templates/:idGet a templateResponse 200
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
name | string | Domain name, for example mail.example.com. |
slug | string | |
subject | string | Subject line. Line breaks are rejected. |
html | string | null | HTML body. Provide html, text or both. |
text | string | null | Plain-text body. Provide html, text or both. |
variables | string[] | |
version | integer | |
created_at | string (ISO 8601) | When the record was created. |
updated_at | string (ISO 8601) | When the record last changed. |
/v1/templates/:idUpdate a templateOnly the fields you pass change. null clears a body part. Every save keeps a version.
Request body
| Field | Type | Description |
|---|---|---|
nameoptional | string | Domain name, for example mail.example.com. |
slugoptional | string | |
subjectoptional | string | Subject line. Line breaks are rejected. |
htmloptional | string | null | HTML body. Provide html, text or both. |
textoptional | string | null | Plain-text body. Provide html, text or both. |
Response 200
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
name | string | Domain name, for example mail.example.com. |
slug | string | |
subject | string | Subject line. Line breaks are rejected. |
html | string | null | HTML body. Provide html, text or both. |
text | string | null | Plain-text body. Provide html, text or both. |
variables | string[] | |
version | integer | |
created_at | string (ISO 8601) | When the record was created. |
updated_at | string (ISO 8601) | When the record last changed. |
/v1/templates/:idDelete a templateResponse 204
Empty body.
/v1/templates/:id/versionsList versionsNewest first. Every save is kept.
Response 200
| Field | Type | Description |
|---|---|---|
data | object[] | Items on this page. |
data[].version | integer | |
data[].name | string | Domain name, for example mail.example.com. |
data[].subject | string | Subject line. Line breaks are rejected. |
data[].html | string | null | HTML body. Provide html, text or both. |
data[].text | string | null | Plain-text body. Provide html, text or both. |
data[].created_by | string | null | |
data[].created_at | string (ISO 8601) | When the record was created. |
/v1/templates/:id/restoreRestore a versionWrites the old version forward as a new one, so the history stays append-only.
Request body
| Field | Type | Description |
|---|---|---|
versionrequired | integer |
Response 200
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
name | string | Domain name, for example mail.example.com. |
slug | string | |
subject | string | Subject line. Line breaks are rejected. |
html | string | null | HTML body. Provide html, text or both. |
text | string | null | Plain-text body. Provide html, text or both. |
variables | string[] | |
version | integer | |
created_at | string (ISO 8601) | When the record was created. |
updated_at | string (ISO 8601) | When the record last changed. |
Suppressions
Addresses this account will not send to.
/v1/suppressionsList suppressionsQuery
| Field | Type | Description |
|---|---|---|
limitoptional | integer | Page size, 1 to 100. Defaults to 20. |
cursoroptional | string | Cursor from a previous page. |
Response 200
| Field | Type | Description |
|---|---|---|
data | object[] | Items on this page. |
data[].id | string (uuid) | Unique id. |
data[].email_address | string | null | The suppressed address. |
data[].reason | "bounce" | "complaint" | "manual" | Why the address was suppressed. |
data[].created_at | string (ISO 8601) | When the record was created. |
next_cursor | string | null | Pass as cursor to fetch the next page. Null on the last page. |
/v1/suppressionsAdd a suppressionStored with reason manual. 409 conflict if already suppressed.
Request body
| Field | Type | Description |
|---|---|---|
email_addressrequired | string (email) | The suppressed address. |
Response 201
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
email_address | string | null | The suppressed address. |
reason | "bounce" | "complaint" | "manual" | Why the address was suppressed. |
created_at | string (ISO 8601) | When the record was created. |
/v1/suppressions/:emailRemove a suppressionURL-encode the address: @ becomes %40.
Response 204
Empty body.
Webhooks
Endpoints that receive signed event POSTs, and the log of every delivery attempt.
/v1/webhooksCreate an endpointThe secret is returned only here. In production the URL must be https and public.
Request body
| Field | Type | Description |
|---|---|---|
urlrequired | string (url) | Endpoint to POST events to. Must be https in production. |
eventsoptional | ("email.queued" | "email.scheduled" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.rejected" | "email.failed" | "email.cancelled")[] | Event types to deliver. Defaults to all eight: email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.rejected, email.failed and email.cancelled. Defaults to ["email.sent","email.delivered","email.delivery_delayed","email.bounced","email.complained","email.rejected","email.failed","email.cancelled"]. |
Response 201
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
url | string | Endpoint to POST events to. Must be https in production. |
events | ("email.queued" | "email.scheduled" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.rejected" | "email.failed" | "email.cancelled")[] | Event types to deliver. Defaults to all eight: email.sent, email.delivered, email.delivery_delayed, email.bounced, email.complained, email.rejected, email.failed and email.cancelled. |
enabled | boolean | Whether deliveries are being attempted. |
created_at | string (ISO 8601) | When the record was created. |
secret | string | Signing secret. Returned once, at creation. |
/v1/webhooksList endpointsResponse 200
| Field | Type | Description |
|---|---|---|
data | object[] | Items on this page. |
data[].id | string (uuid) | Unique id. |
data[].url | string | Endpoint to POST events to. Must be https in production. |
data[].events | ("email.queued" | "email.scheduled" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.rejected" | "email.failed" | "email.cancelled")[] | Every state change for this email, oldest first. |
data[].enabled | boolean | Whether deliveries are being attempted. |
data[].created_at | string (ISO 8601) | When the record was created. |
/v1/webhooks/:idGet an endpointResponse 200
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
url | string | Endpoint to POST events to. Must be https in production. |
events | ("email.queued" | "email.scheduled" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.rejected" | "email.failed" | "email.cancelled")[] | Every state change for this email, oldest first. |
enabled | boolean | Whether deliveries are being attempted. |
created_at | string (ISO 8601) | When the record was created. |
/v1/webhooks/:idDelete an endpointResponse 204
Empty body.
/v1/webhooks/:id/deliveriesList deliveriesQuery
| Field | Type | Description |
|---|---|---|
limitoptional | integer | Page size, 1 to 100. Defaults to 20. |
cursoroptional | string | Cursor from a previous page. |
Response 200
| Field | Type | Description |
|---|---|---|
data | object[] | Items on this page. |
data[].id | string (uuid) | Unique id. |
data[].endpoint_id | string (uuid) | The webhook endpoint this delivery belongs to. |
data[].email_event_id | string (uuid) | null | The event being delivered. |
data[].event_type | "email.queued" | "email.scheduled" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.rejected" | "email.failed" | "email.cancelled" | Type of the event being delivered. |
data[].email_id | string (uuid) | null | The email the event belongs to. |
data[].status | "pending" | "delivered" | "failed" | Current state. |
data[].attempts | integer | Delivery attempts so far, up to 8. |
data[].last_error | string | null | Error from the most recent failed attempt. |
data[].response_code | integer | null | |
data[].duration_ms | integer | null | |
data[].is_test | boolean | |
data[].replay_of | string (uuid) | null | |
data[].created_at | string (ISO 8601) | When the record was created. |
next_cursor | string | null | Pass as cursor to fetch the next page. Null on the last page. |
/v1/webhooks/:id/deliveries/:deliveryId/retryRetry a deliveryQueues the delivery again and returns it.
Response 200
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Unique id. |
endpoint_id | string (uuid) | The webhook endpoint this delivery belongs to. |
email_event_id | string (uuid) | null | The event being delivered. |
event_type | "email.queued" | "email.scheduled" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.rejected" | "email.failed" | "email.cancelled" | Type of the event being delivered. |
email_id | string (uuid) | null | The email the event belongs to. |
status | "pending" | "delivered" | "failed" | Current state. |
attempts | integer | Delivery attempts so far, up to 8. |
last_error | string | null | Error from the most recent failed attempt. |
response_code | integer | null | |
duration_ms | integer | null | |
is_test | boolean | |
replay_of | string (uuid) | null | |
created_at | string (ISO 8601) | When the record was created. |
Account
The account as an integrator sees it: what the key can do, the sandbox and its allowed recipients, and what is set up.
/v1/accountDescribe the accountAny scope; API key only. Read this first when integrating: it says what exists and what the next step is.
Response 200
| Field | Type | Description |
|---|---|---|
account | object | |
account.id | string (uuid) | Unique id. |
account.name | string | Domain name, for example mail.example.com. |
account.plan | "free" | "pro" | "growth" | "enterprise" | |
account.plan_step | string | null | |
key | object | |
key.mode | "live" | "test" | live or test, taken from the API key that created the email. |
key.scopes | string[] | |
sandbox | object | |
sandbox.domain | string | |
sandbox.recipients | string[] | |
sandbox.simulator | object | |
sandbox.simulator.delivered | string | |
sandbox.simulator.bounced | string | |
sandbox.simulator.complained | string | |
domains | object[] | |
domains[].id | string (uuid) | Unique id. |
domains[].name | string | Domain name, for example mail.example.com. |
domains[].status | "pending" | "verified" | "failed" | Current state. |
webhooks | object[] | |
webhooks[].id | string (uuid) | Unique id. |
webhooks[].url | string | Endpoint to POST events to. Must be https in production. |
webhooks[].enabled | boolean | Whether deliveries are being attempted. |
templates | object[] | |
templates[].id | string (uuid) | Unique id. |
templates[].slug | string | |
templates[].name | string | Domain name, for example mail.example.com. |
docs_url | string |
Data rights
Answer a data subject access request or an erasure request. Both need the `account:manage` scope and a live key.
/v1/account/exportExport everything held for the accountNeeds account:manage and a live key.
One JSON document, not paginated: account, users, keys, domains, emails with bodies, events, suppressions and webhooks.
Response 200
Empty body.
/v1/recipients/eraseErase a recipientNeeds account:manage and a live key.
Removes the address from emails, events and stored bodies, keeping only a hashed suppression entry so it is never sent to again.
Request body
| Field | Type | Description |
|---|---|---|
email_addressrequired | string (email) | The suppressed address. |
Response 200
| Field | Type | Description |
|---|---|---|
recipient_hash | string | |
emails_redacted | integer | |
emails_deleted | integer | |
events_redacted | integer | |
suppressed | boolean |
Webhook payload
The body POSTed to your endpoints, signed with Avelto-Signature: t=<unix seconds>,v1=<hex> where v1 is the HMAC-SHA256 of <t>.<body>. See Webhooks.
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Event id. The same id is sent again on every retry; use it to de-duplicate. |
type | "email.queued" | "email.scheduled" | "email.sent" | "email.delivered" | "email.delivery_delayed" | "email.bounced" | "email.complained" | "email.rejected" | "email.failed" | "email.cancelled" | Event type. |
created_at | string (ISO 8601) | When the record was created. |
data | object | Items on this page. |
data.email_id | string (uuid) | The email the event belongs to. |
data.mode | "live" | "test" | live or test, taken from the API key that created the email. |
data.from | string | Sender. a@b.com or Name <a@b.com>. The domain must be verified on your account, or be your sandbox domain. |
data.to | string[] | One recipient or a list. At most 50 recipients across to, cc and bcc. |
data.subject | string | Subject line. Line breaks are rejected. |
data.tags | string[] | Up to 10 tags of letters, numbers, _ - : . for filtering and reporting. |
data.status | string | The email's status after this event. |
data.details | object<string, any> | Event-specific details such as bounce type or diagnostic code. |
Errors
Every error response has this shape. The code is stable; the message is for people.
| Field | Type | Description |
|---|---|---|
error | object | Failure reason, when status is failed. |
error.code | "validation_error" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "rate_limited" | "internal_error" | "sandbox_recipient_not_allowed" | "domain_not_verified" | "recipient_suppressed" | "not_scheduled" | "plan_limit" | "account_paused" | "account_suspended" | One of the codes below. |
error.message | string | Human-readable explanation. |
error.details | any | Extra context, for example the failing fields of a validation error. |
| Code | Status | When |
|---|---|---|
validation_error | 400 | The body or query failed validation. details lists the issues. |
unauthorized | 401 | Missing, malformed or revoked API key. |
forbidden | 403 | A key without the scope for the call (the message names it), or a test key on a live-only action such as deleting a domain. |
not_found | 404 | No such email, domain, template, template version, webhook, delivery or suppression on this account. |
conflict | 409 | The resource already exists: the domain or suppression is already added, or a template slug you chose is already taken. |
rate_limited | 429 | More than the per-key request rate (between 10 and 50 a second depending on plan). Honour Retry-After. |
internal_error | 500 | Something went wrong on our side. Safe to retry with an idempotency key. |
sandbox_recipient_not_allowed | 403 | Sending from the sandbox domain to anyone other than the account owner's verified email. |
domain_not_verified | 403 | from uses a domain that is not added and verified on this account. |
recipient_suppressed | 422 | A recipient is on the suppression list. details.suppressed lists the addresses. |
not_scheduled | 409 | Cancel was called on an email whose status is not scheduled. |
plan_limit | 429 / 403 | Monthly email limit or first-week daily cap reached (429), or the plan's domain limit reached (403). |
account_paused | 403 | Sending is paused on the account, usually after a high bounce or complaint rate. |
account_suspended | 403 | The account has been suspended by us. The message says why, and the dashboard has a button to write to us. |