Aller au contenu

API REST

Accès mis à jour

Essayez les exemples fixes sans clé. Vos documents nécessitent une clé. Les nouvelles clés gratuites et d’essai sont fermées ; les clés existantes conservent leur quota.

URL de base : https://facturx.orvel.dev. Interface OpenAPI interactive sur /api, spécification lisible par machine sur /openapi.json.

Authentification

Endpoint Anonyme Avec clé API
POST /v1/invoices/validate Clé API requise décompté du quota
POST /v1/invoices/extract Clé API requise décompté du quota
POST /v1/invoices/generate 401 obligatoire
POST /v1/invoices/embed 401 obligatoire
POST /v1/invoices/preview-xml 401 obligatoire
GET /v1/usage 401 obligatoire

Envoyez Authorization: Bearer <clé> ou X-API-Key: <clé>. Forfaits et clés.

Les réponses décomptées exposent X-Plan, X-Usage-Used, X-Usage-Quota et X-Usage-Remaining.

GET /v1/demo

Sans clé. Renvoie les liens vers des exemples fixes et leurs rapports publiés ; aucun document personnalisé n'est traité.

POST /v1/trial-keys

Route fermée : 410 trial_issuance_closed, avec les liens de démonstration et de configuration. GET redirige vers le guide MCP. Les clés déjà délivrées restent valides jusqu'à leur expiration d'origine ; leur quota total ne se renouvelle pas.

Endpoints

POST /v1/invoices/generate

Corps : {"invoice": Invoice, "options": GenerateOptions}. Voir Champs de la facture pour l'objet Invoice.

options :

Champ Défaut Valeurs
profile en16931 basicwl, en16931, extended, extended-ctc-fr (MINIMUM/BASIC sont lus et validés, pas produits : la réforme française exige au moins EN 16931)
output facturx-pdf facturx-pdf (PDF/A-3 + CII), cii-xml, ubl-xml
language fr fr, en (langue du PDF visuel)
check fr-ctc base (EN 16931 seul), fr-ctc (EN 16931 + règles françaises BR-FR)
logo_url aucun URL HTTPS d'un logo PNG/SVG affiché dans l'en-tête du PDF
accent_color #1f3a5f Couleur hexadécimale des titres du PDF
footer_text aucun Texte libre en pied de page
party_check actif pour extended-ctc-fr, sinon inactif true interroge EU Verify avant d'émettre un fichier. false saute le contrôle.

Réponse : le document en binaire (application/pdf ou application/xml) avec un nom de fichier dans Content-Disposition. Avec Accept: application/json vous recevez :

{
  "filename": "F-2026-0042-facturx.pdf",
  "media_type": "application/pdf",
  "profile": "en16931",
  "output": "facturx-pdf",
  "content_base64": "JVBERi0xLjcK...",
  "totals": {"line_total": "2739.70", "tax_exclusive": "2739.70", "tax_total": "539.28",
             "tax_inclusive": "3278.98", "amount_due": "3278.98",
             "vat_breakdown": [{"category": "S", "rate": "20", "taxable_amount": "2680.00", "tax_amount": "536.00"}]},
  "validation": {"valid": true, "checks_run": ["xsd", "schematron:base", "schematron:fr-ctc"], "findings": []},
  "evidence": [{"id": "evd_4f0c9a12b7e34d18", "role": "seller", "siren": "552081317", "vat": "FR03552081317", "verdict": "invoice_ready"}]
}

En-têtes supplémentaires : X-Facturx-Profile, X-Facturx-Output, X-Facturx-Amount-Due, X-Facturx-Warnings. Quand un contrôle de partie a eu lieu : X-Facturx-Evidence-Id (un identifiant, ou plusieurs séparés par des virgules) et, si un registre était indisponible, X-Facturx-Party-Check: upstream_unavailable.

Le XML généré est toujours validé (XSD + schematron du check demandé) avant d'être renvoyé. Si une règle échoue vous recevez un 400 invalid_input avec les constats, jamais un fichier non conforme. Si une partie n'est pas prête à facturer vous recevez 400 party_not_ready et aucun fichier. Voir Parties prêtes à facturer.

Parties prêtes à facturer

party_check demande à EU Verify si le vendeur et l'acheteur peuvent figurer sur la facture. Le contrôle a lieu avant la construction du PDF ou du XML.

  • Il est actif quand profile vaut extended-ctc-fr et que vous omettez party_check.
  • Il est inactif pour en16931, extended et basicwl, sauf si vous mettez party_check à true.
  • party_check à false le saute, y compris pour extended-ctc-fr.

Une partie française (pays FR, un SIREN ou un SIRET, ou une TVA qui commence par FR) doit avoir un SIREN. La TVA est contrôlée, et déduite du SIREN si vous ne la donnez pas. L'IBAN du vendeur est contrôlé quand payment.iban est renseigné. L'adresse et l'EORI ne le sont que si vous les envoyez.

