Aller au contenu
Documentation
Français
Ouvrir l'application

Erreurs et limites

Format des erreurs de l'API NovaFisko, codes HTTP, codes machine, limites de débit par route et conduite à tenir après un 429.

L'API utilise les codes HTTP standards et renvoie toujours un corps JSON en cas d'erreur.

Format d'une erreur

{
  "message": "Le plafond de 5 dossiers de votre licence est atteint.",
  "code": "company_limit_reached",
  "errors": {
    "name": ["Le plafond de 5 dossiers de votre licence est atteint."]
  }
}
Champ Présence Description
message toujours Texte lisible, traduit dans la langue de l'utilisateur
code quand l'erreur est métier Identifiant stable, en anglais, à utiliser dans votre code
errors erreurs de validation Objet champ → liste de messages. Les champs imbriqués utilisent la notation pointée : lines.0.account_id

Certaines erreurs ajoutent des champs propres, par exemple required_ability, server_version et server_data, ou blocker_codes pour Peppol.

Astuce

Traitez d'abord le statut HTTP, puis code s'il est présent. N'analysez jamais le texte de message.

Codes HTTP

Statut Signification Conduite à tenir
200 Succès
201 Ressource créée
202 Demande acceptée, traitement immédiat ou différé (test de webhook)
204 Succès sans corps (suppression, déconnexion)
401 Jeton absent, invalide, révoqué ou expiré Se reconnecter ou changer de jeton
403 Action interdite pour ce jeton ou ce rôle Lire code
404 Ressource inconnue, ou dossier auquel l'utilisateur n'a pas accès Vérifier le public_token et les droits
409 Conflit de version (X-Base-Version) Recharger, fusionner, renvoyer
422 Données refusées (validation ou règle comptable) Corriger selon errors et code
429 Trop de requêtes Attendre Retry-After secondes
500 Erreur interne Réessayer plus tard avec la même clé d'idempotence
503 Service indisponible ou maintenance, toujours avec un code Réessayer avec un délai croissant

Un dossier qui existe mais auquel vous n'avez pas accès répond 404 et non 403. C'est voulu : l'API ne révèle pas l'existence d'un dossier à qui n'y est pas autorisé.

Codes machine

Authentification et accès

code Statut Signification
token_ability_missing 403 Le jeton d'intégration n'a pas la capacité indiquée dans required_ability
session_token_required 403 Route réservée aux jetons de session
token_limit_reached 422 50 jetons d'intégration par utilisateur au maximum
webhook_limit_reached 422 20 points de réception par cabinet au maximum
webhook_url_refused 422 URL de webhook refusée (HTTPS requis, hôte privé ou non résolu)
demo_mode 403 Effet externe bloqué dans le cabinet de démonstration
demo_unavailable 503 Le cabinet de démonstration n'est pas disponible
service_unavailable 503 Indisponibilité générale

Licence et plafonds

code Statut Signification
company_limit_reached 422 Plafond de dossiers de la licence ou du plan atteint
user_limit_reached 422 Plafond d'utilisateurs de la licence atteint
invalid_key 422 Clé d'activation inconnue
expired_key 422 Clé d'activation expirée
exhausted_key 422 Clé déjà utilisée le nombre de fois autorisé
key_reserved 422 Clé réservée à un autre cabinet
already_active 422 Cette clé est déjà active sur le cabinet

Concurrence et historique

code Statut Signification
conflict 409 ou 422 L'enregistrement a changé sur le serveur depuis votre lecture
period_locked 422 Période verrouillée ou exercice clôturé
vat_locked 422 Déclaration TVA validée ou déposée
entry_immutable 422 Une écriture validée ne se modifie pas : il faut l'extourner
already_reverted, already_reversed 422 Le retour en arrière ou l'extourne a déjà eu lieu
in_use, booked 422 Suppression refusée : l'enregistrement est utilisé ou comptabilisé
code_taken 422 Restauration refusée : le code a été repris entre-temps
not_revertible, nothing_to_revert, operation_not_found 422 ou 404 Retour en arrière impossible
force_forbidden, read_only 403 Rôle insuffisant

Synchronisation

Ces codes apparaissent dans le résultat de chaque mutation de sync/push, pas comme statut HTTP.

