# Erreurs, idempotence et limites

> Codes d’erreur de l’API nouko, idempotence avec Idempotency-Key et limite de 120 requêtes par minute.

Source : https://nouko.openclouds.fr/docs/erreurs

Toutes les erreurs ont le même format :

```
HTTP/1.1 400 Bad Request
X-Request-Id: 9a7c…

{ "error": { "code": "invalid_request", "message": "country: Invalid enum value" } }
```

| HTTP | Code | Cause | Que faire |
| --- | --- | --- | --- |
| 400 | `invalid_request` | Champ manquant ou invalide (détail dans `message`) | Corrigez la requête, ne réessayez pas telle quelle |
| 400 | `idempotency_key_required` | En-tête `Idempotency-Key` absent ou trop long | Ajoutez une clé stable de 120 caractères max. |
| 401 | `unauthorized` | Clé absente, invalide ou révoquée | Vérifiez la clé et son environnement |
| 403 | `account_suspended` | Compte suspendu par nouko | Contactez le support |
| 404 | `not_found` | Session inexistante ou d’un autre environnement | Vérifiez l’id et la clé utilisée |
| 409 | `not_cancellable` | Session déjà soumise ou terminée | Lisez son statut |
| 429 | `rate_limited` | Plus de 120 requêtes par minute | Attendez puis réessayez avec un délai croissant |
| 500 | `internal_error` | Erreur de nouko | Réessayez avec la **même** `Idempotency-Key` |

## Idempotence

Utilisez une clé liée à votre objet métier (ex. `commande-001`) et stockez-la. En cas de coupure réseau ou d’erreur `5xx`, renvoyez exactement la même requête avec la même clé : vous obtenez la session existante, jamais un doublon.

**Node.js**

```javascript
// Même Idempotency-Key à chaque tentative : jamais de doublon
async function createWithRetry(payload, key, attempts = 4) {
  for (let i = 0; i < attempts; i++) {
    try {
      const res = await fetch('https://nouko.openclouds.fr/api/public/v1/sessions', {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${process.env.NOUKO_API_KEY}`,
          'Idempotency-Key': key,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(payload),
      });
      if (res.status !== 429 && res.status < 500) return res.json(); // 200 si rejeu
    } catch { /* réseau : on réessaie */ }
    await new Promise(r => setTimeout(r, 2 ** i * 1000));
  }
  throw new Error('Nouko indisponible');
}
```

**Python**

```python
import time, uuid

def create_with_retry(payload, key=None, attempts=4):
    key = key or str(uuid.uuid4())  # stockez-la avec votre commande
    for i in range(attempts):
        try:
            r = requests.post("https://nouko.openclouds.fr/api/public/v1/sessions", json=payload, timeout=15,
                headers={"Authorization": f"Bearer {os.environ['NOUKO_API_KEY']}",
                         "Idempotency-Key": key})
            if r.status_code != 429 and r.status_code < 500:
                return r.json()
        except requests.RequestException:
            pass
        time.sleep(2 ** i)
    raise RuntimeError("Nouko indisponible")
```

## Limites

| Limite | Valeur |
| --- | --- |
| Requêtes | 120 par minute et par clé |
| Page de liste | 100 sessions max. |
| Métadonnées | 20 clés max. |
| Validité d’un lien | 15 minutes à 30 jours |
| Réponse webhook attendue | moins de 8 secondes |
