Documentation
Everything you need to send transactional email with LayerSend — from your first API call to webhooks, domain authentication, and suppression management.
Introduction
LayerSend is a transactional email API built on AWS SES. You authenticate with an API key, POST a JSON payload to /api/v1/emails, and we handle delivery, DKIM signing, open/click tracking, bounce handling, and event webhooks.
The base URL for all API requests is:
All request and response bodies are JSON. All timestamps are ISO 8601 in UTC.
Quickstart
Send your first email in under two minutes.
1 — Get an API key
Go to API Keys in the dashboard and create a key with Send permission. Your key starts with ls_live_.
2 — Send via cURL
Response
Authentication
Every request must include your API key in the Authorization header as a Bearer token.
Keys support three permission levels, set at creation time:
| Permission | Scopes | Description |
|---|---|---|
| Send only | send | Can POST /v1/emails only. Cannot read data. |
| Full access | send, emails:read | Can send emails and read email records, events, metrics. |
| Read only | emails:read | Can read email records and events. Cannot send. |
You can also restrict a key to specific sending domains — a key scoped to postpeak.app cannot send from any other domain, even if other domains are verified on your workspace.
Send an email
Request body
| Parameter | Type | Description | |
|---|---|---|---|
| from | string | required | Sender address, e.g. hello@yourdomain.com. |
| from_name | string | optional | Friendly display name shown in the recipient's inbox, e.g. "Acme Support". Rendered as "Acme Support <hello@yourdomain.com>". |
| to | string | string[] | required | Recipient address or array of addresses. |
| subject | string | required | Email subject line (max 998 chars). Required unless using a template that includes it. |
| html | string | optional | HTML body. At least one of html, text, or template is required. |
| text | string | optional | Plain-text fallback body. |
| template | string (UUID) | optional | ID of a saved template. Cannot be combined with html/text. |
| data | object | optional | Key/value pairs injected into template {{placeholders}}. |
| cc | string | string[] | optional | CC recipients. |
| bcc | string | string[] | optional | BCC recipients. |
| reply_to | string | optional | Reply-to address. |
| tags | Record<string,string> | optional | Arbitrary key/value tags for filtering in logs and webhooks. |
| headers | object | optional | Custom email headers as key/value pairs. |
| scheduled_at | string (ISO 8601) | optional | Schedule delivery for a future UTC time. Must be 5 min – 30 days from now. |
| idempotency_key | string | optional | Unique string (max 255 chars) to prevent duplicate sends. Valid for 24 hours. |
Example — plain HTML
Success response — 200
Error responses
| Status | Code | Meaning |
|---|---|---|
| 401 | UNAUTHORIZED | Missing or invalid API key. |
| 403 | DOMAIN_NOT_ALLOWED | The API key is restricted to specific domains and the from domain is not permitted. |
| 403 | DOMAIN_NOT_VERIFIED | The from domain is not verified on this workspace. |
| 422 | VALIDATION_ERROR | Request body failed validation. Check the errors array. |
| 429 | RATE_LIMITED | Too many requests. Slow down and retry. |
| 503 | SES_SANDBOX_MODE | This workspace's underlying AWS SES account is in sandbox mode, which only allows sending to individually-verified recipients regardless of sender domain verification. Request SES production access to lift this. |
| 503 | SEND_FAILED | The send failed for a reason other than sandbox mode - check the error message for details. |
Templates
Templates let you define reusable HTML email designs in the dashboard and reference them by their UUID in API calls. Use {{variable_name}} placeholders in your template HTML, then pass values via the data field.
template with html or text in the same request — the API will return a 422 error.Scheduled sends
Pass a scheduled_at ISO 8601 UTC timestamp to queue a message for future delivery. The time must be between 5 minutes and 30 days from now.
Idempotency
Pass a unique idempotency_key string to guarantee an email is sent at most once, even if you retry the request. If a request with the same key was already accepted within the last 24 hours, the original response is returned and no new email is sent.
Add a domain
Go to Domains → Add domain. Enter the domain you want to send from (e.g. mail.yourdomain.com) and copy the three DNS records shown into your DNS provider.
LayerSend polls DNS automatically. Once all records verify you'll see a green checkmark and can immediately send from any address on that domain.
DNS records
Three TXT records are required per domain:
| Record | Type | Purpose |
|---|---|---|
| DKIM | TXT | Cryptographically signs outgoing messages so receivers can verify authenticity. |
| SPF | TXT | Authorises LayerSend's mail servers to send on your domain's behalf. |
| DMARC | TXT | Tells receiving servers what to do with mail that fails SPF or DKIM checks. |
All records are generated automatically — copy them directly from the dashboard. DKIM keys rotate periodically with no action required from you.
Event types
LayerSend tracks the following lifecycle events for every email:
| Event | Description |
|---|---|
| email.queued | Email accepted and queued for delivery. |
| email.sent | Email dispatched to the sending infrastructure. |
| email.delivered | Receiving mail server confirmed delivery. |
| email.opened | Recipient opened the email (detected via tracking pixel in HTML body). |
| email.clicked | Recipient clicked a tracked link. |
| email.bounced | Delivery failed permanently. The address is automatically added to the suppression list. |
| email.complained | Recipient marked the email as spam. Address is suppressed automatically. |
| email.unsubscribed | Recipient clicked the List-Unsubscribe link. |
Webhooks
Add a webhook endpoint in Webhooks and select which events to receive. LayerSend will POST a signed JSON payload to your URL within seconds of each event.
Payload shape
2xx status within 10 seconds to acknowledge receipt. Failed deliveries are retried up to 5 times with exponential backoff.POST /v1/emails
Send a transactional email. See Send an email for full parameter docs.
GET /v1/emails/:id
Retrieve a sent email and its current delivery status.
GET /v1/emails/:id/events
List all delivery events for a specific email — opens, clicks, bounces, etc.
Templates API
Create and manage reusable email templates. Templates are identified by UUID.
| Method | Path | Description |
|---|---|---|
| GET | /v1/templates | List all templates in the workspace. |
| POST | /v1/templates | Create a new template. |
| GET | /v1/templates/:id | Get a single template by ID. |
| PATCH | /v1/templates/:id | Update an existing template. |
| DELETE | /v1/templates/:id | Delete a template permanently. |
Template fields
| Field | Type | Description | |
|---|---|---|---|
| name | string | required | Template display name (max 255 chars). |
| subject | string | required | Default email subject. Overridden by the subject field in the send request. |
| html_body | string | required | HTML body. Supports {{variable}} placeholders. |
| text_body | string | optional | Plain-text fallback. |
| description | string | optional | Internal notes (max 1000 chars, not sent to recipients). |
Domains API
| Method | Path | Description |
|---|---|---|
| GET | /v1/domains | List all domains in the workspace. |
| POST | /v1/domains | Add a domain. Returns the DNS records to set. |
| GET | /v1/domains/:id | Get a domain's verification status and DNS records. |
| DELETE | /v1/domains/:id | Remove a domain from the workspace. |
Suppressions API
Suppressed addresses never receive email from your workspace. Hard bounces and spam complaints are added automatically. You can also manually suppress addresses.
| Method | Path | Description |
|---|---|---|
| GET | /v1/suppressions | List suppressed addresses. Supports search and pagination. |
| POST | /v1/suppressions | Manually add an address. Reason: bounce | complaint | unsubscribe | manual. |
| DELETE | /v1/suppressions/:id | Remove an address — they become eligible to receive emails again. |
Questions or missing something? info@layersend.com