Docs
← Back to dashboard

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:

https://layersend.com/api/v1

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

curl -X POST https://layersend.com/api/v1/emails \ -H "Authorization: Bearer ls_live_xxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "from": "hello@yourdomain.com", "to": "recipient@example.com", "subject": "Hello from LayerSend", "html": "<p>It works!</p>" }'

Response

{ "id": "em_3d25742f-51b4-4342-a465-77407b34469a", "status": "queued" }
💡You can send from any address while testing. Once you verify a domain, emails are DKIM-signed and deliverability improves significantly.

Authentication

Every request must include your API key in the Authorization header as a Bearer token.

Authorization: Bearer ls_live_xxxxxxxxxxxx

Keys support three permission levels, set at creation time:

PermissionScopesDescription
Send onlysendCan POST /v1/emails only. Cannot read data.
Full accesssend, emails:readCan send emails and read email records, events, metrics.
Read onlyemails:readCan 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.

⚠️Never expose API keys in client-side code or public repositories. Store them in environment variables.

Send an email

POST/v1/emails

Request body

ParameterTypeDescription
fromstringrequiredSender address, e.g. hello@yourdomain.com.
from_namestringoptionalFriendly display name shown in the recipient's inbox, e.g. "Acme Support". Rendered as "Acme Support <hello@yourdomain.com>".
tostring | string[]requiredRecipient address or array of addresses.
subjectstringrequiredEmail subject line (max 998 chars). Required unless using a template that includes it.
htmlstringoptionalHTML body. At least one of html, text, or template is required.
textstringoptionalPlain-text fallback body.
templatestring (UUID)optionalID of a saved template. Cannot be combined with html/text.
dataobjectoptionalKey/value pairs injected into template {{placeholders}}.
ccstring | string[]optionalCC recipients.
bccstring | string[]optionalBCC recipients.
reply_tostringoptionalReply-to address.
tagsRecord<string,string>optionalArbitrary key/value tags for filtering in logs and webhooks.
headersobjectoptionalCustom email headers as key/value pairs.
scheduled_atstring (ISO 8601)optionalSchedule delivery for a future UTC time. Must be 5 min – 30 days from now.
idempotency_keystringoptionalUnique string (max 255 chars) to prevent duplicate sends. Valid for 24 hours.

Example — plain HTML

{ "from": "team@yourdomain.com", "to": "user@example.com", "subject": "Your receipt", "html": "<h1>Thanks for your order!</h1>", "text": "Thanks for your order!", "tags": { "category": "transactional", "shop": "eu" } }

Success response — 200

{ "id": "em_3d25742f-51b4-4342-a465-77407b34469a", "status": "queued" }

Error responses

StatusCodeMeaning
401UNAUTHORIZEDMissing or invalid API key.
403DOMAIN_NOT_ALLOWEDThe API key is restricted to specific domains and the from domain is not permitted.
403DOMAIN_NOT_VERIFIEDThe from domain is not verified on this workspace.
422VALIDATION_ERRORRequest body failed validation. Check the errors array.
429RATE_LIMITEDToo many requests. Slow down and retry.
503SES_SANDBOX_MODEThis 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.
503SEND_FAILEDThe 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.

{ "from": "team@yourdomain.com", "to": "user@example.com", "subject": "Your order is confirmed", "template": "3f2a1b4c-...", "data": { "first_name": "Olivia", "order_id": "4921", "total": "$84.20" } }
ℹ️You cannot combine 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.

{ "from": "team@yourdomain.com", "to": "user@example.com", "subject": "Your weekly digest", "html": "<p>Here's what happened this week…</p>", "scheduled_at": "2026-06-01T09:00:00Z" }

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.

{ "from": "team@yourdomain.com", "to": "user@example.com", "subject": "Reset your password", "html": "<p>Click here to reset…</p>", "idempotency_key": "pwd-reset-user-12345-1717286400" }

Add a domain

Go to DomainsAdd 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:

RecordTypePurpose
DKIMTXTCryptographically signs outgoing messages so receivers can verify authenticity.
SPFTXTAuthorises LayerSend's mail servers to send on your domain's behalf.
DMARCTXTTells 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:

EventDescription
email.queuedEmail accepted and queued for delivery.
email.sentEmail dispatched to the sending infrastructure.
email.deliveredReceiving mail server confirmed delivery.
email.openedRecipient opened the email (detected via tracking pixel in HTML body).
email.clickedRecipient clicked a tracked link.
email.bouncedDelivery failed permanently. The address is automatically added to the suppression list.
email.complainedRecipient marked the email as spam. Address is suppressed automatically.
email.unsubscribedRecipient 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

{ "event": "email.delivered", "created_at": "2026-05-26T10:00:05Z", "data": { "email_id": "em_3d25742f-51b4-4342-a465-77407b34469a", "to": "recipient@example.com", "subject": "Hello from LayerSend", "tags": { "category": "transactional" } } }
💡Respond with any 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

GET/v1/emails/:id

Retrieve a sent email and its current delivery status.

curl https://layersend.com/api/v1/emails/em_3d25742f-51b4-4342-a465-77407b34469a \ -H "Authorization: Bearer ls_live_xxxxxxxxxxxx"

GET /v1/emails/:id/events

GET/v1/emails/:id/events

List all delivery events for a specific email — opens, clicks, bounces, etc.

curl https://layersend.com/api/v1/emails/em_3d25742f-51b4-4342-a465-77407b34469a/events \ -H "Authorization: Bearer ls_live_xxxxxxxxxxxx"

Templates API

Create and manage reusable email templates. Templates are identified by UUID.

MethodPathDescription
GET/v1/templatesList all templates in the workspace.
POST/v1/templatesCreate a new template.
GET/v1/templates/:idGet a single template by ID.
PATCH/v1/templates/:idUpdate an existing template.
DELETE/v1/templates/:idDelete a template permanently.

Template fields

FieldTypeDescription
namestringrequiredTemplate display name (max 255 chars).
subjectstringrequiredDefault email subject. Overridden by the subject field in the send request.
html_bodystringrequiredHTML body. Supports {{variable}} placeholders.
text_bodystringoptionalPlain-text fallback.
descriptionstringoptionalInternal notes (max 1000 chars, not sent to recipients).

Domains API

MethodPathDescription
GET/v1/domainsList all domains in the workspace.
POST/v1/domainsAdd a domain. Returns the DNS records to set.
GET/v1/domains/:idGet a domain's verification status and DNS records.
DELETE/v1/domains/:idRemove 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.

MethodPathDescription
GET/v1/suppressionsList suppressed addresses. Supports search and pagination.
POST/v1/suppressionsManually add an address. Reason: bounce | complaint | unsubscribe | manual.
DELETE/v1/suppressions/:idRemove an address — they become eligible to receive emails again.

Questions or missing something? info@layersend.com