{"openapi":"3.1.0","info":{"title":"Pont Factur-X API","description":"API publique Pont-FacturX : extraction OCR, conversion PDF → Factur-X,\nvalidation technique et suivi des conversions.\n\nURL de base : `https://api.pont-facturx.com`\n\n## Authentification\n\nToutes les requêtes portent une clé API en Bearer :\n\n```\nAuthorization: Bearer sk_live_xxxxxxxxxxxxxxxx\n```\n\nLes clés se créent depuis Réglages → API et ne sont affichées qu'une fois.\n\nSeule exception : `POST /v1/auth/api-keys` exige une session du tableau de bord\n(`SessionAuth`, JWT). Une clé API ne peut pas en créer une autre.\n\n## Environnements\n\n| Préfixe | Crédits | Quotas | Conservation | Transmission externe |\n| --- | --- | --- | --- | --- |\n| `sk_live_` | 1 crédit par conversion | 30 req/min | selon l'offre | autorisée |\n| `sk_test_` | aucun débit | 5/jour, 25/mois, 10/min | aucune | refusée (403) |\n\nLe moteur est **identique** dans les deux modes : un document produit avec une\nclé de test n'est jamais volontairement dégradé. Le marquage vit dans la\nréponse — en-têtes `X-Livemode: false` / `X-Environment: test` et champs\n`livemode`, `environment`, `transmission_allowed` dans les réponses JSON.\n\n## Idempotence\n\n`POST /v1/convert` accepte l'en-tête optionnel `Idempotency-Key` (1 à 200\ncaractères). Rejouer **la même** requête avec la même clé ne débite qu'un seul\ncrédit ; réutiliser la clé pour une requête différente renvoie `409`. Sans\nl'en-tête, chaque appel débite. L'en-tête est ignoré en mode test, où rien\nn'est débité.\n\n## Erreurs\n\nLes erreurs renvoient un corps JSON `{\"detail\": ...}`, objet structuré\n`{\"code\", \"message\"}` quand un code applicatif existe. Codes usuels :\n`400` (requête rejetée avant traitement, aucun débit), `401` (clé invalide),\n`402` (crédits épuisés), `403` (abonnement inactif ou opération interdite en\nmode test), `409` (conflit d'idempotence), `413` (fichier trop volumineux),\n`429` (rate limit ou quota du mode test), `500` (échec système, crédit\nremboursé automatiquement).\n\nUn rejet avant traitement ne débite jamais. Un échec métier après traitement\nconsomme le crédit. Un échec système le rembourse.\n\n## Périmètre\n\nPont-FacturX est une solution compatible : la conversion et la validation\ntechnique sont réalisées ici, la transmission réglementaire est déléguée à un\nconnecteur partenaire (Chorus Pro pour le B2G, en pilote privé).","version":"1.0.0"},"paths":{"/v1/conversions/{record_id}":{"get":{"tags":["Historique"],"summary":"Consulter une conversion","description":"Détail d'une conversion du compte authentifié : statut, profil, montants, SIRET, date d'expiration. Une conversion appartenant à un autre compte renvoie `404`.\n\nLes conversions effectuées avec une clé `sk_test_` ne sont jamais enregistrées et n'apparaissent donc pas ici.","operationId":"conversions_get_v1_conversions__record_id__get","parameters":[{"name":"record_id","in":"path","required":true,"schema":{"type":"string","title":"Record Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionSummary"}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"404":{"description":"Ressource inexistante ou n'appartenant pas au compte authentifié.","content":{"application/json":{"example":{"detail":"Conversion introuvable."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]},{"SessionAuth":[]}]}},"/v1/conversions":{"get":{"tags":["Historique"],"summary":"Lister les conversions du compte","description":"Renvoie les 500 dernières conversions du compte authentifié, triées par date décroissante. Les conversions expirées sont purgées et n'apparaissent plus. Les conversions faites avec une clé `sk_test_` ne sont pas conservées et ne figurent jamais dans cette liste.","operationId":"conversions_list_v1_conversions_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionListResponse"}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]},{"SessionAuth":[]}]}},"/v1/conversions/{record_id}/download/{kind}":{"get":{"tags":["Historique"],"summary":"Télécharger le fichier d'une conversion","description":"Re-télécharge un artefact d'une conversion du compte authentifié. `kind` vaut `pdf` (Factur-X, `application/pdf`) ou `xml` (CII brut, `application/xml`).\n\nUne conversion appartenant à un autre compte renvoie `404`, comme une conversion inexistante : la réponse ne révèle pas l'existence de la ressource.","operationId":"conversions_download_v1_conversions__record_id__download__kind__get","parameters":[{"name":"record_id","in":"path","required":true,"schema":{"type":"string","title":"Record Id"}},{"name":"kind","in":"path","required":true,"schema":{"type":"string","title":"Kind"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Fichier demandé.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}},"application/xml":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"`kind` inconnu.","content":{"application/json":{"example":{"detail":"Unsupported download kind"}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"404":{"description":"Conversion introuvable, expirée, ou fichier plus disponible.","content":{"application/json":{"example":{"detail":"Requested file not available"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]},{"SessionAuth":[]}]}},"/v1/conversions/{record_id}/send-pdp":{"post":{"tags":["Transmission"],"summary":"Transmettre une conversion (Chorus Pro / PDP)","description":"Dépose une conversion existante auprès du connecteur partenaire configuré. **Bêta, pilote privé B2G** : la synchronisation du statut est manuelle et aucun statut final n'est affiché sans retour explicite de la plateforme destinataire.\n\nCorps JSON : `destination` et `recipient_siret`. Refusé avec une clé `sk_test_` (`403 transmission_forbidden_in_test_mode`).","operationId":"conversions_send_pdp_v1_conversions__record_id__send_pdp_post","parameters":[{"name":"record_id","in":"path","required":true,"schema":{"type":"string","title":"Record Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdpSendRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdpSendResponse"}}}},"400":{"description":"Données de transmission invalides ou conversion non transmissible.","content":{"application/json":{"example":{"detail":"Le SIRET destinataire est requis."}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Transmission externe refusée avec une clé `sk_test_`.","content":{"application/json":{"example":{"detail":{"code":"transmission_forbidden_in_test_mode","message":"La transmission externe (Chorus Pro, PDP) est interdite avec une clé de test sk_test_. Utilisez une clé sk_live_."}}}}},"404":{"description":"Ressource inexistante ou n'appartenant pas au compte authentifié.","content":{"application/json":{"example":{"detail":"Conversion introuvable."}}}},"502":{"description":"Le partenaire de transmission a refusé ou n'a pas répondu.","content":{"application/json":{"example":{"detail":"Échec de transmission côté partenaire. Consulte les logs techniques."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]},{"SessionAuth":[]}]}},"/v1/conversions/{record_id}/pdp-status":{"get":{"tags":["Transmission"],"summary":"Suivre le statut d'une transmission","description":"Renvoie le dernier statut connu de la transmission d'une conversion. `status: \"not_sent\"` quand aucune transmission n'existe.\n\nAjoutez `?sync=true` pour interroger la plateforme destinataire au moment de l'appel. **Bêta, pilote privé B2G** : sans `sync`, le statut est celui du dernier échange, pas un état temps réel.","operationId":"conversions_pdp_status_v1_conversions__record_id__pdp_status_get","parameters":[{"name":"record_id","in":"path","required":true,"schema":{"type":"string","title":"Record Id"}},{"name":"sync","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Sync"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PdpStatusResponse"}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"404":{"description":"Ressource inexistante ou n'appartenant pas au compte authentifié.","content":{"application/json":{"example":{"detail":"Conversion introuvable."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]},{"SessionAuth":[]}]}},"/v1/auth/api-keys":{"get":{"tags":["Compte"],"summary":"Lister les clés API actives","description":"Liste les clés non révoquées du compte : préfixe, environnement (`live` / `test`), date de création et dernière utilisation. La valeur complète d'une clé n'est jamais renvoyée.","operationId":"list_api_keys_v1_auth_api_keys_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Clés actives du compte.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyOut"},"title":"Response List Api Keys V1 Auth Api Keys Get"},"example":[{"id":"3f1c8f2a-6a0d-4f2b-9f1e-2b7d1c9a5e10","name":"Production ERP","key_prefix":"sk_live_9f2c1a4b","environment":"live","created_at":"2026-02-01T09:12:44Z","last_used_at":"2026-03-14T08:03:10Z"}]}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]},{"SessionAuth":[]}]},"post":{"tags":["Compte"],"summary":"Créer une clé API","description":"Crée une clé `sk_live_` (abonnement Pro ou Business actif requis) ou `sk_test_` (e-mail vérifié suffisant). **La valeur complète n'est renvoyée qu'ici, une seule fois.**\n\nLimites : 5 clés live actives, 2 clés de test actives par compte. Cette opération exige une session du tableau de bord (JWT) : une clé API ne peut pas en créer une autre.","operationId":"create_api_key_v1_auth_api_keys_post","security":[{"SessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreate"}}}},"responses":{"201":{"description":"Clé créée. `key` n'est jamais réaffiché.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"},"example":{"id":"3f1c8f2a-6a0d-4f2b-9f1e-2b7d1c9a5e10","name":"Production ERP","key_prefix":"sk_live_9f2c1a4b","environment":"live","created_at":"2026-02-01T09:12:44Z","key":"sk_live_9f2c1a4b…"}}}},"400":{"description":"Nombre maximal de clés actives atteint pour cet environnement.","content":{"application/json":{"example":{"detail":"Maximum 5 clés API actives par compte."}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"422":{"description":"Requête invalide.","content":{"application/json":{"example":{"detail":"Le nom de la clé est requis."}}}}}}},"/v1/auth/api-keys/{key_id}":{"delete":{"tags":["Compte"],"summary":"Révoquer une clé API","description":"Révoque immédiatement et définitivement une clé. Les requêtes portant cette clé reçoivent ensuite un `401 invalid_api_key`. Réponse `204` sans corps.","operationId":"revoke_api_key_v1_auth_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"204":{"description":"Clé révoquée."},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"404":{"description":"Clé inexistante, déjà révoquée, ou appartenant à un autre compte.","content":{"application/json":{"example":{"detail":"Clé introuvable."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]},{"SessionAuth":[]}]}},"/v1/account/usage":{"get":{"tags":["Compte"],"summary":"Consulter le quota et le plan du compte","description":"Renvoie le plan actif, le solde de crédits (gratuits, abonnement, achetés) et la limite de taux. À appeler avant une série de conversions pour éviter un `402` en cours de traitement. Ne débite rien.","operationId":"account_usage_v1_account_usage_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Plan et crédits du compte authentifié.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountUsageOut"},"example":{"plan":"Abonnement Pro","subscription_status":"active","credits_available":187,"free_remaining":0,"subscription_remaining":187,"paid_credits":0,"rate_limit":"30 requests/minute"}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"429":{"description":"Trop de requêtes. Le rate limit HTTP renvoie un en-tête `Retry-After` ; le quota du mode test renvoie un code applicatif.","content":{"application/json":{"examples":{"rate_limit":{"value":{"error":"Rate limit exceeded: 30 per 1 minute"}},"test_quota_exceeded":{"value":{"detail":{"code":"test_quota_exceeded","message":"Quota du mode test atteint (5 requêtes/jour, 25/mois). Passez à une clé sk_live_ pour un usage en production."}}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]},{"SessionAuth":[]}]}},"/v1/extract":{"post":{"tags":["Conversion"],"summary":"Extraire les données d'un PDF (OCR)","description":"Lit un PDF de facture et renvoie les données extraites en JSON. Aucun document Factur-X n'est généré et **aucun crédit n'est débité**.\n\nWorkflow en deux temps :\n\n1. `POST /v1/extract` → `invoice_data`\n2. relecture / correction du JSON\n3. `POST /v1/convert` avec `invoice_data` → PDF Factur-X\n\nAvec une clé `sk_test_`, la réponse porte en plus `livemode: false`, `environment: \"test\"`, `transmission_allowed: false` et les en-têtes `X-Livemode` / `X-Environment` ; le fichier envoyé est supprimé immédiatement.","operationId":"extract_v1_extract_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_extract_v1_extract_post"}}}},"responses":{"200":{"description":"Données extraites du PDF.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Extract V1 Extract Post"},"example":{"job_id":"0f0a4f6e-2c39-4a6e-9d21-9c3f0f7f1f8e","invoice_data":{"invoiceNumber":"FA-2026-0042","issueDate":"2026-03-14","currency":"EUR","totalHT":1250.0,"totalTVA":250.0,"totalTTC":1500.0,"seller":{"name":"ACME SAS","siret":"12345678900017"},"buyer":{"name":"Client SARL","siret":"98765432100019"}},"raw":{"...":"sortie brute du moteur d'extraction"}}}}},"400":{"description":"Requête rejetée avant traitement : type de fichier non accepté, PDF vide ou illisible, `invoice_data` non JSON, `Idempotency-Key` invalide. Aucun crédit débité.","content":{"application/json":{"example":{"detail":"Veuillez envoyer un fichier PDF."}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"413":{"description":"Fichier au-delà de la taille maximale acceptée (15 Mo).","content":{"application/json":{"example":{"detail":{"code":"FILE_TOO_LARGE","message":"Fichier trop volumineux (max 15 Mo)."}}}}},"429":{"description":"Trop de requêtes. Le rate limit HTTP renvoie un en-tête `Retry-After` ; le quota du mode test renvoie un code applicatif.","content":{"application/json":{"examples":{"rate_limit":{"value":{"error":"Rate limit exceeded: 30 per 1 minute"}},"test_quota_exceeded":{"value":{"detail":{"code":"test_quota_exceeded","message":"Quota du mode test atteint (5 requêtes/jour, 25/mois). Passez à une clé sk_live_ pour un usage en production."}}}}}}},"500":{"description":"Échec du moteur d'extraction.","content":{"application/json":{"example":{"detail":"Échec de l'extraction OCR. Réessayez ou contactez le support."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/convert":{"post":{"tags":["Conversion"],"summary":"Convertir un PDF en Factur-X","description":"Génère un PDF hybride Factur-X (PDF/A-3 avec XML CII embarqué) et le renvoie directement en `application/pdf`.\n\n- `invoice_data` absent → extraction OCR automatique.\n- `profile` : `MINIMUM`, `BASIC_WL` (défaut) ou `EN16931`.\n- Débit : 1 crédit avec une clé `sk_live_`, aucun avec `sk_test_`.\n\n**En-tête `Idempotency-Key`** (optionnel, 1 à 200 caractères) : rejouer la même requête avec la même clé ne débite qu'un crédit ; réutiliser la clé pour une requête différente (autre fichier, autre profil, autres données) renvoie `409`. Sans l'en-tête, chaque appel débite. En mode test l'en-tête est ignoré : rien n'est débité.\n\nLe résultat de la validation technique du document généré part dans les en-têtes `X-Facturx-Validation-Status` (`PASSED` / `VALIDATION_FAILED`) et `X-Facturx-Validation` (détail JSON, borné en taille). Une validation en échec **ne produit pas** une erreur serveur : le PDF est renvoyé en `200` et le crédit est consommé, la cause étant les données fournies.\n\nAvec une clé `sk_test_`, la réponse porte aussi `X-Livemode: false`, `X-Environment: test` et `X-Transmission-Allowed: false` ; le document produit est identique à celui d'une clé live.","operationId":"convert_v1_convert_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_convert_v1_convert_post"}}}},"responses":{"200":{"description":"PDF Factur-X. En-têtes : `Content-Disposition`, `X-Facturx-Validation-Status`, `X-Facturx-Validation`.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-Facturx-Validation-Status":{"description":"`PASSED` ou `VALIDATION_FAILED`.","schema":{"type":"string"}},"X-Facturx-Validation":{"description":"Détail JSON de la validation exécutée.","schema":{"type":"string"}},"X-Livemode":{"description":"`false` avec une clé sk_test_ (absent sinon).","schema":{"type":"string"}}}},"400":{"description":"Requête rejetée avant traitement : type de fichier non accepté, PDF vide ou illisible, `invoice_data` non JSON, `Idempotency-Key` invalide. Aucun crédit débité.","content":{"application/json":{"example":{"detail":"Veuillez envoyer un fichier PDF."}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"402":{"description":"Crédits épuisés : aucun crédit n'est débité, la requête est rejetée.","content":{"application/json":{"example":{"detail":{"code":"no_credits","message":"Aucun crédit disponible. Rechargez votre compte."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"409":{"description":"`Idempotency-Key` déjà utilisée pour une requête différente.","content":{"application/json":{"example":{"detail":{"code":"idempotency_key_reused","message":"Cette Idempotency-Key a déjà été utilisée pour une autre requête. Utilisez une clé unique par conversion."}}}}},"413":{"description":"Fichier au-delà de la taille maximale acceptée (15 Mo).","content":{"application/json":{"example":{"detail":{"code":"FILE_TOO_LARGE","message":"Fichier trop volumineux (max 15 Mo)."}}}}},"429":{"description":"Trop de requêtes. Le rate limit HTTP renvoie un en-tête `Retry-After` ; le quota du mode test renvoie un code applicatif.","content":{"application/json":{"examples":{"rate_limit":{"value":{"error":"Rate limit exceeded: 30 per 1 minute"}},"test_quota_exceeded":{"value":{"detail":{"code":"test_quota_exceeded","message":"Quota du mode test atteint (5 requêtes/jour, 25/mois). Passez à une clé sk_live_ pour un usage en production."}}}}}}},"500":{"description":"Échec système. Le crédit éventuellement débité est remboursé automatiquement ; la réponse dit explicitement s'il l'a été.","content":{"application/json":{"example":{"detail":"Échec de la conversion Factur-X. Le crédit a été remboursé."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/validate":{"post":{"tags":["Validation"],"summary":"Valider un PDF Factur-X ou un XML CII","description":"Contrôle technique d'un document existant : profil détecté et URN, présence et nom de la pièce jointe XML, validation XSD, règles EN 16931 (Schematron), conteneur PDF/A. Envoi en multipart, champ `file` (PDF ou XML, 15 Mo maximum).\n\n**Stateless** : rien n'est enregistré, le fichier est supprimé après traitement. **Aucun crédit débité** aujourd'hui.\n\nUn document invalide renvoie `200` avec `valid: false` et des erreurs structurées — ce n'est pas une erreur serveur. Les `4xx` sont réservés aux précontrôles (taille, fichier vide, PDF chiffré) et les `5xx` aux pannes du moteur de validation.\n\nLe verdict porte sur les contrôles listés dans `checks` : il ne vaut pas acceptation par une plateforme destinataire.","operationId":"validate_document_v1_validate_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-internal-service-token","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Internal-Service-Token"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_validate_document_v1_validate_post"}}}},"responses":{"200":{"description":"Rapport de validation. `valid` résume le verdict, `checks` détaille chaque contrôle exécuté, `errors` liste les anomalies.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Validate Document V1 Validate Post"},"examples":{"document_valide":{"value":{"valid":true,"profile":"BASIC_WL","profile_urn":"urn:factur-x.eu:1p0:basicwl","facturx_version":"1.0","input_type":"pdf","xml_filename":"factur-x.xml","checks":{"xsd":{"status":"passed"},"schematron":{"status":"passed"},"pdfa":{"status":"passed"}},"errors":[],"engine_version":"1.0.0","request_id":"8b1f0f3a-1f2e-4a5b-9c8d-0e1f2a3b4c5d"}},"document_invalide":{"value":{"valid":false,"profile":"EN16931","input_type":"pdf","xml_filename":"factur-x.xml","checks":{"xsd":{"status":"failed"},"schematron":{"status":"skipped"},"pdfa":{"status":"passed"}},"errors":[{"code":"XML_SCHEMA_INVALID","severity":"error","message":"Élément 'ram:IssueDateTime' manquant."}],"engine_version":"1.0.0","request_id":"8b1f0f3a-1f2e-4a5b-9c8d-0e1f2a3b4c5d"}}}}}},"400":{"description":"Précontrôle échoué : fichier vide, illisible ou PDF chiffré.","content":{"application/json":{"example":{"detail":{"code":"EMPTY_FILE","message":"Fichier vide ou illisible."}}}}},"401":{"description":"Clé API manquante, invalide ou révoquée.","content":{"application/json":{"example":{"detail":{"code":"invalid_api_key","message":"Clé API invalide ou révoquée."}}}}},"403":{"description":"Accès refusé : abonnement inactif, e-mail non vérifié, ou opération interdite au mode test.","content":{"application/json":{"examples":{"subscription_inactive":{"value":{"detail":{"code":"subscription_inactive","message":"Votre abonnement n'est plus actif ou ne permet pas l'accès API."}}},"email_not_verified":{"value":{"detail":{"code":"email_not_verified","message":"Vérifiez votre adresse e-mail pour utiliser une clé de test."}}}}}}},"413":{"description":"Fichier au-delà de la taille maximale acceptée (15 Mo).","content":{"application/json":{"example":{"detail":{"code":"FILE_TOO_LARGE","message":"Fichier trop volumineux (max 15 Mo)."}}}}},"429":{"description":"Trop de requêtes. Le rate limit HTTP renvoie un en-tête `Retry-After` ; le quota du mode test renvoie un code applicatif.","content":{"application/json":{"examples":{"rate_limit":{"value":{"error":"Rate limit exceeded: 30 per 1 minute"}},"test_quota_exceeded":{"value":{"detail":{"code":"test_quota_exceeded","message":"Quota du mode test atteint (5 requêtes/jour, 25/mois). Passez à une clé sk_live_ pour un usage en production."}}}}}}},"500":{"description":"Panne du moteur de validation.","content":{"application/json":{"example":{"detail":"Échec du moteur de validation."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ApiKeyAuth":[]},{"SessionAuth":[]}]}},"/health":{"get":{"summary":"Disponibilité de l'API","description":"Sonde de disponibilité, sans authentification. Répond `{\"ok\": true}` quand l'API accepte du trafic. À utiliser pour vérifier qu'un sous-domaine ou un déploiement répond.","operationId":"health_health_get","responses":{"200":{"description":"L'API répond.","content":{"application/json":{"schema":{},"example":{"ok":true}}}},"429":{"description":"Trop de requêtes. Le rate limit HTTP renvoie un en-tête `Retry-After` ; le quota du mode test renvoie un code applicatif.","content":{"application/json":{"examples":{"rate_limit":{"value":{"error":"Rate limit exceeded: 30 per 1 minute"}},"test_quota_exceeded":{"value":{"detail":{"code":"test_quota_exceeded","message":"Quota du mode test atteint (5 requêtes/jour, 25/mois). Passez à une clé sk_live_ pour un usage en production."}}}}}}}},"tags":["Service"]}}},"components":{"schemas":{"AccountUsageOut":{"properties":{"plan":{"type":"string","title":"Plan"},"subscription_status":{"type":"string","title":"Subscription Status"},"credits_available":{"type":"integer","title":"Credits Available"},"free_remaining":{"type":"integer","title":"Free Remaining"},"subscription_remaining":{"type":"integer","title":"Subscription Remaining"},"paid_credits":{"type":"integer","title":"Paid Credits"},"rate_limit":{"type":"string","title":"Rate Limit"}},"type":"object","required":["plan","subscription_status","credits_available","free_remaining","subscription_remaining","paid_credits","rate_limit"],"title":"AccountUsageOut"},"ApiKeyCreate":{"properties":{"name":{"type":"string","title":"Name"},"environment":{"type":"string","enum":["live","test"],"title":"Environment","default":"live"}},"type":"object","required":["name"],"title":"ApiKeyCreate"},"ApiKeyCreated":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"key_prefix":{"type":"string","title":"Key Prefix"},"environment":{"type":"string","title":"Environment","default":"live"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"key":{"type":"string","title":"Key"}},"type":"object","required":["id","name","key_prefix","created_at","last_used_at","revoked_at","key"],"title":"ApiKeyCreated"},"ApiKeyOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"key_prefix":{"type":"string","title":"Key Prefix"},"environment":{"type":"string","title":"Environment","default":"live"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"}},"type":"object","required":["id","name","key_prefix","created_at","last_used_at","revoked_at"],"title":"ApiKeyOut"},"Body_convert_v1_convert_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"profile":{"type":"string","title":"Profile","default":"BASIC_WL"},"invoice_data":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoice Data"}},"type":"object","required":["file"],"title":"Body_convert_v1_convert_post"},"Body_extract_v1_extract_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_extract_v1_extract_post"},"Body_validate_document_v1_validate_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_validate_document_v1_validate_post"},"ConversionListResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ConversionSummary"},"type":"array","title":"Items"}},"type":"object","required":["items"],"title":"ConversionListResponse"},"ConversionSummary":{"properties":{"id":{"type":"string","title":"Id"},"file_name":{"type":"string","title":"File Name"},"profile":{"type":"string","title":"Profile"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"invoice_number":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invoice Number"},"client_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Name"},"amount_total":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amount Total"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"recipient_siret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Siret"},"destinataire_code_service":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Destinataire Code Service"},"destinataire_numero_engagement":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Destinataire Numero Engagement"},"fournisseur_siret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fournisseur Siret"}},"type":"object","required":["id","file_name","profile","status","created_at"],"title":"ConversionSummary"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"PdpSendRequest":{"properties":{"recipient_siret":{"type":"string","maxLength":14,"minLength":14,"title":"Recipient Siret"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"destination":{"type":"string","title":"Destination","default":"chorus_pro"},"force_resend":{"type":"boolean","title":"Force Resend","default":false},"use_complete_submission":{"type":"boolean","title":"Use Complete Submission","default":false},"destinataire_id_structure_cpp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Destinataire Id Structure Cpp"},"destinataire_code_service":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Destinataire Code Service"},"destinataire_numero_engagement":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Destinataire Numero Engagement"},"mode_depot":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode Depot"},"type_facture":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type Facture"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","required":["recipient_siret"],"title":"PdpSendRequest"},"PdpSendResponse":{"properties":{"record_id":{"type":"string","title":"Record Id"},"provider":{"type":"string","title":"Provider"},"destination":{"type":"string","title":"Destination"},"transmission_id":{"type":"string","title":"Transmission Id"},"status":{"type":"string","title":"Status"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"}},"type":"object","required":["record_id","provider","destination","transmission_id","status"],"title":"PdpSendResponse"},"PdpStatusResponse":{"properties":{"record_id":{"type":"string","title":"Record Id"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"},"destination":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Destination"},"transmission_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transmission Id"},"status":{"type":"string","title":"Status"},"provider_reference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider Reference"},"recipient_siret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Siret"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["record_id","status"],"title":"PdpStatusResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{},"tokenUrl":"/v1/auth/login"}}},"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"sk_live_... | sk_test_...","description":"Clé API en Bearer : `Authorization: Bearer sk_live_...`.\n\nLes clés se créent depuis Réglages → API. Une clé `sk_live_` exige un abonnement Pro ou Business actif ; une clé `sk_test_` exige seulement une adresse e-mail vérifiée."},"SessionAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Jeton de session du tableau de bord (JWT), obtenu à la connexion sur https://www.pont-facturx.com.\n\nRéservé aux opérations qu'une clé API ne peut pas effectuer, comme la création d'une clé API."}}},"tags":[{"name":"Conversion","description":"Extraction OCR et génération Factur-X (PDF/A-3 + XML CII)."},{"name":"Validation","description":"Contrôles techniques d'un PDF Factur-X ou d'un XML CII : XSD, règles EN 16931 (Schematron), conteneur PDF/A. Stateless, rien n'est conservé."},{"name":"Historique","description":"Consultation et re-téléchargement des conversions du compte."},{"name":"Transmission","description":"Dépôt Chorus Pro et suivi de statut (bêta, pilote privé B2G). Refusé avec une clé de test."},{"name":"Compte","description":"Crédits, plan actif et gestion des clés API."},{"name":"Service","description":"Disponibilité de l'API."}],"servers":[{"url":"https://api.pont-facturx.com","description":"Production"}]}