# Factures France : PDF et Factur-X vers JSON, avec contrôles (`geckostar/factures-france-pdf-json`) Actor

Lit des factures PDF : données structurées Factur-X / ZUGFeRD quand elles sont présentes, sinon règles sur le texte, avec une confiance par champ. Contrôles français : SIREN, TVA, HT + TVA = TTC, mentions obligatoires. Aucun modèle de langage.

- **URL**: https://apify.com/geckostar/factures-france-pdf-json.md
- **Developed by:** [Gecko Lab](https://apify.com/geckostar) (community)
- **Categories:** Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 invoice parseds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Factures France : PDF et Factur-X vers JSON

Lit des factures PDF et renvoie un JSON normalisé, une confiance par champ et des contrôles propres
à la France. **Aucun modèle de langage, aucune clé d'API** dans cette version.

### Ordre de lecture

1. **Factur-X / ZUGFeRD 2.x** : le XML CII embarqué (pièce jointe PDF/A-3 `factur-x.xml`,
   `zugferd-invoice.xml`, `xrechnung.xml`) est lu directement. Profils reconnus : MINIMUM, BASIC WL,
   BASIC, EN 16931, EXTENDED. Confiance « haute » pour chaque champ présent.
2. **Couche texte** (lecture `pypdf`, mise en page conservée, 20 premières pages par défaut) + règles :
   SIREN/SIRET (clé vérifiée), TVA FR (cohérence avec le SIREN), IBAN (clé vérifiée), numéro, dates
   d'émission et d'échéance, totaux HT / TVA / TTC, noms vendeur et acheteur (heuristique, confiance basse).
3. **PDF sans texte** (scan) : statut `non_lisible_sans_modele`, non facturé.

Confiance par champ : `haute` (étiquette + validation), `moyenne` (étiquette ou validation),
`basse` (déduction par position), `champ_non_trouve` (valeur `null`, jamais inventée). La liste
`champs_non_trouves` reprend les champs absents.

Non pris en charge dans cette version : XML UBL, ZUGFeRD 1.0, images (JPG/PNG), lignes de facture en
lecture texte, factures en plusieurs devises.

### Contrôles (sans appel réseau)

| Code | Vérifie |
|---|---|
| `SIREN_VENDEUR`, `SIREN_ACHETEUR` | Clé de Luhn du SIREN ou du SIRET (exception La Poste) |
| `TVA_VENDEUR_COHERENTE`, `TVA_ACHETEUR_COHERENTE` | Le numéro de TVA FR porte ce SIREN et la bonne clé |
| `TOTAUX_COHERENTS` | HT + TVA = TTC à 0,02 € près |
| `VENTILATION_TVA` | Somme des montants de TVA par taux = total TVA (Factur-X) |
| `MENTIONS_OBLIGATOIRES` | Numéro, date, nom et SIREN/SIRET du vendeur, TVA du vendeur si TVA facturée, nom de l'acheteur, totaux, échéance ; en lecture texte : pénalités de retard et indemnité forfaitaire de 40 € |
| `SIREN_ACHETEUR_PRESENT` | SIREN de l'acheteur, une des nouvelles mentions de la facturation électronique (les autres ne sont pas vérifiées) |

Statut de chaque contrôle : `ok`, `echec` ou `non_verifiable`. La liste des mentions est volontairement
limitée à ce qui se lit de façon fiable ; elle ne vaut pas audit de conformité.

Option `checkSupplier` (désactivée par défaut) : contrôle du vendeur par le paquet commun (même moteur
que l'Actor « Contrôle fournisseur » : identité, TVA VIES, BODACC, verdict). Pas d'événement facturé en plus.

### Entrée

| Champ | Défaut | Rôle |
|---|---|---|
| `pdfUrls` | – | Liens http(s) publics |
| `pdfFile` | – | Un PDF déposé dans le formulaire |
| `keyValueStoreKeys` | – | « cle » (magasin par défaut) ou « magasin/cle » (magasin nommé) |
| `checkSupplier` | false | Contrôle du vendeur |
| `maxPdfMb` | 10 | Taille maximale d'un PDF (1 à 25 Mo) |
| `maxPages` | 20 | Pages lues en mode texte (1 à 50) |
| `maxItems` | 100 | Nombre maximal de factures (≤ 1000) |
| `maxConcurrency` | 2 | Factures en parallèle (1 à 4) |

Les liens d'enregistrement Apify (`https://api.apify.com/v2/key-value-stores/<id>/records/<clé>`) sont
lus par le SDK sur la plateforme (avec les droits de l'exécution), téléchargés comme un lien ordinaire en local.

### Sécurité

- Téléchargement : http/https, ports 80 et 443, sans identifiants dans l'URL ; toutes les adresses
  résolues doivent être publiques (refus de localhost, 127.0.0.0/8, 10/8, 172.16/12, 192.168/16,
  169.254/16, 100.64/10, ::1, fc00::/7, fe80::/10, NAT64 64:ff9b::/96 et 64:ff9b:1::/48, IPv4 dans IPv6...).
  La connexion TCP part vers l'adresse IP déjà vérifiée (backend réseau `PinnedPublicBackend`, TLS sur le
  nom d'origine) : pas de seconde résolution DNS hors contrôle. L'adresse jointe est revérifiée après
  connexion. 3 redirections au plus, chacune revérifiée ; aucun proxy implicite.
- Délai global de 90 s par téléchargement, abandon sous 10 Ko/s après 10 s, 15 s au plus sans recevoir
  d'octet ; contenu compressé refusé (`Accept-Encoding: identity`) ; taille bornée.
- Analyse de chaque PDF dans un **interpréteur jetable** (`factures_france/worker.py`) : espace mémoire
  plafonné à 300 Mo, temps CPU plafonné, aucun fichier écrit ; arrêt net (`kill`) à l'expiration du délai
  de 60 s. Le programme appelant n'est pas ré-importé (pas de `multiprocessing`).
- Plafonds pypdf abaissés (`limits.py`) : 10 Mo par flux décompressé, appliqués à chaque lecture.
- Texte tronqué à 200 000 caractères et blancs réduits avant les expressions régulières, dont les
  répétitions de blancs sont bornées.
- XML lu sans entités externes, sans DTD, sans réseau, 5 Mo au plus. PDF chiffrés et non-PDF refusés.
- Un XML Factur-X presque vide (moins de 3 champs clés) n'est pas une facture extraite : repli sur le
  texte, sinon `extraction_insuffisante`, non facturé.
- Journal : index, statut, méthode, taille et 12 premiers caractères du SHA-256. Jamais d'URL, de nom,
  d'IBAN, de SIREN ni de montant, y compris en cas d'erreur imprévue (seul le type d'erreur est noté).
- Mémoire : environ 150 Mo pour le processus principal + 300 Mo au plus par analyse. La concurrence
  effective est bornée par la mémoire allouée (512 Mo : 1 ; 1 Go : 2 ; 2 Go : 4). Mesure locale avec
  512 Mo et les PDF de preuve de la revue : 329 Mo au plus au total.

### Facturation

Un événement : `invoice-parsed`, facturé seulement si `statut = extrait`, c'est-à-dire XML Factur-X lu,
ou, en lecture texte, au moins 3 des 4 champs clés trouvés (numéro, date d'émission, total TTC, SIREN ou
TVA du vendeur). Non facturés : `extraction_insuffisante`, `non_lisible_sans_modele`, `erreur`, `doublon`.
Budget vérifié avant chaque lot, arrêt propre à la limite de dépense. Ne pas activer dans la console
l'événement synthétique `apify-default-dataset-item`.

### Données personnelles

Les factures contiennent des données personnelles (noms, adresses, IBAN). Les entrées, le jeu de données
et le relevé `BILAN` restent dans les stockages du compte Apify de l'utilisateur ; le journal ne contient ni
lien, ni nom, ni IBAN, ni SIREN, ni montant (journaux `httpx` et `httpcore` forcés au niveau WARNING).
Avec `checkSupplier`, le SIREN/SIRET et le numéro de TVA du vendeur, et eux seuls, partent vers l'API
Recherche d'entreprises, VIES et l'API du BODACC.

Sortie Factur-X bornée : 1 000 lignes, 50 taux de TVA, textes de
1 000 caractères ; un résultat refusé par le stockage devient une erreur `ELEMENT_TROP_GROS` non facturée
et le lot continue.

### Conditions d'utilisation / Terms

Outil destiné aux professionnels. Aucune valeur n'est inventée : un champ non lu vaut null, mais un champ lu peut être erroné, surtout en lecture du texte (d'où la confiance par champ). Vérifiez les résultats avant tout usage comptable, fiscal ou de paiement, en particulier l'IBAN. Les contrôles signalent des incohérences ; ils ne valent ni audit, ni attestation de conformité, ni conseil juridique, fiscal ou financier. Les factures fournies restent sous votre responsabilité et ne sont enregistrées que dans votre compte Apify. Dans les limites permises par la loi, l'éditeur ne répond pas des décisions prises sur la seule base de ces résultats, ni de l'usage que l'utilisateur en fait. Cette clause n'écarte aucun droit que la loi réserve aux consommateurs, notamment la garantie légale de conformité des contenus et services numériques.

Intended for business use. No value is invented, but a value read may be wrong: check results before any accounting, tax or payment use, especially the IBAN. Checks flag inconsistencies; they are not an audit or legal, tax or financial advice. To the extent permitted by law, the developer is not liable for decisions based solely on these results or for the user's use of them. Nothing here limits statutory consumer rights.

### Mentions légales / Legal notice

- Éditeur et vendeur / Publisher and seller : Audric Moussaoui, entrepreneur individuel (EI), nom commercial / trade name « geckostar »
- Adresse / Address : 88 rue Oberkampf, 75011 Paris, France
- Téléphone / Phone : +33 6 95 11 28 15
- Courriel / E-mail : audricmm@gmail.com
- SIREN : en cours d'attribution, déclaration d'activité déposée le 24/10/2026 / being assigned, registration filed on 24 October 2026
- Directeur de la publication / Publication director : Audric Moussaoui
- TVA non applicable, art. 293 B du CGI / VAT not applicable (French VAT franchise, art. 293 B CGI)
- Hébergement / Hosting : Apify Technologies s.r.o., Vodičkova 704/36, 110 00 Prague 1, République tchèque / Czech Republic (hello@apify.com)

# Actor input Schema

## `pdfUrls` (type: `array`):

Un lien http(s) public par ligne (ports 80 et 443). Les adresses locales ou privées sont refusées.

## `pdfFile` (type: `string`):

Un fichier PDF déposé depuis votre poste.

## `keyValueStoreKeys` (type: `array`):

Clés d'enregistrements PDF : « cle » (magasin par défaut de l'exécution) ou « nom-du-magasin/cle » (magasin nommé de votre compte).

## `checkSupplier` (type: `boolean`):

Ajoute un verdict sur le vendeur à partir de sources publiques (identité, TVA intracommunautaire, procédures collectives). Plus lent. Désactivé par défaut.

## `maxPdfMb` (type: `integer`):

Les fichiers plus gros sont refusés.

## `maxPages` (type: `integer`):

Seules les premières pages sont lues quand il n'y a pas de données Factur-X.

## `maxItems` (type: `integer`):

Garde-fou : l'exécution est refusée si la liste est plus longue.

## `maxConcurrency` (type: `integer`):

Entre 1 et 4, et au plus une analyse par tranche de 300 Mo de mémoire au-delà de 150 Mo (512 Mo : 1 ; 1 Go : 2 ; 2 Go : 4).

## Actor input object example

```json
{
  "pdfUrls": [
    "https://raw.githubusercontent.com/akretion/factur-x/master/tests/fixtures/pdf/invoice_EN16931.pdf"
  ],
  "checkSupplier": false,
  "maxPdfMb": 10,
  "maxPages": 20,
  "maxItems": 100,
  "maxConcurrency": 2
}
```

# Actor output Schema

## `results` (type: `string`):

Une ligne par saisie, dans la vue Synthèse ; les lignes non facturées portent facturable = false.

## `bilan` (type: `string`):

Compteurs de l'exécution : éléments traités, facturés et non facturés.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "pdfUrls": [
        "https://raw.githubusercontent.com/akretion/factur-x/master/tests/fixtures/pdf/invoice_EN16931.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("geckostar/factures-france-pdf-json").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "pdfUrls": ["https://raw.githubusercontent.com/akretion/factur-x/master/tests/fixtures/pdf/invoice_EN16931.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("geckostar/factures-france-pdf-json").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "pdfUrls": [
    "https://raw.githubusercontent.com/akretion/factur-x/master/tests/fixtures/pdf/invoice_EN16931.pdf"
  ]
}' |
apify call geckostar/factures-france-pdf-json --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,geckostar/factures-france-pdf-json"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/bDIgEbW6pmUli6AvJ/builds/ehTTQwaIN4wQSwjI3/openapi.json
