API REST¶
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 |
20 req/min par IP | décompté de votre quota, sans limite de débit |
POST /v1/invoices/extract |
20 req/min par IP | décompté de votre quota, sans limite de débit |
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 la clé dans Authorization: Bearer <clé> (ou X-API-Key: <clé>). Les clés sont délivrées à la fin du paiement Stripe, voir Tarifs.
Chaque réponse décomptée porte X-Plan, X-Usage-Used, X-Usage-Quota et X-Usage-Remaining.
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 |
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": []}
}
En-têtes supplémentaires : X-Facturx-Profile, X-Facturx-Output, X-Facturx-Amount-Due, X-Facturx-Warnings.
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.
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 |
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:..."}
],
"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.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": "free", "name": "Free", "price_eur_month": 0, "quota": 50, "checkout_url": "https://facturx.orvel.dev/v1/checkout/free"}, ...], "portal_url": "https://facturx.orvel.dev/docs/account/", "mcp_url": "https://facturx.orvel.dev/mcp", "billing": "stripe"}
GET /v1/checkout/{plan}¶
Public. plan vaut free, starter, pro ou scale. HTTP 303 vers Stripe Checkout. 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.0", "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 | 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.