code Signification
locked Donnée comptable validée ou verrouillée côté serveur
validation Données refusées, détail dans errors
not_supported_offline Cette opération ne passe pas par sync/push
not_found, forbidden, invalid_mutation, unknown_temp_id, unprocessable Mutation refusée définitivement
server_error Erreur temporaire, retryable: true
conflict_already_resolved, conflict_choice_unavailable Résolution de conflit refusée (422)

Peppol

Les refus Peppol renvoient blocker_codes, une liste parmi : provider_not_configured, vat_number_missing, address_missing, email_missing, already_registered, managed_by_novadesko, registered_elsewhere, not_registered, provider_error.

{
  "message": "Le dossier ne peut pas être inscrit sur Peppol.",
  "errors": {"peppol": ["Le dossier ne peut pas être inscrit sur Peppol."]},
  "blockers": ["L'adresse e-mail de contact est manquante."],
  "blocker_codes": ["email_missing"],
  "state": {"status": "none", "can_register": false}
}
Note

Toutes les erreurs 422 ne portent pas de code. Une erreur de validation simple ne contient que message et errors. Prévoyez ce cas.

Erreur de validation

{
  "message": "Le champ entry date est obligatoire. (et 1 erreur supplémentaire)",
  "errors": {
    "entry_date": ["Le champ entry date est obligatoire."],
    "lines.1.account_id": ["Le champ lines.1.account_id est obligatoire quand lines.1.account n'est pas présent."]
  }
}

Limites de débit

Les limites s'appliquent par minute. Elles sont comptées par utilisateur pour les routes authentifiées et par adresse IP pour les routes publiques. Les routes qui ne figurent pas dans ce tableau n'ont pas de limite propre.

Route Limite par minute
POST auth/login 20
POST auth/demo 10
POST auth/tokens 20
POST firms/{firm}/webhooks/{id}/test 12
GET pricing, GET pricing/simulate 120
POST firms/{firm}/licence/activate 10
POST firms/{firm}/sync 6
GET lookup/search, lookup/companies/{identifier}, lookup/vat 60
GET lookup/cities, lookup/streets 120
POST companies/{company}/apply-sheet, third-parties/{id}/apply-sheet 30
POST document-imports 30
POST document-imports/{id}/process, .../validate 120
POST document-imports/{id}/retry 60
POST documents/book-all 5
POST bank-transactions/match 10
POST bank-transactions/book-matched 5
POST payments/sepa 20
GET vies, POST third-parties/{id}/vies 30
POST sync/novadesko 10
POST integrations/{id}/test, .../sync 12
POST peppol/register 6
POST peppol/refresh 12
GET peppol/lookup 30
GET third-parties/{id}/peppol 60
POST third-parties/peppol/check-all 6
GET exports/{type} 30
GET exports/{type}/preview-url 60
GET exports/full-dossier/{fiscalYear} 10
POST fiscal-years/{id}/year-end 5
GET history/export 30

Chaque réponse d'une route limitée indique votre consommation :

HTTP/1.1 200 OK
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 27

Réponse 429

HTTP/1.1 429 Too Many Requests
Retry-After: 41
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1791188421
Content-Type: application/json

{"message": "Too Many Attempts."}

Attendez le nombre de secondes indiqué par Retry-After avant de réessayer. X-RateLimit-Reset donne l'instant de remise à zéro en secondes Unix.

import time
import requests

def call(method, url, **kwargs):
    for attempt in range(5):
        response = requests.request(method, url, timeout=60, **kwargs)
        if response.status_code == 429:
            # Honour the server delay, never hammer the API
            time.sleep(int(response.headers.get("Retry-After", "5")) + 1)
            continue
        if response.status_code in (500, 503):
            time.sleep(2 ** attempt)
            continue
        return response
    raise RuntimeError("NovaFisko API unavailable")
Attention

Quand vous réessayez une écriture après une erreur réseau, un 500 ou un 503, renvoyez le même X-Client-Mutation-Id. Sans cela, vous risquez de créer un doublon. Voir Idempotence.

Autres limites

Limite Valeur
Fichiers par dépôt dans l'importateur 20
Taille d'un fichier déposé 25 Mo
Fichiers extraits d'une archive ZIP 50
Mutations par appel sync/push 200
Changements par appel sync/pull 500 par défaut, 1000 au maximum
Éléments par page 50 par défaut, 200 au maximum (500 pour les mouvements bancaires)
Durée d'une URL signée d'aperçu d'export 15 minutes

Voir aussi