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
profilevautextended-ctc-fret que vous omettezparty_check. - Il est inactif pour
en16931,extendedetbasicwl, sauf si vous mettezparty_checkàtrue. party_checkàfalsele saute, y compris pourextended-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) ouwarning.validvautfalsedè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.pdfaest lu dans le XMP (3Battendu),facturx_xmpest 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¶
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.