> ## 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.

# Conventions

> Format, identifiants, pagination, limites de débit, idempotence et CORS.

## Adresse et format

* Toutes les routes sont sous `https://lekalao.example.com/api/v1`.
* Envoyez et recevez du JSON : `Content-Type: application/json` et `Accept: application/json`.
* Une ressource seule est enveloppée dans `data` : `{"data": {…}}`.
* Les dates sont en ISO 8601 avec fuseau : `2026-09-17T09:12:44+00:00`. Sans fuseau, une date envoyée est lue dans le fuseau de l'installation (UTC par défaut).
* Les montants sont des entiers dans la plus petite unité de la devise : `1250` = 12,50 €. Pour le franc CFA, qui n'a pas de subdivision, `15000` = 15 000 FCFA.

## Identifiants

Chaque ressource est désignée par son `id`, qui est un uuid et jamais un numéro de ligne. Les adresses se construisent avec : `/api/v1/lists/{id}/subscribers`.

Les tags peuvent aussi être désignés par leur **nom** là où c'est naturel : `tags` d'un abonné, règles de segment.

## Pagination

Les listes sont paginées :

| Paramètre  | Défaut                | Maximum |
| ---------- | --------------------- | ------- |
| `page`     | 1                     |         |
| `per_page` | 25 (50 pour les tags) | 100     |

```json theme={null}
{
  "data": [ … ],
  "links": {
    "first": "https://lekalao.example.com/api/v1/lists/9d5c…/subscribers?page=1",
    "last": "https://lekalao.example.com/api/v1/lists/9d5c…/subscribers?page=52",
    "prev": null,
    "next": "https://lekalao.example.com/api/v1/lists/9d5c…/subscribers?page=2"
  },
  "meta": { "current_page": 1, "from": 1, "last_page": 52, "per_page": 25, "to": 25, "total": 1284 }
}
```

Suivez `links.next` jusqu'à ce qu'il vaille `null`.

## Limite de débit

Chaque **jeton** peut faire 120 appels par minute (réglable par l'installation). Chaque réponse dit où vous en êtes :

```http theme={null}
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1789637580
```

Au-delà, la réponse est `429` avec `Retry-After` en secondes :

```json theme={null}
{ "message": "Too many requests. Try again in 23 seconds." }
```

Attendez `Retry-After` secondes avant de reprendre. Pour inscrire beaucoup de monde, utilisez le [lot](/fr/developers/subscribers#inscrire-en-lot) : un appel pour 1 000 adresses.

## Idempotence

Un appel qui expire vous laisse dans le doute : la commande est-elle passée ? Ajoutez un en-tête `Idempotency-Key` à vos `POST` et `PUT` et renvoyez le même appel sans risque :

```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 "Idempotency-Key: commande-2026-00481-confirmation" \
  -d '{"template": "confirmation-commande", "to": ["ada@example.com"], "variables": {"order": "2026-00481"}}'
```

| Situation                                           | Réponse                                                                                        |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| Première fois                                       | Traité normalement. La réponse porte `Idempotency-Key`.                                        |
| Même clé, même route, même corps, dans les 24 h     | La première réponse, rejouée à l'identique, avec `Idempotent-Replay: true`. Rien n'est refait. |
| Même clé pendant que le premier appel tourne encore | `409`. Réessayez un peu plus tard.                                                             |
| Même clé, autre route ou autre corps                | `422` : une clé sert à une seule requête.                                                      |
| Même clé après 24 h                                 | `422` : la clé a expiré, envoyez-en une nouvelle.                                              |
| Premier appel en erreur `5xx`                       | Rien n'est retenu : le renvoi est traité comme neuf.                                           |

Choisissez une clé qui décrit l'opération (numéro de commande + action) ou un UUID généré avant le premier essai. 255 caractères au plus. Les clés sont propres à chaque équipe.

## CORS

Les routes `api/*` et `subscribe/*` acceptent les appels venant de n'importe quelle origine, sans cookies. Les en-têtes de débit et d'idempotence sont lisibles par le navigateur.

<Warning>
  CORS ouvert ne veut pas dire qu'il faut appeler l'API depuis un navigateur :
  le jeton y serait visible de tous. Seul le [formulaire
  d'inscription](/fr/developers/forms) est fait pour ça.
</Warning>