invoice_ready renvoie le fichier. Chaque élément de evidence peut contenir id (evd_ plus 16 caractères hexadécimaux), role, siren, siret, name, vat, vies_request_identifier, vies_name, iban, iban_checksum (mod-97), address, ban_id, eori et verdict. Le même identifiant est écrit sur la facture comme note de sujet AAI (EU Verify evidence evd_…). Rien n'est stocké.

not_ready est un HTTP 400. Aucun document n'est produit.

{
  "code": "party_not_ready",
  "message": "A party is not invoice-ready. No document was produced.",
  "details": [{
    "source": "eu-verify",
    "severity": "fatal",
    "rule": "vat_not_registered",
    "message": "not registered",
    "location": null,
    "test": null,
    "json_pointer": "/invoice/buyer/vat"
  }],
  "evidence": []
}

details[].json_pointer désigne le champ à corriger : /invoice/seller/siren, /invoice/buyer/vat, /invoice/payment/iban, et la même forme pour l'adresse et l'EORI. Codes fermés : siren_missing, siren_checksum, siren_unknown, siren_closed, siren_siret_mismatch, vat_missing, vat_malformed, vat_not_registered, iban_invalid, address_invalid, address_unmatched, eori_malformed, eori_not_registered.

Une panne de registre ne bloque pas le fichier. Le document est renvoyé et X-Facturx-Party-Check vaut upstream_unavailable. Si EU Verify lui-même est injoignable, cet en-tête vaut party check unavailable suivi du type d'erreur, et le fichier est quand même renvoyé. Un échec définitif bloque quand même, même si un autre registre est en panne en même temps. Dans une réponse party_not_ready, evidence ne liste que les parties qui ont réussi.

En MCP, generate_invoice refuse de la même façon et inclut l'identifiant de preuve dans le résumé quand le fichier est émis.

POST /v1/invoices/embed

multipart/form-data :

Partie Obligatoire Description
pdf oui Votre PDF de facture visuel
xml l'un des deux Fichier XML Factur-X / CII à incorporer
invoice_json l'un des deux JSON de facture ; le XML est généré à partir de celui-ci
profile non Profil lors de la génération depuis invoice_json (défaut en16931)
check non base ou fr-ctc (défaut)
language non fr ou en, langue des métadonnées
party_check même règle que generate Appliqué seulement quand invoice_json est envoyé. Un XML brut n'est pas contrôlé.

Réponse : application/pdf, un fichier PDF/A-3 avec le XML joint sous le nom factur-x.xml et les métadonnées XMP Factur-X. Le XML est validé d'abord ; l'UBL ne peut pas être incorporé (Factur-X est CII uniquement).

POST /v1/invoices/validate?check=fr-ctc

Envoyez le fichier en multipart/form-data (file) ou comme corps brut de la requête (Content-Type: application/pdf ou application/xml). Accepte les PDF Factur-X / ZUGFeRD, le XML CII et le XML UBL 2.1 Invoice ou CreditNote.

{
  "valid": true,
  "flavor": "factur-x",
  "profile": "en16931",
  "checks_run": ["pdf", "xsd", "schematron:base", "schematron:fr-ctc"],
  "checks_skipped": [],
  "error_count": 0,
  "warning_count": 1,
  "findings": [
    {"source": "schematron:base", "severity": "warning", "rule": "BR-CO-25", "message": "...", "location": "/rsm:...", "json_pointer": "/invoice/number"}
  ],
  "pdf": {"pages": 1, "attachments": ["factur-x.xml"], "pdfa": "3B", "facturx_xmp": "EN 16931"}
}
  • flavor : factur-x (CII), ubl-2.1-invoice, ubl-2.1-creditnote.
  • profile : détecté depuis le XML (minimum, basicwl, basic, en16931, extended, extended-ctc-fr).
  • severity : error (bloquant) ou warning. valid vaut false dès qu'il y a au moins une erreur.
  • json_pointer : le champ du JSON de facture pour ce constat quand il peut être nommé (/invoice/seller/siren, /invoice/number, …). Vide quand la règle ne correspond pas à un seul champ. Un agent peut corriger ce champ et rappeler generate.
  • pdf : uniquement pour une entrée PDF. pdfa est lu dans le XMP (3B attendu), facturx_xmp est le ConformanceLevel.

POST /v1/invoices/extract?include_xml=true

Même entrée que validate. Renvoie :

