Email

Sending email

How to send a transactional email via the API, idempotency, and reading send logs.

Send an email

POST /comms/v1/send
x-tenant-id: {your-tenant-id}
Content-Type: application/json
 
{
  "channel": "email",
  "to": "recipient@example.com",
  "subject": "Your order #1234 is confirmed",
  "content": {
    "html": "<p>Hi! Your order has been placed.</p>",
    "text": "Hi! Your order has been placed."
  }
}

Response (200):

{
  "id": "re_abc123xyz",
  "status": "sent"
}

The id is the provider message ID (from Resend). Save it if you need to correlate delivery events later.

Request fields

Field Required Description
channel Yes Must be "email"
to Yes Recipient email address
subject Recommended Email subject line
content.html Recommended HTML body
content.text Recommended Plain text fallback
from No Override the sending address for this email only
idempotencyKey No Prevents duplicate sends (see below)
metadata No Arbitrary key-value pairs stored with the log (not sent)
emailHeaders No Extra headers forwarded verbatim to the provider

At least one of content.html or content.text should be provided. Sending without either results in a blank email.

From address resolution

If you don't pass a from field, the service builds the from address automatically:

  1. If you have a Vlozi alias claimed — uses Your Name <alias@vlozi.app>
  2. If you have a sender name configured — uses Your Name <hello@vlozi.app>
  3. Otherwise — uses the platform default Vlozi <hello@vlozi.app>

To always send from your branded address, configure your sender settings (see Sender settings) before sending.

Idempotency

Pass an idempotencyKey to guarantee at-most-once delivery:

POST /comms/v1/send
Content-Type: application/json
 
{
  "channel": "email",
  "to": "customer@example.com",
  "subject": "Password reset",
  "content": { "text": "Your reset code is 123456" },
  "idempotencyKey": "pwd-reset-user_abc-2026-06-28T10:00:00Z"
}

If the same idempotencyKey is sent again, the service returns the original result immediately without calling the email provider again. The key is stored with the send log — choose a key that uniquely identifies the logical send (user ID + action + timestamp).

Credit usage

Each email costs 0.2 credits (5 emails per credit). Credits are checked before the send. If your balance is insufficient, the request returns 402:

{
  "error": "INSUFFICIENT_CREDITS",
  "balance": 0,
  "required": 1
}

Send logs

View the last 50 emails sent from your account:

GET /comms/v1/logs
x-tenant-id: {your-tenant-id}

Response:

{
  "logs": [
    {
      "id": "log_01j...",
      "channel": "email",
      "recipient": "customer@example.com",
      "sender": "Acme <hello@vlozi.app>",
      "subject": "Your order is confirmed",
      "status": "sent",
      "provider": "resend",
      "sentAt": "2026-06-28T10:01:02Z",
      "createdAt": "2026-06-28T10:01:01Z"
    }
  ]
}

Status values:

Status Meaning
queued Accepted but not yet dispatched
sent Left our system; awaiting provider confirmation
delivered Provider confirmed delivery to inbox
failed Delivery failed (bounce, network error, invalid address)

For failed sends, the error field in the log contains the reason.

Dashboard

Communication → Email Logs — searchable list of all outbound emails, with status badges and delivery timestamps. Click any row to see the full log entry and delivery events.

Communication · EmailEdit on GitHub