API v1 Stable

Send a transactional email

Accepts a template-based email request and queues it for delivery.

POST Stable

Send a transactional email

/v1/send

Use this endpoint for password resets, verification emails, app notifications, billing messages, and other transactional events. A successful response means the message has been accepted and queued, not that SES has already delivered it.

Request

Name Type Required Description Example
Authorization string Yes Bearer API key for the EmailsDone environment. Bearer ed_...
Idempotency-Key string No Optional retry key. Reusing the same key returns the original accepted message for 24 hours.
Max 120 characters
password-reset-user-123-2026-05-26
templateId string Yes Template identifier, for example password-reset or verify-email. password-reset
to email Yes Recipient email address. user@example.com
templateVersion string No Optional template version such as v1. If omitted, EmailsDone uses the latest published version for the template. v1
from email No Optional From address. For custom sending domains, the domain must match the effective project or environment sending domain. If omitted, EmailsDone uses the environment From Email setting, then the project From Email setting, then notifications@domain. notifications@example.com
fromName string No Optional display name for the From header. If omitted, EmailsDone uses the environment setting, then the project setting.
Max 120 characters
Acme App
replyTo email No Optional Reply To email address. If omitted, EmailsDone uses the environment setting, then the project setting. support@example.com
data object Yes Template data. Required and optional fields are derived from the selected template blocks. {"actionButton":{"label":"Reset password","url":"https://app.example.com/reset/token"}}

curl

curl -X POST 'https://api.emailsdone.dev/v1/send' \
  -H 'Authorization: Bearer ed_...' \
  -H 'Content-Type: application/json' \
  -d '{
  "templateId": "password-reset",
  "templateVersion": "v1",
  "to": "user@example.com",
  "from": "notifications@example.com",
  "fromName": "Acme App",
  "replyTo": "support@example.com",
  "data": {
    "actionButton": {
      "label": "Reset password",
      "url": "https://app.example.com/reset/token"
    }
  }
}'

Response

Name Type Required Description Example
ok boolean Yes True when the request was accepted. true
status string Yes Message acceptance state. accepted
messageId string Yes Message record identifier for later operational lookup. msg_abc123
idempotent boolean Yes True when the response is for an earlier request with the same Idempotency-Key. false
{
  "ok": true,
  "status": "accepted",
  "messageId": "msg_abc123",
  "idempotent": false
}

Errors

StatusCodeMessage
400 invalid_request Expected templateId, to, and data.
400 invalid_from_address From address failed validation.
400 invalid_from_name From name failed validation.
400 invalid_reply_to Reply To failed validation.
400 invalid_template_data Template data failed validation.
401 missing_api_key Authorization bearer token is missing.
401 invalid_api_key API key is invalid.
402 trial_expired The trial can no longer send email.
403 api_key_revoked API key has been revoked.
403 monthly_quota_exceeded Tenant has exhausted the monthly quota.
403 app_paused Sending is paused for the app.
403 app_blocked Sending is blocked for the app.
403 recipient_complained Recipient has complained.
403 recipient_unsubscribed Recipient is unsubscribed from notifications.
403 sending_domain_not_ready The configured sending domain is not verified yet.
403 from_domain_not_allowed From address does not match the configured sending domain.
404 project_not_found Project not found for API key.
404 environment_not_found Environment not found for API key.
404 template_not_found Template was not found.
404 template_version_not_found Requested template version was not found.
405 method_not_allowed Only POST is allowed.
500 internal Unexpected server error.

Notes

  • Use Idempotency-Key for password resets, billing emails, and other retry-prone workflows.
  • Do not send HTML. Choose a templateId and pass the required template data.
  • Treat accepted as queued. Delivery and bounce state are recorded asynchronously.