Resources

Emails

.md

Send transactional email through your verified domains.

The Emails resource sends one-to-one transactional email (receipts, notifications, password resets) from any verified domain connection. Emails are queued asynchronously via AWS SQS and return 202 Accepted immediately.

Send an emailPOST/v1/emails

Permission: write.

FieldTypeRequiredDescription
fromstringYesSender email. The domain must be configured and verified for outbound email in Connections.
from_namestringNoSender display name.
tostring[]YesArray of recipient email addresses. The maximum per request depends on your plan (see Limits below).
subjectstringYesEmail subject line.
htmlstringConditionalHTML email body. Provide html OR text (or both).
textstringConditionalPlain text email body.
ccstring[]NoCC recipients.
bccstring[]NoBCC recipients.
reply_tostringNoReply-to address. Applied to immediate sends only; scheduled emails (send_at) are currently sent without a Reply-To header, so replies go to the from address.
metadataobjectNoArbitrary JSON metadata stored with the email.
track_opensbooleanNoEnable open tracking pixel (requires html). Default: false.
track_clicksbooleanNoRewrite links for click tracking (requires html). Default: false.
type_sentstringNotransactional (default) or broadcast. Determines the SQS queue.
filesarrayNoAttachments: [{ fileName, fileData (base64), contentType }]. Max 5 files per email, 10 MB per file.
send_atstringNoISO 8601 date to schedule the email. Must be in the future and at most 30 days ahead. If omitted, the email sends immediately.
terminal
Bash
01curl https://api.tickos.dev/v1/emails \
02 -H 'Authorization: Bearer sk_your_api_key' \
03 -H 'Content-Type: application/json' \
04 -d '{
05 "from": "support@yourdomain.com",
06 "from_name": "Acme Support",
07 "to": ["jane@example.com"],
08 "subject": "Your invoice is ready",
09 "html": "<p>Hi Jane, your invoice is attached.</p>",
10 "track_opens": true,
11 "send_at": "2026-07-15T10:00:00-06:00"
12 }'
UTF-8 · LF · Bashtickos.dev

Returns 202 with { id, status: "queued", queued_at } for immediate emails, or { id, status: "scheduled", scheduled_at } for scheduled emails. Scheduled emails are processed by a cron job every minute.

At send time, scheduled emails are checked again: if the account is suspended, the send limits are reached or the primary recipient is suppressed, the email is marked blocked; if the sending domain is no longer verified, it is marked failed.

Attachments

Each entry in files needs fileName, fileData (base64-encoded content) and contentType. Up to 5 files per email and 10 MB per file (more files, or a larger file, returns 400). Attachments are stored in your account storage: if the upload would exceed your plan storage quota, the request returns 429 with the limit-exceeded body described below.

Limits

Every send is checked against your plan before it is accepted:

PlanMax recipients in to per request
Free10
Starter50
Pro100
Enterprise200

The monthly email quota of your plan, plus daily and hourly sending limits, are also enforced. When a recipient count, send limit or storage quota is exceeded, the API returns 429 with this body:

response.json
JSON
01{
02 "error": "Limit exceeded",
03 "message": "Hourly email limit reached (30/30). Please wait before sending more emails.",
04 "current": 30,
05 "limit": 30,
06 "percentage": 100,
07 "recommended_plan": "starter"
08}
UTF-8 · LF · JSONtickos.dev

If your account is suspended, sends return 403 with { "error": "Account suspended. Please contact support." }.

Suppressed recipients

Before sending, every address in to is checked against its contact record. A recipient is rejected when the contact has 3 or more recorded bounces (metadata.bounce_count) or is marked undeliverable (metadata.email_deliverable set to "false"). The whole request is rejected with HTTP 422 -- no email is sent to any recipient:

response.json
JSON
01{
02 "error": "Recipient blocked",
03 "message": "Recipient jane@example.com has too many bounces (3)."
04}
UTF-8 · LF · JSONtickos.dev

Only the to addresses are checked; cc and bcc addresses are not.

List scheduled emailsGET/v1/emails/scheduled

Permission: read. Returns emails with status "scheduled", ordered by scheduled_at ascending. Query params: limit (default 50, max 100) and offset.

Each item also includes cc_addresses, bcc_addresses, created_at, metadata, type_sent, track_opens and track_clicks.
JSON
01{
02 "data": [
03 {
04 "id": "email_abc123",
05 "from_address": "support@yourdomain.com",
06 "to_address": "jane@example.com",
07 "subject": "Your invoice is ready",
08 "status": "scheduled",
09 "scheduled_at": "2026-07-15T16:00:00.000Z",
10 "...": "..."
11 }
12 ],
13 "total": 1,
14 "limit": 50,
15 "offset": 0
16}
UTF-8 · LF · JSONtickos.dev

Reschedule an emailPATCH/v1/emails/{id}/schedule

