Send
Send transactional emails to individual recipients using templates and dynamic variables.
The Send endpoint delivers a single transactional email immediately. Use this for password resets, order confirmations, welcome emails, and other one-off messages that are triggered by user actions.
For bulk or automated sending, use Sequences instead.
Send transactional email
POST /api/sendSends a single email to a recipient using a pre-defined template. The template is rendered with the provided variables and delivered via your verified domain.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
to | string | Yes | Recipient email address. Must match an existing contact. |
template | string | Yes | The ID of the template to use. |
variables | object | No | Key-value pairs to inject into the template's Liquid variables. |
from | string | No | Override the from address. Must be on a verified domain. Defaults to the tenant's default from address. |
ignoreUnsubscribe | boolean | No | If true, sends even if the contact has unsubscribed. Use only for legally required messages (e.g. receipts, security alerts). Defaults to false. |
Response
On success returns 200 OK with the SES message ID, a fixed status of "sent", and the internal send record ID. There is no success flag — a failure is returned as an error response, not a body with status.
{
"messageId": "0100018f...-a1b2c3d4-...",
"status": "sent",
"sendId": "snd_01H9..."
}Delivery outcomes after hand-off to SES (delivered, bounced, complained) are tracked on the send record and surfaced via the Sends API and webhooks, not in this response.
Errors
Suppression and unsubscribe are re-checked at send time. If the contact has unsubscribed or is suppressed (bounce/complaint) and ignoreUnsubscribe is false, the send is refused.
| Code | Description |
|---|---|
VALIDATION_ERROR | Missing to or template, invalid email format, template disabled, or the contact is unsubscribed/suppressed and ignoreUnsubscribe is false. |
CONTACT_NOT_FOUND | No contact exists for the to address. |
TEMPLATE_NOT_FOUND | The specified template does not exist. |
DOMAIN_NOT_FOUND | The sending domain is not registered. |
DOMAIN_NOT_VERIFIED | The sending domain is not verified. |
FORBIDDEN | Tenant sending is paused, or the recipient is not on the sandbox whitelist. |
Examples
curl -X POST https://api.kraiter.com/api/send \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "alice@example.com",
"template": "password-reset",
"variables": {
"resetUrl": "https://app.example.com/reset?token=abc123",
"expiresIn": "24 hours"
}
}'const send = await kraiter.send({
to: "alice@example.com",
template: "password-reset",
variables: {
resetUrl: "https://app.example.com/reset?token=abc123",
expiresIn: "24 hours",
},
});Sending to suppressed contacts
By default, the API rejects sends to contacts who have unsubscribed or been suppressed. For legally required messages (receipts, security alerts, account notifications), set ignoreUnsubscribe to true:
curl -X POST https://api.kraiter.com/api/send \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "alice@example.com",
"template": "security-alert",
"variables": { "action": "Password changed" },
"ignoreUnsubscribe": true
}'const send = await kraiter.send({
to: "alice@example.com",
template: "security-alert",
variables: { action: "Password changed" },
ignoreUnsubscribe: true,
});Use ignoreUnsubscribe sparingly. Sending marketing content to suppressed contacts violates anti-spam regulations and can damage your sender reputation.
Template variables
Variables are injected into the template using Liquid syntax. For example, a template with {{ resetUrl }} will be replaced with the value of variables.resetUrl. If a required variable is missing, the template renders with an empty string for that placeholder.
See the Templates reference for details on template creation and variable declaration.