Aller au contenu

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) ou warning. valid vaut false dès qu'il y a au moins une erreur.
  • 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": "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.