> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lekalao.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Transactional e-mails

> Order confirmations, invoices, password resets: one call per e-mail.

A transactional e-mail goes to one person because of what they have just done. It needs no list and no marketing consent, and it is logged and followed like a campaign. See [Overview](/transactional/overview).

## With a template

The cleanest way: the content lives in Lekalao, the application sends only the data. Create a template named `order-confirmation` ([Transactional templates](/transactional/templates)), then:

```bash theme={null}
curl -X POST https://lekalao.example.com/api/v1/transactional-mails/send \
  -H "Authorization: Bearer $LEKALAO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Idempotency-Key: order-2026-00481-confirmation" \
  -d '{
    "template": "order-confirmation",
    "to": ["ada@example.com"],
    "locale": "en",
    "variables": {
      "customer": { "name": "Ada" },
      "order": {
        "number": "2026-00481",
        "total": "12,500 FCFA",
        "items": ["Wholemeal bread", "Croissant x4"]
      }
    }
  }'
```

In the template:

```html theme={null}
<p>Hello {{ customer.name }},</p>
<p>Your order <strong>{{ order.number }}</strong> is confirmed.</p>
<ul>
    {% for item in order.items %}
    <li>{{ item }}</li>
    {% endfor %}
</ul>
<p>Total: {{ order.total }}</p>
```

Variables are escaped; loops run over lists of plain values. The whole syntax is in [Personalisation](/content/personalization).

## Without a template

Send the HTML as it is:

```bash theme={null}
curl -X POST https://lekalao.example.com/api/v1/transactional-mails/send \
  -H "Authorization: Bearer $LEKALAO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "to": ["ada@example.com"],
    "subject": "Your September invoice",
    "html": "<p>Hello Ada, your invoice is attached.</p>",
    "from_email": "invoices@mybakery.example",
    "from_name": "The Bakery",
    "attachments": [
      { "name": "invoice-2026-09.pdf", "content": "JVBERi0xLjcKJcfsj6IK…", "mime": "application/pdf" }
    ]
  }'
```

## The fields

| Field                                 |                                                                       |
| ------------------------------------- | --------------------------------------------------------------------- |
| `template`                            | The name of a transactional template.                                 |
| `html`                                | The body, when there is no template. One of the two is required.      |
| `subject`                             | The subject. With a template, it replaces the template's own.         |
| `to`, `cc`, `bcc`                     | Arrays of addresses. Without `to`, the template's default recipients. |
| `variables`                           | A free object, which fills the template.                              |
| `locale`                              | Which language version of the template to send. See below.            |
| `from_email`, `from_name`, `reply_to` | The sender; otherwise the template's, otherwise the team's.           |
| `mailer`                              | The name of a configured sending provider, to force the route.        |
| `attachments`                         | 10 at most: `name`, `content` in base64, `mime` optional.             |

## In several languages

A template can have one version per language ([Languages](/content/languages)). `locale` picks it:

| `locale` sent                         | Version used                                                 |
| ------------------------------------- | ------------------------------------------------------------ |
| absent                                | The base version.                                            |
| `pt-BR`, and the template has `pt-BR` | `pt-BR`.                                                     |
| `pt-BR`, the template only has `pt`   | `pt`.                                                        |
| `pt`, the template only has `pt-BR`   | The base version: a language never takes a regional version. |
| a language with no version            | The base version.                                            |

Pass your customer's language as your application knows it: Lekalao falls back on its own.

## The answer

`201` once the provider has taken the e-mail:

```json theme={null}
{
    "data": {
        "id": "e3b0c442-98fc-4c14-9a1e-2f6b7d8a9c10",
        "template": "order-confirmation",
        "subject": "Order 2026-00481 confirmed",
        "from": "hello@mybakery.example",
        "to": ["ada@example.com"],
        "cc": [],
        "bcc": [],
        "status": "sent",
        "failure_reason": null,
        "opens": 0,
        "clicks": 0,
        "sent_at": "2026-09-17T10:14:03+00:00",
        "created_at": "2026-09-17T10:14:02+00:00"
    }
}
```

`502` when the provider refused it: the e-mail is logged with `status: failed` and the reason in `failure_reason`. It is `failed` too when the plan's monthly allowance is used up.

`422` when the sender is not allowed, when neither `template` nor `html` is given, or when there is no recipient at all.

<Note>
  Sending is synchronous: the answer comes back once the provider has
  replied. Call the API from a background job of your application, not during
  your customer's own request.
</Note>

## Follow and send again

| Call                                                                                    |                                                                                                      |
| --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `GET /transactional-mails?template=order-confirmation&status=failed&to=ada@example.com` | The log, filtered.                                                                                   |
| `GET /transactional-mails/{id}`                                                         | One e-mail, with opens and clicks.                                                                   |
| `POST /transactional-mails/{id}/resend`                                                 | Sends it again unchanged; a new e-mail is created. `409` when the template did not keep the content. |

Bounces and complaints arrive through the `mail.bounced` and `mail.complaint` webhooks.

## Other roads

* A **Laravel** application can keep `Mail::to()->send()`: see [Laravel transport](/developers/laravel-transport).
* Software that only speaks **SMTP**: see [SMTP relay](/developers/smtp-relay).
