> ## Documentation Index
> Fetch the complete documentation index at: https://storekit.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Erreurs

> Comment le MCP marchand signale les échecs : rejets HTTP, résultats d'outil isError avec codes stables et règles de reprise pour les écritures en timeout.

Les échecs remontent à deux niveaux. Les problèmes d'authentification, d'origine et de limite de débit sont rejetés **avant** MCP, sous forme de réponses HTTP classiques. Tout ce qui se produit à l'intérieur d'un appel d'outil revient sous forme de résultat d'outil MCP avec `isError: true`.

## Niveau HTTP

| Statut | Cause | Corps |
| - | - | - |
| `401` | Identifiant manquant ou invalide | En-tête `WWW-Authenticate: Bearer realm="OAuth", resource_metadata="…"` ; démarre la discovery OAuth |
| `403` | En-tête `Origin` absent de la liste autorisée | `{ "error": "Origin not allowed" }` |
| `429` | Plus de 60 requêtes en une minute pour cet utilisateur ou cette clé | `{ "error": "Rate limit exceeded" }` avec `Retry-After` en secondes |

Ces réponses sont en dehors de l'enveloppe MCP ; une bibliothèque client MCP les remonte généralement comme des erreurs de transport.

## Erreurs d'outil

Un appel d'outil qui échoue est un succès JSON-RPC normal dont le résultat porte `isError: true`, un unique bloc texte et **pas** de `structuredContent` :

```json theme={null}
{
  "isError": true,
  "content": [
    {
      "type": "text",
      "text": "{\"error\":{\"code\":\"INVALID_INPUT\",\"message\":\"Date range exceeds 90 days\",\"nextSteps\":[\"Split the range into shorter intervals.\"],\"retryable\":false}}"
    }
  ]
}
```

Parse le texte en JSON pour obtenir :

| Champ | Signification |
| - | - |
| `code` | L'un des codes ci-dessous. Stable ; branche là-dessus |
| `message` | Description courte et sûre. Pour `INVALID_INPUT`, elle nomme le problème ; pour les autres codes, c'est une phrase fixe |
| `nextSteps` | Instructions qu'un agent peut suivre |
| `retryable` | Actuellement toujours `false` : voir [Reprise](#reprise) |

Rien d'autre issu de l'échec sous-jacent n'est exposé : ni traces de pile, ni SQL, ni réponses upstream, ni identifiants internes. Chaque requête est journalisée côté serveur avec le `x-request-id` renvoyé dans la réponse HTTP ; cite-le quand tu contactes le support.

## Codes

| Code | Quand | Correction typique |
| - | - | - |
| `INVALID_INPUT` | Violation de schéma, plage de dates de plus de 90 jours, horodatage d'écriture sans offset, `period` combiné à `from`/`to`, requête de stats à l'échelle du compte sur un compte multi-devises | Corrige les arguments ; `message` indique ce qui a échoué |
| `PERMISSION_DENIED` | L'identifiant ne peut pas agir sur ce compte | Vérifie la clé ou le token |
| `NOT_FOUND` | L'établissement, la commande, le menu ou le lien n'existe pas **sur ce compte** : les ressources d'autres comptes sont indiscernables de ressources inexistantes | Appelle `list-venues` (ou l'outil list adéquat) et vérifie l'ID |
| `CONFLICT` | L'état empêche l'écriture, par exemple un code de réduction déjà utilisé dans cet établissement | Lis l'état actuel, puis décide |
| `TIMEOUT` | L'outil a dépassé 30 secondes, ou un appel upstream a atteint le timeout | Réduis la portée de la requête. Pour une écriture, **vérifie l'état avant de réessayer** |
| `UPSTREAM_UNAVAILABLE` | Une dépendance (base de données, prestataire de paiement) n'a pas pu être atteinte | Attends, puis réessaie les lectures ; vérifie l'état avant de réessayer les écritures |
| `INTERNAL_ERROR` | Tout ce qui est inattendu | Réessaie les lectures une fois ; écris à [mcp@storekit.com](mailto:mcp@storekit.com) avec l'ID de requête si ça persiste |

## Reprise

Les lectures (`readOnlyHint: true`) peuvent être réessayées sans risque après `TIMEOUT`, `UPSTREAM_UNAVAILABLE` ou `INTERNAL_ERROR`, avec backoff.

Les écritures, c'est différent. `create-discount-code` et `create-payment-link` sont marqués `idempotentHint: false` et n'ont pas de clé d'idempotence. Un `TIMEOUT` est renvoyé lorsque le budget de 30 secondes est épuisé, ce qui peut se produire **après** que la ligne a été committée : le code ou le lien peut déjà exister. Avant de réessayer une écriture :

1. Appelle `list-discount-codes` et cherche le code, ou `list-payment-links` filtré par établissement et cherche le titre/la référence.
2. N'appelle l'écriture à nouveau que si elle est absente.

Ne réessaie jamais les écritures automatiquement. C'est pour cette raison que `retryable` est `false` sur chaque code aujourd'hui : le serveur ne sait pas si ton écriture a abouti, donc il ne te dit pas de réessayer.

## Erreurs de validation venant de ton client

Comme les erreurs ne portent pas de `structuredContent`, les clients conformes à la spec (dont le SDK TypeScript officiel) sautent la validation d'output-schema sur ces réponses et remontent l'enveloppe. Si ton client rapporte plutôt une erreur `-32602` ou « structured content does not match schema », c'est qu'il valide le *texte* contre l'`outputSchema` de l'outil ; lis directement le bloc texte.


## Related topics

- [Format de réponse](/docs/fr/developers/mcp/response-format.md)
- [Configuration de storekit Payments](/docs/fr/guides/payments/storekit-payments-setup.md)
- [Stratégies de frais de livraison](/docs/fr/guides/increasing-sales/delivery-fee-strategies.md)
- [Zonal (Aztec)](/docs/fr/guides/integrations/pos/zonal.md)
- [Bannières promotionnelles](/docs/fr/guides/marketing/promotional-banners.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.