API UPO de KSeF : suivi du statut et preuves durables

Construisez un flux fiable pour l’API UPO de KSeF : interrogez le statut, traitez les échecs, vérifiez le XML UPO et archivez une preuve durable.

Ernest Bursa

Ernest Bursa

Founder · · 13 min de lecture
Polish software engineer in a Warsaw office reviewing a green 200 invoice status and verified XML receipt beside an archive box

Pour récupérer un UPO de KSeF en toute sécurité, conservez la référence de facture renvoyée lors de l’envoi, puis interrogez le statut de la facture jusqu’à ce qu’il atteigne un état terminal. Ne considérez la facture comme acceptée qu’au statut 200, accompagné d’un numéro KSeF. Téléchargez ensuite le XML UPO, vérifiez le hachage de la réponse, le schéma et la signature XAdES, puis archivez les octets exacts. Une réponse d’envoi positive ou une URL UPO temporaire ne prouve pas que KSeF a accepté la facture.

Qu’est-ce qui prouve que KSeF a accepté une facture ?

L’acceptation exige le résultat complet du traitement asynchrone, pas une simple soumission HTTP réussie. L’appel d’envoi renvoie un referenceNumber de facture et lance la vérification. Il n’attribue pas le numéro KSeF définitif et ne prouve pas que le document a passé les contrôles de KSeF.

Cette distinction est au cœur d’une intégration fiable. Votre application peut recevoir une réponse normale de la route d’envoi alors que la facture attend encore sa validation. Si vous la marquez comme acceptée à ce stade, votre état local devancera celui du système officiel. Vous risquez d’afficher une fausse réussite au client, de lancer trop tôt les traitements comptables en aval ou de perdre les identifiants nécessaires pour détecter un rejet ultérieur.

Le guide officiel des sessions interactives décrit la vérification après soumission comme asynchrone. Enregistrez immédiatement la référence de facture renvoyée avec votre facture locale et la référence de session. Ces identifiants ont chacun un rôle distinct :

  • L’identifiant de votre facture locale rattache le traitement à votre propre enregistrement métier.
  • La référence de session désigne la session KSeF utilisée pour le transport.
  • La référence de facture désigne cette soumission pendant son traitement par KSeF.
  • Le numéro KSeF n’arrive qu’après l’acceptation et fait alors partie de la preuve.

Pour obtenir un résultat positif, attendez que la facture atteigne le statut 200, vérifiez que la réponse contient le numéro KSeF, puis récupérez l’UPO. Le manuel KSeF 2.0 du ministère, partie II précise que l’acceptation attribue un numéro KSeF et rend l’UPO disponible sous la forme d’un document XML distinct.

Vous obtenez ainsi un modèle d’état clair : soumise, en cours de traitement, acceptée ou en échec. Ne confondez pas soumission et acceptation. La réponse HTTP prouve le transport ; le statut 200, le numéro KSeF et l’UPO vérifié prouvent le résultat final.

Quel point d’accès de statut KSeF faut-il interroger ?

Interrogez le statut de chaque facture lorsque vous avez besoin du résultat propre à cette facture. Utilisez GET /sessions/{referenceNumber}/invoices/{invoiceReferenceNumber} avec la référence de session et la référence de facture enregistrées lors de la soumission.

D’après la spécification OpenAPI officielle, la réponse peut contenir le statut KSeF de la facture, son numéro local, son numéro KSeF, son hachage, sa date d’acquisition, sa date de facturation, sa date de stockage permanent, son mode de facturation, ainsi qu’une URL temporaire de téléchargement de l’UPO et sa date d’expiration. Enregistrez les champs utiles dès leur apparition, sans attendre la fin de toute la session.

Le point d’accès de session, GET /sessions/{referenceNumber}, répond à un autre besoin. Il fournit l’état de la session et des totaux tels que invoiceCount, successfulInvoiceCount et failedInvoiceCount. Une fois la session fermée, il peut également renvoyer des références et des URL de téléchargement pour les pages UPO agrégées.

Ces totaux servent au rapprochement. Ils permettent de vérifier que le nombre de résultats individuels enregistrés correspond à celui de KSeF. En revanche, ils n’indiquent pas quel numéro KSeF a été attribué à quelle facture locale. Comme une session peut contenir à la fois des factures acceptées et rejetées, son résultat global ne remplace pas le dossier de chaque facture.

Utilisez donc les deux vues de manière explicite :

  1. Interrogez le statut de chaque facture pour piloter la facture affichée dans votre produit ou ERP.
  2. Consultez le statut de la session pour rapprocher les totaux et, le cas échéant, récupérer les pages UPO agrégées.
  3. Examinez toute différence entre les totaux de la session et les résultats enregistrés par facture.