{
  "flavor": "factur-x",
  "profile": "en16931",
  "xml_filename": "factur-x.xml",
  "xml": "<?xml ...>",
  "fields": {
    "number": "F20260023", "type_code": "380", "issue_date": "2026-01-15", "due_date": "2026-02-14",
    "currency": "EUR",
    "seller": {"name": "...", "siren": "...", "vat_id": "FR...", "address": {...}},
    "buyer": {"name": "...", "siren": "...", "address": {...}},
    "totals": {"tax_exclusive": "...", "tax_total": "...", "tax_inclusive": "...", "amount_due": "..."},
    "vat_breakdown": [{"category": "S", "rate": "20", "taxable_amount": "...", "tax_amount": "..."}],
    "lines": [{"id": "1", "item_name": "...", "quantity": "1", "unit_price": "...", "net_amount": "...", "vat_rate": "20"}]
  }
}

POST /v1/invoices/preview-xml

Même corps que generate. Renvoie le XML CII (ou UBL) sans la passe schematron. Moyen économique d'itérer sur une correspondance de champs ; toujours validé contre les XSD.

GET /v1/schema/invoice, GET /v1/schema/options

JSON Schema (draft 2020-12) des objets Invoice et GenerateOptions. Utile pour générer des clients ou valider des formulaires.

GET /v1/usage

{"plan": "starter", "used": 412, "quota": 1000, "remaining": 588, "period": "2026-09"}

GET /v1/plans

Public, sans clé. Catalogue des plans avec les liens de paiement en libre-service et l'URL du portail client (ce qu'utilisent les boutons de la page des tarifs).

{"currency": "EUR", "plans": [{"id": "starter", "name": "Starter", "price_eur_month": 29, "quota": 1000, "checkout_url": "https://facturx.orvel.dev/v1/checkout/starter"}, ...], "portal_url": "https://facturx.orvel.dev/docs/account/", "mcp_url": "https://facturx.orvel.dev/mcp", "billing": "stripe"}

GET /v1/checkout/{plan}

Page de présentation publique (HTTP 200), sans création de session de paiement. plan vaut starter, pro ou scale. prepaid et l’ancienne route evaluation redirigent vers l’espace connecté. La route free redirige vers la démo.

POST /v1/checkout/{plan}

Action explicite d’achat ; crée une session et renvoie HTTP 303 vers Stripe Checkout. Les soumissions navigateur depuis un autre site sont refusées. Les forfaits mensuels sont des abonnements. Les crédits prépayés s’achètent depuis l’espace avec un compte vérifié : 10 EUR pour 100 opérations, sans expiration ni recharge automatique. Après paiement, Stripe redirige vers Votre clé API avec ?session_id=.

GET /v1/billing/session/{session_id}

Public. Après une session Checkout terminée, renvoie {api_key, plan, quota, customer_email}. La clé fx.<subscription_id>.<hmac> fonctionne immédiatement en REST et MCP.

POST /v1/billing/portal

Nécessite une clé Stripe (Authorization: Bearer fx.…). Renvoie {url} vers le portail client Stripe (changement de plan, résiliation, factures).

GET /health

{"status": "ok", "version": "0.1.9", "schematron": true}. schematron: false signifie que le moteur de règles redémarre ; les appels de validation renvoient 503 jusqu'à son retour (quelques secondes).

Erreurs

Toutes les erreurs partagent une seule forme :

{"code": "invalid_input", "message": "XML does not pass EN 16931 business rules", "details": [ ... ]}
HTTP code Signification
400 party_not_ready Un vendeur ou un acheteur a échoué au contrôle EU Verify. details désigne le champ. Aucun document n'est renvoyé.
400 invalid_input Document invalide, ou le XML généré/incorporé échoue à une règle métier (details = constats)
400 unsupported_profile Combinaison profil/sortie impossible (ex. UBL dans un PDF Factur-X)
400 not_an_einvoice Le PDF n'a pas de pièce jointe Factur-X / le XML n'est ni CII ni UBL
401 api_key_required, invalid_api_key Clé absente ou inconnue
402 quota_exceeded Quota mensuel du plan atteint
402 checkout_incomplete La session Stripe Checkout n'est pas encore payée
503 billing_unavailable Le paiement n'est pas encore configuré
413 too_large Corps supérieur à 15 Mo
422 validation_error Le JSON de la requête ne respecte pas le schéma (details[].loc désigne le champ)
429 rate_limited Limite anonyme atteinte ; ajoutez une clé
500 render_error Le rendu PDF a échoué (signalez-le)
503 schematron_unavailable Moteur de règles en démarrage ; réessayez après quelques secondes

Limites

  • Taille du corps 15 Mo. Un PDF Factur-X typique fait moins de 500 Ko.
  • La génération prend 0,5 à 2 s (rendu PDF + schematron). La validation 0,2 à 1 s.
  • Aucun document n'est stocké. Les journaux contiennent le numéro de facture et les identifiants de règles, jamais les montants ni les données des parties.