Gestion des erreurs
L'API Facturino utilise des codes HTTP standards et retourne systématiquement un objet error structuré.
Chaque erreur contient un identifiant de requête (request_id) à fournir au support pour toute investigation.
Format de réponse
Toutes les erreurs partagent la même enveloppe — un seul objet error en racine, jamais d'autres champs frères.
Inspiré du modèle Stripe pour faciliter l'intégration.
{
"error": {
"type": "invalid_request_error",
"code": "missing_required_field",
"message": "Field 'customerId' is required.",
"param": "customerId",
"doc_url": "https://facturino.com/docs/errors#missing_required_field",
"hint": "Either provide a customerId or inline a 'buyer' object.",
"request_id": "req_8a3b9f2e1d"
}
} | Champ | Description |
|---|---|
type | Catégorie de l'erreur (voir tableau ci-dessous) |
code | Code machine-readable pour le branchement (ex. missing_required_field) |
message | Message en clair, lisible pour un humain (ne pas afficher tel quel aux utilisateurs finaux) |
param | Optionnel — Nom du paramètre invalide quand applicable |
doc_url | Optionnel — Lien vers la documentation détaillée pour ce code |
hint | Optionnel — Suggestion d'action concrète |
request_id | Identifiant unique de la requête (préfixe req_) — à fournir au support |
Codes HTTP
| Code | Signification | Action |
|---|---|---|
200 / 201 | Succès | Continuer |
202 | Accepté (job asynchrone) | Suivre l'id du job via GET /v1/jobs/:id |
204 | Succès, pas de contenu | Continuer |
400 | Requête invalide (validation, format) | Corriger le payload, ne pas retenter |
401 | Authentification manquante ou invalide | Vérifier la clé API |
402 | Paiement requis (plan insuffisant) | Mettre à niveau le plan |
403 | Action interdite (scope, transition d'état) | Vérifier permissions et statut |
404 | Ressource introuvable | Vérifier l'identifiant |
409 | Conflit (idempotency-key réutilisée, version) | Voir error.code |
422 | Donnée invalide après validation (SIRET inconnu, TVA invalide) | Corriger le payload |
429 | Trop de requêtes | Retentez après le délai indiqué dans Retry-After |
500 | Erreur serveur | Retentez avec backoff exponentiel |
503 | Service indisponible (PA injoignable, maintenance) | Retentez après quelques secondes |
Types d'erreur
Le champ error.type classifie l'erreur — utilisez-le comme premier discriminant dans votre code. Liste exhaustive :
| Type | Statut HTTP | Description |
|---|---|---|
invalid_request_error | 400 | Le payload est mal formé, un champ requis manque, une valeur est invalide. |
validation_error | 422 | Schéma Zod refusé — voir error.param pour le champ fautif. |
authentication_error | 401 | Clé API absente, invalide, révoquée ou expirée. |
permission_error | 403 | La clé n'a pas le scope requis pour cette opération. |
not_found_error | 404 | La ressource n'existe pas, ou n'est pas accessible avec cette clé (livemode mismatch). |
conflict_error | 409 | Conflit (transition d'état impossible, ressource déjà finalisée). |
rate_limit_error | 429 | Limite de requêtes dépassée — consulter Retry-After. |
plan_limit_error | 402 | Plan insuffisant ou quota dépassé (factures/mois, taille storage…). |
api_error | 500 | Erreur serveur — Facturino est notifié automatiquement. |
Codes d'erreur fréquents
Le champ error.code est le discriminant fin sous le type. Le code est aussi le fragment du doc_url retourné dans la réponse (https://facturino.com/docs/errors#<code>).
| Code | Type | Cause |
|---|---|---|
missing_required_field | invalid_request_error | Un champ obligatoire est absent (voir error.param). |
invalid_field_value | invalid_request_error | Valeur invalide (date hors plage, code pays inconnu, livemode mismatch…). |
invalid_content_type | invalid_request_error | Le header Content-Type doit être application/json. |
validation_error | validation_error | Schéma Zod refusé : SIRET invalide, format date, longueur dépassée, valeur hors enum. |
invalid_api_key | authentication_error | Clé inconnue ou mal formée. |
api_key_revoked | authentication_error | La clé a été révoquée depuis le dashboard. |
api_key_expired | authentication_error | La clé a dépassé sa date d'expiration optionnelle. |
missing_api_key | authentication_error | Header Authorization absent ou mal formé. |
captcha_required | authentication_error | Trop de tentatives — résoudre le captcha avant de retenter. |
scope_insufficient | permission_error | La clé n'a pas le scope nécessaire pour cette opération. |
not_found | not_found_error | La ressource n'existe pas ou n'est pas dans votre environnement (fac_test_ vs fac_live_). |
conflict | conflict_error | Requête concurrente avec la même Idempotency-Key encore en cours de traitement. |
invalid_status_transition | invalid_request_error | Transition d'état impossible — 400 (cf. machine à états des factures/devis/avoirs ; ex: éditer une facture finalisée → émettre un avoir via POST /v1/credit-notes). |
resource_deleted | conflict_error | La ressource a été supprimée (soft-delete) et n'est plus modifiable. |
conflict | conflict_error | Même Idempotency-Key réutilisée avec un payload différent (24 h). |
rate_limit_exceeded | rate_limit_error | Limite par minute dépassée — voir Retry-After. |
plan_limit_error | plan_limit_error | Fonctionnalité réservée à un plan supérieur. |
quota_exceeded | plan_limit_error | Quota mensuel du plan dépassé (factures, e-reporting, établissements…). |
storage_quota_exceeded | plan_limit_error | Quota de stockage de fichiers (PDF, logos) dépassé pour ce plan. |
payload_too_large | invalid_request_error | Corps de requête au-delà de la limite (CSV, pièce jointe). |
pa_unavailable | invalid_request_error | La Plateforme Agréée est injoignable (timeout, 5xx en amont). |
pa_not_configured | invalid_request_error | Aucune PA connectée pour cet établissement. Configurer depuis Paramètres → Facturation électronique. |
siret_not_found | invalid_request_error | SIRET introuvable dans l'annuaire SIRENE. |
vat_validation_failed | invalid_request_error | Le numéro TVA intracom n'a pas pu être validé par VIES. |
schematron_validation_failed | invalid_request_error | Le document viole une règle Schematron EN16931 ou CIUS-FR (BT-46, BR-55…). |
invalid_payment_amount | invalid_request_error | Montant de paiement nul ou négatif. |
payment_exceeds_amount_due | invalid_request_error | Le paiement dépasse le restant dû — non autorisé. |
sandbox_payment_unavailable | invalid_request_error | Paiement en ligne indisponible pour une facture de test — le portail public répond 409, POST /v1/invoices/:id/payment-link répond 422 (les clés Stripe plateforme sont 100 % live). Remède : tester le flux avec une clé fac_live_ sur une facture live. |
deposit_not_enabled | invalid_request_error | Le dépôt PA automatique n'est pas activé pour cet établissement (Paramètres → Facturation électronique). |
related_invoice_not_found | invalid_request_error | La facture liée à l'avoir est introuvable (remboursement). |
credit_note_not_refundable | invalid_request_error | L'avoir n'est pas dans un état remboursable (non finalisé, ou déjà intégralement remboursé). |
invalid_refund_amount | invalid_request_error | Montant de remboursement nul, négatif ou mal formé. |
refund_exceeds_credit_note | invalid_request_error | Le remboursement dépasse le montant restant de l'avoir. |
subscription_paused | invalid_request_error | L'abonnement de l'émetteur est suspendu — l'opération est bloquée jusqu'à régularisation. |
not_implemented | invalid_request_error | Endpoint pas encore disponible (statut 501). |
internal_error | api_error | Erreur serveur — Facturino est notifié automatiquement. |
Stratégie de retry
Tous les codes 4xx sauf 409/429 sont permanents — corrigez le payload, ne retentez pas.
| Cas | Stratégie |
|---|---|
429 | Lire le header Retry-After (secondes) et attendre exactement cette durée |
500 / 502 | Backoff exponentiel : 1s, 2s, 4s, 8s — max 5 tentatives |
503 (PA) | Backoff long : 30s, 60s, 120s — max 3 tentatives sur 5 min |
409 idempotency | NE PAS retenter — le payload diffère du précédent |
Idempotence et retry. Toujours envoyer un header Idempotency-Key sur les requêtes POST. Sans cela, un retry après un timeout réseau peut créer un doublon. Voir Idempotence.
Exemples
Node.js :
try {
const invoice = await facturino.invoices.create({ /* ... */ })
} catch (err) {
if (err.type === 'invalid_request_error') {
console.error(`Champ invalide: ${err.param} — ${err.message}`)
} else if (err.type === 'rate_limit_error') {
// Retentez après le délai indiqué dans Retry-After
await sleep(err.retryAfterMs)
} else {
// Toujours logguer err.requestId pour le support
logger.error({ requestId: err.requestId, code: err.code }, err.message)
}
} Python :
from facturino import Facturino, FacturinoError
try:
invoice = client.invoices.create(...)
except FacturinoError as err:
if err.type == "invalid_request_error":
print(f"Champ invalide: {err.param} — {err.message}")
elif err.type == "rate_limit_error":
time.sleep(err.retry_after_seconds)
else:
logger.error({"request_id": err.request_id}, err.message) Contacter le support
Pour toute erreur inexpliquée ou un comportement inattendu, contactez le support en fournissant :
- Le
request_idexact (préfixereq_) — il permet de retrouver les logs côté Facturino. - L'horodatage de la requête (à la seconde près).
- Le payload envoyé (masquez les champs sensibles si nécessaire).
Contacter le support · best-effort (Gratuit, Essential), prioritaire (Pro).