Le guide officiel consacré au statut des sessions et à l’UPO décrit ces deux niveaux. Les séparer évite une erreur d’identité courante : considérer comme interchangeables une référence de session, une référence de facture et un numéro KSeF.

Quels codes de statut de facture sont terminaux ?

Votre mécanisme d’interrogation doit s’arrêter sur chaque état terminal documenté, pas seulement en cas de réussite. Les codes 100 et 150 signalent un traitement toujours en cours. Le code 200 signale une réussite. Les résultats 4xx et 5xx documentés ci-dessous exigent le traitement de l’échec ou une analyse approfondie.

Code Signification Classement en production
100 Acceptée pour la suite du traitement Non terminal
150 En cours de traitement Non terminal
200 Réussite Réussite terminale
405 Annulée en raison d’une erreur de session Échec terminal
410 Périmètre d’autorisation non valide Échec terminal
415 Impossible d’envoyer une facture avec pièce jointe Échec terminal
430 Erreur de vérification du fichier de facture Échec terminal
435 Erreur de déchiffrement du fichier Échec terminal
440 Facture en double Échec terminal, examiner les extensions structurées
450 Erreur de validation sémantique de la facture Échec terminal
500 Erreur inconnue Échec terminal, analyse manuelle
550 Opération annulée par le système Examiner, puis réessayer au niveau de l’opération si nécessaire

Ces significations proviennent de SessionInvoiceStatusResponse dans le contrat OpenAPI actuel. Enregistrez le code numérique, la description, les détails et les extensions structurées reçus. Le texte lisible facilite les opérations, tandis que le code offre à la logique applicative un point de décision stable.

Le statut de doublon 440 demande une attention particulière. Il peut contenir des informations structurées sur la session d’origine et le numéro KSeF. Ces données servent à l’analyse ; elles ne vous autorisent pas à convertir silencieusement la nouvelle tentative en réussite. Ne créez un lien vers l’original qu’après avoir vérifié, selon vos propres règles d’identité et de hachage, que les deux dossiers représentent le même document.

Votre analyseur doit aussi tolérer les champs inconnus. Le journal des modifications de l’API précise que des propriétés supplémentaires peuvent apparaître sans constituer une rupture de compatibilité. Un code de statut inconnu doit orienter la facture vers une analyse manuelle. Il ne doit jamais conduire à une acceptation par défaut.

Comment organiser l’interrogation des statuts en production ?

En production, l’interrogation doit pouvoir reprendre après une interruption, rester bornée et respecter les quotas. Enregistrez chaque tentative, appliquez une temporisation exponentielle avec un décalage aléatoire, respectez Retry-After et basculez les traitements anormalement longs vers le rapprochement au lieu de les interroger indéfiniment.

