usend Docs
API endpoints

Emails

Send, batch, retrieve, list, reschedule and cancel emails.

Send an email

POST /emails

Validates, stores and queues an email. Works with full_access and sending_access keys. See Send emails for a guide.

Headers

NameTypeRequiredDescription
Idempotency-KeystringNoUp to 256 characters. See Idempotency.

Body parameters

NameTypeRequiredDescription
fromstringYes*Sender, [email protected] or Name <[email protected]>, on a verified domain. *Optional when the template has a sender.
tostring | string[]YesRecipients. Up to 50 recipients across to, cc and bcc.
subjectstringYes*A single line. *Optional when the template has a subject.
htmlstringNoHTML body. html or text is required unless you use template.
textstringNoPlain-text body.
ccstring | string[]NoCc recipients.
bccstring | string[]NoBcc recipients.
reply_tostring | string[]NoReply-to addresses. replyTo is also accepted.
headersobjectNoCustom headers, as { "Name": "value" }. Reserved headers are refused.
tagsobject[]No{ "name", "value" } pairs. ASCII letters, numbers, _ and -, up to 256 characters each.
attachmentsobject[]No{ "filename", "content", "content_type" } with base64 content. Up to 40 MB in total.
scheduled_atstringNoISO 8601 timestamp or a phrase like in 1 hour or tomorrow at 9am (UTC), up to 30 days ahead. scheduledAt is also accepted.
templateobjectNo{ "id": "<template id or alias>", "variables": { ... } }. Uses the published version of a template. Cannot be combined with html or text.
cURL
curl -X POST https://api.usend.et/emails \
  -H "Authorization: Bearer us_123456789" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": ["[email protected]"],
    "subject": "Hello world",
    "html": "<p>It works!</p>",
    "tags": [{ "name": "category", "value": "welcome" }]
  }'
Response
{ "id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c" }

Send a batch of emails

POST /emails/batch

Sends up to 100 emails in one request. The body is an array of email objects with the same fields as POST /emails, except attachments and scheduled_at. Works with full_access and sending_access keys. See Batch sending.

Headers

NameTypeRequiredDescription
x-batch-validationstringNostrict (default): one invalid email rejects the batch. permissive: valid emails are sent and invalid ones are listed in errors.
Idempotency-KeystringNoReplays the first response for 24 hours.
cURL
curl -X POST https://api.usend.et/emails/batch \
  -H "Authorization: Bearer us_123456789" \
  -H "Content-Type: application/json" \
  -d '[
    { "from": "Acme <[email protected]>", "to": ["[email protected]"], "subject": "Hi Ann", "text": "Hello" },
    { "from": "Acme <[email protected]>", "to": ["[email protected]"], "subject": "Hi Ben", "text": "Hello" }
  ]'
Response
{
  "data": [
    { "id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c" },
    { "id": "9a2c5f10-7b1e-4d0f-8a6b-2f4c1e9d3b77" }
  ]
}

With x-batch-validation: permissive, the response also has "errors": [{ "index": 1, "message": "..." }].

Retrieve an email

GET /emails/{id}

NameTypeRequiredDescription
idstringYesThe email ID (path).
cURL
curl https://api.usend.et/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c \
  -H "Authorization: Bearer us_123456789"
Response
{
  "object": "email",
  "id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
  "from": "Acme <[email protected]>",
  "to": ["[email protected]"],
  "cc": [],
  "bcc": [],
  "reply_to": [],
  "subject": "Hello world",
  "html": "<p>It works!</p>",
  "text": "",
  "tags": [{ "name": "category", "value": "welcome" }],
  "created_at": "2026-10-11T09:12:43.120Z",
  "scheduled_at": null,
  "last_event": "delivered",
  "broadcast_id": null
}

last_event is one of queued, scheduled, sent, delivered, delivery_delayed, bounced, complained, opened, clicked, failed or canceled. When sending failed, or some recipients were skipped, an error field explains why. html and text are emptied after your plan's data retention period.

List emails

GET /emails

Returns sent emails, newest first, without html and text. Paginated.

