# Erreurs

> Chaque code d'erreur renvoyé par Ikiform, avec son statut HTTP, sa cause et sa solution.

Les soumissions de formulaire et l'API REST partagent la même enveloppe d'erreur. Les requêtes JSON la reçoivent avec le statut HTTP correspondant ; les envois de formulaire depuis un navigateur reçoivent une page d'erreur hébergée avec le même message et le même statut.

## L'enveloppe d'erreur

`Erreur`:

```json
{
  "ok": false,
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please slow down."
  },
  "request_id": "req_01k7v2c9t3e8m5q4x6z0a1b2c3"
}
```

- `error.code` est stable : basez votre logique dessus. `error.message` est un texte en anglais destiné aux humains et peut changer.
- `error.fields` est présent sur les erreurs de validation, indexé par id de champ, chacun avec une liste de messages. Les erreurs qui concernent tout le corps utilisent la clé `_form`.
- `error.challenge_url` est présent sur `challenge_required`.
- `request_id` correspond à l'en-tête `X-Request-Id` présent sur chaque réponse.
- Les réponses limitées en débit contiennent `Retry-After` en secondes. Les deux en-têtes sont lisibles depuis le code navigateur.

## Codes

| Statut | Code | Où |
| --- | --- | --- |
| 400 | [`invalid_body`](#invalid-body) | Envoi |
| 400 | [`invalid_request`](#invalid-request) | API |
| 401 | [`unauthorized`](#unauthorized) | API |
| 402 | [`plan_required`](#plan-required) | Envoi |
| 403 | [`forbidden`](#forbidden) | Les deux |
| 403 | [`origin_not_allowed`](#origin-not-allowed) | Envoi |
| 403 | [`form_paused`](#form-paused) | Envoi |
| 403 | [`captcha_failed`](#captcha-failed) | Envoi |
| 403 | [`challenge_required`](#challenge-required) | Envoi |
| 404 | [`not_found`](#not-found) | Les deux |
| 405 | [`method_not_allowed`](#method-not-allowed) | API |
| 409 | [`idempotency_in_progress`](#idempotency-in-progress) | Envoi |
| 413 | [`payload_too_large`](#payload-too-large) | Envoi |
| 415 | [`unsupported_media_type`](#unsupported-media-type) | Envoi |
| 415 | [`unsupported_charset`](#unsupported-charset) | Envoi |
| 422 | [`validation_failed`](#validation-failed) | Envoi |
| 422 | [`files_not_supported`](#files-not-supported) | Envoi |
| 422 | [`too_deep`](#too-deep) | Envoi |
| 422 | [`idempotency_mismatch`](#idempotency-mismatch) | Envoi |
| 429 | [`rate_limited`](#rate-limited) | Les deux |
| 429 | [`quota_exceeded`](#quota-exceeded) | Envoi |
| 500 | [`server_error`](#server-error) | Les deux |

### 400 invalid_body

|   |   |
| --- | --- |
| Message | `The request body could not be read.` |
| Cause | JSON ou multipart mal formé, tableau ou chaîne JSON au lieu d'un objet, ou clé d'idempotence de plus de 255 caractères. |
| Solution | Envoyez un seul objet JSON, ou laissez le navigateur ou `FormData` construire le corps. |

### 400 invalid_request

|   |   |
| --- | --- |
| Message | `The request is invalid.` |
| Cause | `limit`, `status`, `form_id` ou `cursor` est invalide. Le message indique le paramètre. |
| Solution | Utilisez `limit` de 1 à 100, `status` à `received` ou `spam`, un vrai id `frm_`, et les curseurs exactement tels que renvoyés. |

### 401 unauthorized

|   |   |
| --- | --- |
| Message | `A valid API key is required.` |
| Cause | Pas d'en-tête `Authorization`, pas un token Bearer, ou une clé inconnue, révoquée ou expirée. |
| Solution | Envoyez `Authorization: Bearer ik_sk_...` avec une clé secrète active. |

### 402 plan_required

|   |   |
| --- | --- |
| Message | `This form isn't accepting submissions right now.` |
| Cause | L'espace de travail n'a pas d'offre active. Cela ne peut arriver qu'une fois la facturation activée. |
| Solution | Choisissez une offre dans le tableau de bord sous **Settings**. |

### 403 forbidden

|   |   |
| --- | --- |
| Message | `You do not have access to this resource.` |
| Cause | La clé API est mal formée, appartient à un autre espace de travail, est une clé publiable utilisée sur l'API REST, ou n'a pas la portée nécessaire. |
| Solution | Utilisez une clé secrète de cet espace de travail avec la portée indiquée dans le message. |

### 403 origin_not_allowed

|   |   |
| --- | --- |
| Message | `This form does not accept submissions from this site.` |
| Cause | L'envoi vient d'un site hors des domaines autorisés du formulaire et le formulaire refuse les non-correspondances, ou une clé publiable a été utilisée depuis un domaine non listé sur la clé. |
| Solution | Ajoutez le site à **Allowed domains** ou aux domaines de la clé. Pour les envois serveur, utilisez une clé secrète. |

### 403 form_paused

|   |   |
| --- | --- |
| Message | `This form is not accepting submissions right now.` |
| Cause | Le formulaire est en pause dans le tableau de bord. |
| Solution | Réactivez le formulaire. |

### 403 captcha_failed

|   |   |
| --- | --- |
| Message | `The captcha check failed. Please try again.` |
| Cause | Le token Turnstile est absent, expiré, déjà utilisé, ou sa vérification a échoué. |
| Solution | Obtenez un nouveau token pour chaque envoi. Avec vos propres clés, vérifiez que la clé de site correspond au secret. |

### 403 challenge_required

|   |   |
| --- | --- |
| Message | `Complete the human check, then send the form again.` |
| Cause | Le formulaire utilise la vérification humaine Ikiform et un envoi JSON est arrivé sans token. |
| Solution | Appelez `challenge(formId)` du SDK et passez le token, ou utilisez `error.challenge_url`. Les envois serveur peuvent envoyer une clé secrète à la place. |

### 404 not_found

|   |   |
| --- | --- |
| Message | `Not found.` |
| Cause | Le formulaire n'existe pas, a été supprimé ou désactivé, ou l'id ou la route est faux. Également renvoyé pour un `GET` vers `/f/<formId>`. |
| Solution | Copiez l'endpoint depuis la vue d'ensemble du formulaire, et envoyez un POST au lieu de l'ouvrir dans un onglet. |

### 405 method_not_allowed

|   |   |
| --- | --- |
| Message | `This method is not allowed here.` |
| Cause | Un preflight de navigateur sur l'API REST, qui fonctionne uniquement de serveur à serveur. |
| Solution | Appelez `/api/v1` depuis votre backend. |

### 409 idempotency_in_progress

|   |   |
| --- | --- |
| Message | `A request with this idempotency key is still being processed.` |
| Cause | Une requête avec cette clé d'idempotence est encore en cours de traitement. |
| Solution | Attendez un instant et réessayez avec la même clé ; vous recevrez la première réponse. |

### 413 payload_too_large

|   |   |
| --- | --- |
| Message | `The submission is too large.` |
| Cause | Le corps, un nom de champ, une valeur ou le nombre de champs dépasse sa limite. Le message indique lequel. |
| Solution | Voir [Limites](https://ikiform.com/fr/docs/limits.md#submissions). Répartissez les longs textes sur plusieurs champs, ou stockez les fichiers ailleurs et envoyez un lien. |

### 415 unsupported_media_type

|   |   |
| --- | --- |
| Message | `Send the form as urlencoded, multipart or JSON.` |
| Cause | Le `Content-Type` n'est ni urlencoded, ni multipart, ni JSON, ou il est absent. |
| Solution | Définissez `Content-Type: application/json` quand vous envoyez du JSON. |

### 415 unsupported_charset

|   |   |
| --- | --- |
| Message | `Only UTF-8 is supported.` |
| Cause | Le corps n'est pas en UTF-8, ou déclare un autre charset. |
| Solution | Encodez en UTF-8. Ajoutez `accept-charset="utf-8"` aux anciens formulaires HTML. |

### 422 validation_failed

|   |   |
| --- | --- |
| Message | `Some fields are invalid.` |
| Cause | Des champs ont échoué à la validation. `error.fields` associe les ids de champs à des messages. |
| Solution | Affichez les messages à côté des champs. Voir [Champs](https://ikiform.com/fr/docs/fields.md#errors). |

### 422 files_not_supported

|   |   |
| --- | --- |
| Message | `File uploads are not supported yet.` |
| Cause | L'envoi contient un fichier. L'envoi de fichiers n'existe pas encore. |
| Solution | Retirez les inputs de fichier, ou téléversez les fichiers ailleurs et envoyez le lien. |

### 422 too_deep

|   |   |
| --- | --- |
| Message | `The JSON body is nested too deeply.` |
| Cause | Le corps JSON est imbriqué sur plus de 3 niveaux, en comptant l'objet racine. |
| Solution | Aplatissez les données, par exemple `{ "address_city": "London" }`. |

### 422 idempotency_mismatch

|   |   |
| --- | --- |
| Message | `This idempotency key was already used with a different payload.` |
| Cause | Cette clé d'idempotence a déjà été utilisée pour ce formulaire dans les dernières 24 heures avec des champs différents. |
| Solution | Utilisez une nouvelle clé pour de nouvelles données. Ne gardez la même clé que pour les nouvelles tentatives à l'identique. |

### 429 rate_limited

|   |   |
| --- | --- |
| Message | `Too many requests. Please slow down.` |
| Cause | Limite de débit dépassée. `Retry-After` indique combien de secondes attendre. |
| Solution | Attendez et réessayez. Si de vrais visiteurs l'atteignent, modifiez la [limite de débit](https://ikiform.com/fr/docs/rate-limits.md) du formulaire. |

### 429 quota_exceeded

|   |   |
| --- | --- |
| Message | `This form isn't accepting submissions right now.` |
| Cause | L'espace de travail a reçu ce mois-ci 2 fois sa limite mensuelle de soumissions. |
| Solution | Passez au palier supérieur, ou attendez le mois suivant. Voir [Usage mensuel](https://ikiform.com/fr/docs/limits.md#monthly-usage). |

### 500 server_error

|   |   |
| --- | --- |
| Message | `Something went wrong on our side.` |
| Cause | Une erreur s'est produite du côté d'Ikiform. |
| Solution | Réessayez avec un backoff et une clé d'idempotence. Si le problème persiste, indiquez le `request_id`. |

## Ce qui n'est pas une erreur

- Le spam reçoit le même `201` ou la même redirection qu'une vraie soumission. Cherchez-le sous le filtre spam du tableau de bord.
- Un `_redirect` non autorisé est ignoré, et le navigateur arrive sur la page de remerciement hébergée.
- Un `_replyto` qui n'est pas une seule adresse e-mail valide est ignoré.

## Réessayer

- Réessayez un `429` après `Retry-After`, et les `500`, `409` ou erreurs réseau avec un backoff. Envoyez une [clé d'idempotence](https://ikiform.com/fr/docs/frameworks.md#idempotency) pour qu'une nouvelle tentative ne crée jamais de doublon.
- Ne réessayez pas les autres erreurs `4xx` sans rien changer. Corrigez d'abord la requête.
