
# Créer des invitations en masse

`POST /v1/invitations:batch` · autorisation `invitations:write`

Crée de 1 à 100 invitations (`items`). Chaque élément suit les règles de `POST /v1/invitations` et est écrit de manière indépendante : un élément en échec n'interrompt pas les autres. La réponse est `200 OK` et `items` conserve l'ordre de la requête ; le `status` d'un élément est `201` (nouvelle invitation), `200` (une invitation en attente a été renvoyée) ou le statut HTTP de son erreur, et un élément en échec porte un `error` avec `code`, `status` et des pointeurs de champs de la forme `/items/<i>/…`. Le `accept_url` des éléments `link_only` n'est renvoyé que dans cette réponse (`Cache-Control: no-store`) ; une réponse rejouée avec `Idempotency-Key` ne contient pas de liens et renvoie `secret_redacted: true`. Un élément sans `organization_id` est une invitation à l'environnement. Un élément `email` est envoyé par e-mail ; si l'envoi d'e-mails d'invitation n'est pas configuré pour ce déploiement, il s'agit d'une erreur d'élément `501 not_implemented`, et un `application_id` qui n'existe pas dans cet environnement est une erreur d'élément `404 not_found`. Chaque invitation écrite est journalisée sous `invitation.created`.

## Requête

| Champ | Type | Obligatoire | Description |
|---|---|---|---|
| `items` | object[] | oui | 1 à 100 invitations, chacune avec les champs de `POST /v1/invitations`. |
| `Idempotency-Key` | header | non | Permet à une nouvelle tentative de renvoyer le résultat enregistré, sans liens. |

## Réponse

`200 OK` avec un résultat par élément.

```json
{
  "items": [
    {
      "status": 201,
      "invitation": {
        "id": "inv_01j9xt9v3w4y8z0a2b4c6d8e0g",
        "organization_id": "org_01j9xk3m7q8r2s4t6v8w0y2z4a",
        "email": "ada@example.com",
        "role_ids": [
          "rol_01j9xr7s1t2w6x8y0z2a4b6c8e"
        ],
        "application_id": null,
        "delivery": "link_only",
        "delivery_status": "not_sent",
        "status": "pending",
        "send_count": 1,
        "last_sent_at": "2026-10-12T09:31:00.123456Z",
        "expires_at": "2026-10-19T09:31:00.123456Z",
        "accepted_user_id": null,
        "accepted_at": null,
        "revoked_at": null,
        "created_at": "2026-10-12T09:31:00.123456Z",
        "updated_at": "2026-10-12T09:31:00.123456Z",
        "version": 1,
        "accept_url": "https://acme.eu.keenauth.app/u/login?invitation=<token>"
      }
    },
    {
      "status": 422,
      "error": {
        "code": "validation_failed",
        "status": 422,
        "errors": [
          {
            "pointer": "/items/1/email",
            "code": "invalid_value"
          }
        ]
      }
    }
  ]
}
```

## Erreurs

| HTTP | code | Quand |
|---|---|---|
| 422 | `validation_failed` | `items` est absent, vide ou comporte plus de 100 éléments. |
| 401 | `unauthenticated` | L'identifiant d'authentification est absent, invalide ou révoqué. |
| 403 | `insufficient_permissions` | L'identifiant ne possède pas l'autorisation requise. Un élément avec un rôle privilégié (`is_privileged`) échoue avec cette erreur d'élément lorsque l'identifiant ne possède pas `roles:write`. |
| 429 | `rate_limited` | La limite de débit a été dépassée ; réessayez après la période indiquée par `Retry-After`. |
| 503 | `service_unavailable` | Une dépendance est temporairement indisponible ; réessayez après la période indiquée par `Retry-After`. |

## Exemple

```bash
curl -i -X POST "https://api.eu.keenauth.com/v1/invitations:batch" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 0f6c1d2e3a4b5c6d7e8f9a0b" \
  -d '{"items":[{"organization_id":"org_01j9xk3m7q8r2s4t6v8w0y2z4a","email":"ada@example.com","delivery":"link_only"},{"organization_id":"org_01j9xk3m7q8r2s4t6v8w0y2z4a","email":"bob@example.com","delivery":"link_only"}]}'
```

## Données personnelles

Ce point de terminaison traite des données personnelles : les adhésions à une organisation et les invitations. [Données personnelles dans les API KeenAuth](/docs/policies/personal-data) décrit ce qui est stocké, pendant combien de temps les données sont conservées et comment elles sont supprimées. N'envoyez de catégories particulières de données personnelles (santé, données biométriques, religion, opinions politiques, orientation sexuelle) dans aucun champ.