Permission: write. Change the send_at date of a scheduled email. The new date must be in the future and at most 30 days ahead. Only works on emails with status "scheduled" (other statuses return 400). Returns { id, status: "scheduled", scheduled_at, message }.

terminal
Bash
01curl -X PATCH https://api.tickos.dev/v1/emails/email_abc123/schedule \
02 -H 'Authorization: Bearer sk_your_api_key' \
03 -H 'Content-Type: application/json' \
04 -d '{ "send_at": "2026-07-20T09:00:00-06:00" }'
UTF-8 · LF · Bashtickos.dev

Cancel a scheduled emailDELETE/v1/emails/{id}/schedule

Permission: write. Cancels a scheduled email before it is sent. Only works on emails with status "scheduled" (other statuses return 400).

The response is { id, status: "cancelled", message: "Scheduled email cancelled successfully" }. Note that the stored email is marked as failed with error_message "Cancelled by user": a later GET /v1/emails/{id} returns status "failed", not "cancelled".

Get email statusGET/v1/emails/{id}

Permission: read. Returns the current delivery state of a single email, including bounce details when applicable. Useful for polling after a send. The response contains id, status, from, to (primary recipient), cc, subject, type_sent, created_at and the fields below.

FieldTypeDescription
statusstringscheduled, queued, processing, sent, delivered, bounced, failed or blocked. Cancelled scheduled emails show failed.
queued_atstring | nullWhen the email entered the send queue.
scheduled_atstring | nullWhen the email is scheduled to send (scheduled emails).
delivered_atstring | nullDelivery confirmation timestamp.
bounced_atstring | nullBounce timestamp, if any.
error_messagestring | nullFailure reason when status is failed (for example "Cancelled by user").
bounceobject | null{ type, sub_type, recipients } when the email bounced.

Send from a templatePOST/v1/emails/template

Permission: write. Sends an email using a saved template with variable substitution. Template sends are always immediate and transactional: this endpoint does not accept send_at, files, text or type_sent. The same plan limits, suppression checks and 403/422/429 responses as POST /v1/emails apply.

FieldTypeRequiredDescription
template_idstringYesTemplate ID (e.g. etpl_xxxxxxxx). Unknown IDs return 404.
tostring[]YesArray of recipient email addresses.
variablesobjectNoCustom variable values as strings: { "order_id": "A-1001" }. See precedence below.
fromstringNoOverride the template sender email. Required if the template has none.
from_namestringNoOverride the template sender name.
subjectstringNoOverride the template subject. Required if the template has none.
reply_tostringNoOverride the template reply-to address.
ccstring[]NoCC recipients.
bccstring[]NoBCC recipients.
track_opensbooleanNoDefault: false.
track_clicksbooleanNoDefault: false.
metadataobjectNoStored with the email. TickOS adds template_id and template_name to it.
terminal
Bash
01curl https://api.tickos.dev/v1/emails/template \
02 -H 'Authorization: Bearer sk_your_api_key' \
03 -H 'Content-Type: application/json' \
04 -d '{
05 "template_id": "etpl_xxxxxxxx",
06 "to": ["jane@example.com"],
07 "variables": { "order_id": "A-1001", "plan_name": "Pro" }
08 }'
UTF-8 · LF · Bashtickos.dev

Returns 202 with { id, status: "queued", template_id, template_name, queued_at }.

Template variables

Variables use {{key}} syntax with no spaces inside the braces ({{ order_id }} is not replaced). Values are HTML-escaped and replaced in both the HTML body and the subject. Variables are resolved in this order:

  1. System variables: name, first_name, email and phone. They are always resolved from the contact record of the first address in to (empty string if unknown; email falls back to the recipient address).
  2. Custom variables from the variables object in the request.
  3. Default values defined in the template.
Reserved names
Because system variables are resolved first, custom values for name, first_name, email or phone are ignored. Use different keys (for example customer_name) for your own values. Variables with no value at any level are left as-is in the output. All recipients receive the content resolved for the first address in to.

Email statisticsGET/v1/emails/stats

Permission: read. Returns delivery, tracking and health metrics.

Query paramDescription
start_dateISO 8601 date. Only emails created on or after this date are counted. Default: all time.
include_timelineSet to true to add a timeline object: { days: [{ date, received, sent, broadcast }] }, a daily series (UTC) of inbound, transactional and campaign emails.

The response contains total, sent, received, byStatus { delivered, sent, pending, failed }, tracking { emailsWithTracking, uniqueOpens, uniqueClicks, openRate, clickRate } and health (last 7 days: totalSent7d, totalDelivered7d, totalBounced7d, totalComplained7d, bounceRate, complaintRate, deliveryRate, plus hard/soft bounce breakdown fields that are null when not available).

Suppressions
Recipients whose contact has 3 or more recorded bounces, or is marked undeliverable, are rejected. Sending to such an address in to returns HTTP 422 and nothing is sent. See Suppressed recipients above.