NameTypeRequiredDescription
limitintegerNo1 to 100. Default 50.
afterstringNoReturn emails older than this email ID.
beforestringNoReturn emails newer than this email ID.
cURL
curl "https://api.usend.et/emails?limit=2" \
  -H "Authorization: Bearer us_123456789"
Response
{
  "object": "list",
  "data": [
    {
      "object": "email",
      "id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
      "from": "Acme <[email protected]>",
      "to": ["[email protected]"],
      "cc": [],
      "bcc": [],
      "reply_to": [],
      "subject": "Hello world",
      "tags": [],
      "created_at": "2026-10-11T09:12:43.120Z",
      "scheduled_at": null,
      "last_event": "delivered",
      "broadcast_id": null
    }
  ],
  "has_more": true
}

List email events

GET /emails/{id}/events

Returns the full event history of an email, oldest first.

NameTypeRequiredDescription
idstringYesThe email ID (path).
cURL
curl https://api.usend.et/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/events \
  -H "Authorization: Bearer us_123456789"
Response
{
  "object": "list",
  "data": [
    { "id": "0f6a1f52-6b3e-4d1a-9a3c-5e2b8d7c4f01", "type": "email.queued", "recipient": "", "payload": {}, "created_at": "2026-10-11T09:12:43.130Z" },
    { "id": "5c2d8e7a-1b4f-4a6e-8d3c-9f0e1a2b3c4d", "type": "email.sent", "recipient": "", "payload": {}, "created_at": "2026-10-11T09:12:44.512Z" },
    {
      "id": "7e9f0a1b-2c3d-4e5f-8a9b-0c1d2e3f4a5b",
      "type": "email.delivered",
      "recipient": "[email protected]",
      "payload": { "delivery": { "response": "250 2.0.0 OK" } },
      "created_at": "2026-10-11T09:12:47.118Z"
    }
  ]
}

type is one of the email event types. payload holds the event-specific details (bounce, delivery, open, click...). Events are kept for 90 days.

Update a scheduled email

PATCH /emails/{id}

Changes the send time of an email that is still scheduled.

NameTypeRequiredDescription
idstringYesThe email ID (path).
scheduled_atstringYesThe new time: ISO 8601 or a phrase like in 1 hour, in the future and at most 30 days ahead.
cURL
curl -X PATCH https://api.usend.et/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c \
  -H "Authorization: Bearer us_123456789" \
  -H "Content-Type: application/json" \
  -d '{ "scheduled_at": "2026-10-12T09:00:00Z" }'
Response
{ "object": "email", "id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c" }

Fails with 422 if the email is no longer scheduled.

Cancel a scheduled email

POST /emails/{id}/cancel

Cancels an email that is still scheduled. Records an email.canceled event.

NameTypeRequiredDescription
idstringYesThe email ID (path).
cURL
curl -X POST https://api.usend.et/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/cancel \
  -H "Authorization: Bearer us_123456789"
Response
{ "object": "email", "id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c" }

List attachments

GET /emails/{id}/attachments

Lists the attachments of a sent email with signed download links. See Attachments.

NameTypeRequiredDescription
idstringYesThe email ID (path).
cURL
curl https://api.usend.et/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments \
  -H "Authorization: Bearer us_123456789"
Response
{
  "object": "list",
  "data": [
    {
      "object": "attachment",
      "id": "2a0c9ce0-3112-4728-976e-47ddcd16a318",
      "filename": "invoice-1042.pdf",
      "content_type": "application/pdf",
      "content_disposition": "attachment",
      "size": 48213,
      "download_url": "https://api.usend.et/attachments/eyJrIjoib3V0Ii...",
      "expires_at": "2026-10-11T10:12:43Z"
    }
  ]
}

download_url needs no API key and expires after one hour.

Retrieve an attachment

GET /emails/{id}/attachments/{attachment_id}

NameTypeRequiredDescription
idstringYesThe email ID (path).
attachment_idstringYesThe attachment ID (path).
cURL
curl https://api.usend.et/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/2a0c9ce0-3112-4728-976e-47ddcd16a318 \
  -H "Authorization: Bearer us_123456789"

Returns one attachment object, as in the list above.