← Documentation

Send an email

POST /api/v1/email/send takes a template id, a recipient and the values of its variables.

POST https://sentfa.st/api/v1/email/send
Content-Type: application/json
x-api-key: YOUR_API_KEY

Request body

FieldTypeRequiredDescription
idstringYesId of the email template to send, for example em_a1b2c3d4. It must belong to the project that owns the key.
tostringYesRecipient address.
ccstring[]NoAddresses in copy.
paramsobjectNoValues for the template variables. Keys are the variable names, values are strings.
attachmentsobject[]NoFiles to attach. See below.
{
  "id": "em_a1b2c3d4",
  "to": "customer@example.com",
  "cc": ["billing@example.com"],
  "params": {
    "user_name": "Alex",
    "invoice_number": "2026-0184"
  }
}

Variables

The subject and the body of a template can contain placeholders written as {{variable_name}}. At send time each one is replaced with the matching key from params.

Keys you do not send are left as they are in the template, so an invoice email that expects {{invoice_number}} and does not receive it will go out with the placeholder visible. Send every variable the template declares.

Attachments

Each attachment needs a filename and the file itself, given either as a public URL or as base64:

{
  "id": "em_a1b2c3d4",
  "to": "customer@example.com",
  "attachments": [
    { "filename": "invoice.pdf", "url": "https://example.com/invoices/2026-0184.pdf" },
    { "filename": "terms.txt", "base64": "VGVybXMgYW5kIGNvbmRpdGlvbnM=", "contentType": "text/plain" }
  ]
}

A URL must be absolute and use http or https; anything else is rejected with 400. The file also has to be reachable from the internet without authentication — a URL that cannot be fetched makes the send fail.

Response

{ "ok": true, "message": "Email \"em_a1b2c3d4\" queued/sent to customer@example.com" }

ok: true means SentFast handed the message to the delivery provider and wrote the send to your logs. It is not a guarantee that the recipient's mail server accepted it — that is why the log exists.

Every failure uses the same shape with ok: false and an error string. See Errors for the full list.

Full example

// Node.js — no dependencies
async function sendWelcomeEmail(email, name) {
  const res = await fetch('https://sentfa.st/api/v1/email/send', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': process.env.SENTFAST_API_KEY,
    },
    body: JSON.stringify({
      id: 'em_a1b2c3d4',
      to: email,
      params: { user_name: name },
    }),
  });

  const data = await res.json();
  if (!data.ok) throw new Error(`SentFast: ${data.error}`);
  return data;
}