L’API publie des limites, pas un intervalle d’interrogation obligatoire. Le guide officiel des limites de débit indique actuellement 30 requêtes par seconde, 120 par minute et 1 200 par heure pour le point d’accès au statut d’une facture. Les autres routes /sessions/*, notamment celles du statut de session et des UPO, autorisent 10 requêtes par seconde, 120 par minute et 1 200 par heure. Une réponse 429 contient Retry-After.

La combinaison de ces limites compte. Une boucle qui s’exécute chaque seconde peut respecter le plafond par seconde pendant un petit test, tout en épuisant le quota horaire en production. Après un déploiement ou une panne, plusieurs processus de traitement peuvent aussi provoquer des rafales synchronisées. Le décalage aléatoire répartit ces requêtes, tandis qu’un next_attempt_at enregistré permet de reprendre le même calendrier après un redémarrage.

submit invoice
persist local_id, session_reference, invoice_reference, submitted_hash

repeat with bounded exponential backoff and jitter:
  response = get invoice status
  persist code, details, extensions, checked_at

  if response is 429:
    schedule next attempt from Retry-After
  else if code is 100 or 150:
    schedule next attempt
  else if code is 200 and ksef_number is present:
    persist ksef_number and status timestamps
    retrieve, verify, and archive UPO
    finish as accepted
  else if code is documented terminal failure:
    finish as failed and route to the matching repair path
  else:
    stop automatic acceptance and request manual investigation

if processing exceeds the operational deadline:
  move record to reconciliation queue

Le délai opérationnel maximal est votre garde-fou, pas un statut KSeF inventé. Il doit empêcher un traitement de réessayer indéfiniment tout en conservant le dossier pour des vérifications ultérieures. Enregistrez au minimum l’heure de la dernière tentative, le nombre de tentatives, les détails de la dernière réponse et la prochaine tentative planifiée. Ces données suffisent à reprendre l’interrogation après l’arrêt du processus.

Comment récupérer les UPO d’une facture et d’une session ?

Récupérez l’UPO d’une facture une fois que celle-ci a atteint le statut 200 ; récupérez les pages UPO agrégées uniquement lorsque les conditions propres à la session sont remplies. L’artefact d’une facture peut exister alors qu’une session interactive reste ouverte.

Dans le contrat OpenAPI actuel, KSeF expose trois routes authentifiées :

  • GET /sessions/{sessionReferenceNumber}/invoices/{invoiceReferenceNumber}/upo
  • GET /sessions/{sessionReferenceNumber}/invoices/ksef/{ksefNumber}/upo
  • GET /sessions/{sessionReferenceNumber}/upo/{upoReferenceNumber} pour une page UPO agrégée

La réponse de statut peut aussi fournir une URL signée upoDownloadUrl ou downloadUrl. Récupérez cette URL de stockage avec une simple requête HTTP GET, sans y joindre le jeton d’accès KSeF. Les descriptions OpenAPI précisent que les téléchargements par ces URL signées ne sont pas comptabilisés dans les limites de l’API et qu’ils expirent à l’horodatage indiqué dans la réponse.

Cette distinction est importante. Les routes de l’API exigent l’un des périmètres d’autorisation énumérés par le contrat actuel, notamment InvoiceWrite, Introspection, PefInvoiceWrite ou EnforcementOperations. Les anciennes indications présentant la récupération par l’API comme non authentifiée ne correspondent pas au contrat à appliquer aujourd’hui. L’authentification est obligatoire pour la route de l’API KSeF ; l’URL de stockage signée doit être téléchargée sans votre jeton d’accès.

L’UPO d’une facture devient disponible après l’acceptation de celle-ci et l’attribution d’un numéro KSeF. L’UPO agrégé devient disponible après la fermeture de la session, le traitement de tous les documents et le stockage permanent d’au moins l’un d’eux avec un numéro KSeF. La fermeture d’une session interactive ne doit donc pas constituer une condition préalable à la collecte de l’UPO d’une facture déjà disponible.

Comment vérifier l’UPO avant de l’archiver ?

N’archivez l’UPO qu’après avoir comparé les octets exacts de la réponse au hachage de transport, puis vérifié le schéma XML, la signature et votre enregistrement de soumission. Réussir à analyser le XML est utile, mais ne constitue pas un contrôle complet de l’intégrité ni de l’identité.

Chaque réponse réussie de téléchargement d’une facture ou d’un UPO expose x-ms-meta-hash, le hachage SHA-256 du document renvoyé encodé en Base64. Lisez le corps sous forme d’octets, calculez le SHA-256 de ces octets inchangés, encodez le résultat en Base64, puis comparez-le à l’en-tête avant toute transformation ou normalisation du XML.

Validez ensuite le XML avec le schéma XSD officiel de l’UPO v4-3. UPO v4-3 est la version par défaut depuis le 22 décembre 2025 et repose sur un schéma unique pour les UPO de facture et de session. Il comprend TrybWysylki, qui distingue les modes d’envoi Online et Offline. Le journal des modifications de l’API consigne ce changement de version et le fonctionnement du hachage.

Validez ensuite la signature XAdES et sa chaîne de confiance avec les éléments appropriés fournis par le ministère. Enfin, comparez les champs métier du document signé à votre enregistrement de soumission : référence de session, hachage de la facture, NIP du vendeur, numéro local de la facture, numéro KSeF, date d’émission, horodatages de soumission et d’acquisition, ainsi que mode d’envoi.

Effectuez ces contrôles séparément et conservez le résultat de chacun. Un hachage de réponse correct prouve que vous avez stocké les octets transmis dans cette réponse. La validation du schéma prouve la conformité structurelle. La validation de la signature couvre l’authenticité et l’intégrité selon le modèle de confiance retenu. La correspondance des champs métier prouve que l’artefact appartient à la facture que vous souhaitiez traiter.

Que doit contenir votre dossier de preuves KSeF ?

Un dossier KSeF durable doit conserver les identifiants, l’historique des états, les octets exacts de l’UPO et les résultats des vérifications. Si vous ne stockez que le numéro KSeF, vous ne pourrez pas reproduire la manière dont votre système a établi sa conclusion.

Élément de preuve Pourquoi le conserver
Clé primaire et numéro métier de la facture locale Rattache la preuve KSeF à votre écriture comptable
Hachage exact du XML FA(3) soumis Identifie le document envoyé et facilite les contrôles de doublons
Références de session et de facture Permet l’interrogation du statut, la récupération de l’UPO et l’analyse par l’équipe d’assistance
Numéro KSeF Consigne l’identifiant attribué après l’acceptation
Dernier code de statut, avec sa description, ses détails et ses extensions Conserve le résultat officiel du traitement et le contexte structuré des erreurs
Dates de facturation, d’acquisition et de stockage permanent Préserve la distinction entre les horodatages au lieu de déduire un état de leur ordre
Octets exacts du XML UPO Conserve la preuve indépendamment de l’infrastructure de transmission
SHA-256 calculé et x-ms-meta-hash Consigne la comparaison d’intégrité de la réponse
Version du schéma UPO et résultat de sa validation Indique le contrat structurel vérifié
Résultat de la signature XAdES et de la chaîne de confiance Consigne la vérification de l’authenticité
Horodatages de récupération et de vérification Indique quand la preuve a été collectée et contrôlée
Historique des nouvelles tentatives, réparations, corrélations et traces Rend les échecs reproductibles et exploitables par les équipes opérationnelles

Conservez les trois horodatages KSeF dans des champs distincts. invoicingDate, acquisitionDate et permanentStorageDate correspondent à des événements différents. Ne déduisez pas une machine à états de leur ordre apparent. Le code de statut et les identifiants enregistrés restent la référence faisant foi pour les décisions du flux de travail.

Conservez également les octets bruts, même si vous extrayez des champs faciles à rechercher. Une clé de stockage d’objets associée à un hachage de contenu convient, à condition que la conservation et les contrôles d’accès respectent vos exigences en matière de preuves. L’URL temporaire ne doit pas remplacer l’objet. Elle n’est qu’un moyen parmi d’autres de le récupérer.

Comment reprendre après un échec ou l’expiration d’un lien ?

La reprise s’appuie sur les identifiants persistants et le statut, pas sur une URL signée mise en cache. Si une URL expire, interrogez de nouveau KSeF par la procédure authentifiée pour obtenir un chemin de récupération à jour.

Après un problème de transport ou le redémarrage d’un processus, reprenez à partir de la référence de facture enregistrée et du dernier statut relevé. En cas de 429, respectez précisément Retry-After. Pour les statuts 100 et 150, poursuivez le calendrier borné. Face à un échec terminal documenté, arrêtez l’interrogation et créez une procédure de correction adaptée à l’erreur au lieu de renvoyer la facture sans discernement.

Le statut 440 exige une procédure de rapprochement spécifique. Examinez ses extensions structurées, retrouvez la soumission d’origine, puis comparez l’identité de la facture dans votre système et son hachage immuable. Ce n’est qu’ensuite que vous pourrez déterminer si le document original accepté constitue le résultat valide pour votre facture locale. Une réponse signalant un doublon reste un échec pour l’opération tentée.

Utilisez les totaux de la session comme deuxième ligne de défense. Comparez invoiceCount, successfulInvoiceCount et failedInvoiceCount à vos dossiers par facture. Une différence peut révéler une tâche perdue, un résultat de traitement non enregistré ou une facture passée en analyse manuelle. Le guide consacré aux sessions et aux UPO fournit les champs officiels au niveau de la session et les règles de disponibilité.

Au 28 août 2026, KSeF API 2.6.1 est la version la plus récente indiquée comme déployée en PRD. La version 2.7.1 a atteint TEST le 26 août 2026, avec un déploiement en DEMO prévu le 15 septembre 2026 et en PRD le 23 septembre 2026. Les modifications documentées ne changent pas ce flux de statut et d’UPO, mais la documentation de production ne doit pas présenter la version 2.7.1 comme déployée en production avant cette date. Consultez de nouveau le journal des modifications officiel lors de la mise en œuvre ou de la révision de l’intégration.

Comment KSeF Kit assure la traçabilité de bout en bout

KSeF Kit applique aux factures Stripe le même enchaînement fondé sur les preuves. Il convertit les factures Stripe finalisées au format FA(3), les soumet, attend leur acceptation, stocke l’UPO et inscrit le numéro KSeF dans les métadonnées Stripe.

Cette mise en œuvre met clairement en évidence le caractère asynchrone du traitement. La finalisation dans Stripe ne vaut pas acceptation de la facture par KSeF. KSeF Kit attend le résultat officiel et conserve l’artefact qui le prouve. Vous pouvez consulter la documentation sur le processus de dépôt pour connaître la séquence fonctionnelle, ou la page produit KSeF Kit pour découvrir l’intégration à Stripe.

La règle générale reste la même, que vous développiez l’intégration ou utilisiez un produit : conservez chaque référence, arrêtez-vous à chaque statut terminal, vérifiez l’artefact téléchargé et archivez une preuve qui reste exploitable après l’expiration de son URL. Vous transformerez ainsi un appel d’API réussi en un résultat que vous pourrez rapprocher de vos données et justifier plus tard.

Si vous émettez des factures via Stripe et préférez ne pas développer vous-même ce mécanisme d’interrogation et de conservation des preuves, découvrez comment KSeF Kit les dépose et les consigne.

Articles similaires

Pret a recruter plus intelligemment ?

Commencez gratuitement pendant 30 jours. Résiliez avant la fin et vous ne payez rien. Configurez votre premier pipeline de recrutement en quelques minutes.

Commencer gratuitement