# Gérer les erreurs

> Le format des erreurs, les codes stables, et ce qu’il faut faire selon la famille de l’erreur.

Toutes les erreurs suivent la RFC 9457 (`application/problem+json`) :

```json
{
    "type": "https://nessflow.com/en/developers/errors/project.locked",
    "title": "Projet en lecture seule : votre offre ne couvre plus ce projet. Rien n’y est exécuté, tout y reste lisible.",
    "status": 403,
    "code": "project.locked"
}
```

Votre code s’appuie sur `code`, qui ne change pas ; `title` est traduit selon `Accept-Language` et peut être reformulé. `type` mène à l’entrée du catalogue des codes.

## Que faire, selon la famille

- `401` (`unauthenticated`) : jeton absent, invalide ou expiré. Ne réessayez pas, renouvelez le jeton.
- `403` : refus d’autorisation. `token.missing_scope` (le jeton n’a pas le scope, voir `required_scopes`), `api.write_not_in_plan` ou `plan_limit.…` (l’offre, voir `upgrade_to`), `project.locked` (projet en lecture seule). Réessayer n’y changera rien.
- `404` (`not_found`) : la ressource n’existe pas, ou appartient à une autre équipe.
- `409` : conflit avec l’état courant (`crawl.already_running`, `export.not_ready`…). Attendez, puis réessayez.
- `422` (`validation_failed`) : `errors` donne, champ par champ, ce qui ne va pas.
- `429` (`rate_limited`) : attendez `Retry-After` secondes.
- `5xx` : réessayez avec un délai croissant ; une écriture facturée se réessaie avec la même `Idempotency-Key`.

## Un exemple

Une écriture facturée sans clé d’idempotence est refusée avant toute exécution :

```bash expect=400
curl -X POST "https://api.nessflow.com/v1/campaigns/$CAMPAIGN_ID/crawls" \
  -H "Authorization: Bearer $NESSFLOW_TOKEN"
```

La réponse porte `code: idempotency.key_required` et `header: Idempotency-Key`.
