/developpeurs · API partenaire
L'API Billies — devis et factures conformes dans ton logiciel.
Ton produit génère des devis signables en ligne et des factures légales françaises — numérotation séquentielle, TVA, mentions obligatoires, PDF, e-facturation via une plateforme de dématérialisation — sans développer un moteur de facturation. En marque grise : tes utilisateurs restent dans ton interface, les documents portent la mention « propulsé par Billies ». Ou en mode connecté : ton utilisateur branche son propre compte Billies, ton logiciel y crée et émet ses documents avec son accord.
Deux offres, la même API
Tous les endpoints, sans engagement ni frais de mise en service dans les deux cas. Seule la façon de payer change.
Intégré
99 € par mois · 10 sous-comptes actifs inclus ·puis 5 € par sous-compte actif
Le prix par sous-compte actif est dégressif, par tranche : 5 € par mois du 11ᵉ au 100ᵉ, 4 € du 101ᵉ au 500ᵉ, 3 € au-delà. Un sous-compte est « actif » un mois donné s'il a émis au moins un document ce mois-là. Un sous-compte qui n'émet rien ne coûte rien : tu peux créer un sous-compte pour chacun de tes utilisateurs sans regarder le compteur.
À l'acte
0 € par mois · 0,50 € par document émis
Dégressif par tranche, remis à zéro chaque mois : 0,50 € par document jusqu'à 999 par mois, puis 0,30 € de 1 000 à 9 999, puis 0,20 € au-delà. Pas d'abonnement : un mois sans émission est un mois à 0 €. Une carte est demandée à l'activation.
Dans les deux offres, les documents émis sur des comptes connectés (voir mode connecté) ne te sont jamais facturés — c'est l'utilisateur qui paie son propre abonnement Billies. Le détail de ta consommation est disponible à tout moment via GET /usage.
Gros volumes ou partenariat ? Une offre sur mesure est possible — écris-nous à contact@billies.fr.
Démarrage rapide
Du compte vide au devis signable : cinq étapes, cinq appels.
- 1.
Active l'API dans tes réglages
Depuis ton compte Billies, active l'offre API (99 €/mois). Ton compte devient un compte partenaire.
- 2.
Crée ta clé
Toujours dans les réglages : génère une clé bil_live_…. Elle n'est affichée qu'une fois — stocke-la dans ton gestionnaire de secrets.
- 3.
Crée un sous-compte
Un sous-compte par entreprise cliente de ton logiciel. C'est lui qui porte l'identité légale des documents.
- 4.
Crée un devis
Un client final + des lignes en centimes. Le document naît en brouillon, les totaux sont calculés pour toi.
- 5.
Émets
L'émission attribue le numéro légal et génère le PDF. Tu récupères l'URL du PDF et, si tu veux, un lien de signature en ligne.
# Ta clé API — créée dans Réglages → API (affichée une seule fois)
export BILLIES_API_KEY="bil_live_…"
BASE="https://billies.fr/api/partner/v1"
# 1. Crée un sous-compte pour ton client final
curl -s -X POST "$BASE/companies" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Idempotency-Key: onboarding-martin-001" \
-H "Content-Type: application/json" \
-d '{ "name": "Plomberie Martin", "siret": "73282932000074", "postalCode": "69003", "city": "Lyon" }'
# → 201 { "company": { "id": "COMPANY_ID", … } }
# 2. Ajoute le client à facturer
curl -s -X POST "$BASE/companies/COMPANY_ID/clients" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "type": "business", "displayName": "SCI Les Tilleuls", "email": "compta@lestilleuls.example" }'
# → 201 { "client": { "id": "CLIENT_ID", … } }
# 3. Crée un devis (brouillon)
curl -s -X POST "$BASE/companies/COMPANY_ID/documents" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Idempotency-Key: devis-sdb-tilleuls-01" \
-H "Content-Type: application/json" \
-d '{
"type": "quote",
"clientId": "CLIENT_ID",
"title": "Rénovation salle de bain",
"lines": [
{ "description": "Pose faïence murale", "quantity": 12, "unitPriceCents": 4500, "vatRate": 10, "unit": "m²" }
]
}'
# → 201 { "document": { "id": "DOCUMENT_ID", "status": "draft", "totalTtcCents": 59400, … } }
# 4. Émets : numéro légal + PDF, le document devient immuable
curl -s -X POST "$BASE/companies/COMPANY_ID/documents/DOCUMENT_ID/issue" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Idempotency-Key: emission-devis-sdb-01"
# → 200 { "number": "D-20260709-0001", "status": "sent", "pdfUrl": "https://…" }
# 5. Lien de signature en ligne, à afficher dans TON interface
curl -s -X POST "$BASE/companies/COMPANY_ID/documents/DOCUMENT_ID/signature-link" \
-H "Authorization: Bearer $BILLIES_API_KEY"
# → 200 { "url": "https://billies.fr/q/…" }Les fondamentaux
Authentification
Chaque requête porte ta clé API en en-tête Authorization: Bearer bil_live_…. Tu crées tes clés dans tes réglages Billies ; la clé complète n'est affichée qu'une seule fois (on n'en stocke qu'une empreinte). Plusieurs clés peuvent être actives en parallèle, pour une rotation sans coupure : crée la nouvelle, bascule ton code, révoque l'ancienne.
curl "https://billies.fr/api/partner/v1/companies" \
-H "Authorization: Bearer bil_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"Format des erreurs
Toute erreur renvoie le même objet JSON, avec un code stable sur lequel brancher ton code — le message est là pour les humains, il peut changer.
{
"error": {
"code": "conflict",
"message": "Ce document est déjà émis : il ne peut plus être modifié."
}
}| Code | HTTP | Quand |
|---|---|---|
| unauthorized | 401 | Clé absente, révoquée ou inconnue. |
| forbidden | 403 | La clé n'a pas le scope requis. |
| not_found | 404 | Ressource inexistante — ou rattachée à un autre partenaire. |
| invalid_request | 400 | Corps invalide, champ manquant, Idempotency-Key absent. |
| conflict | 409 | L'état du document interdit l'action (ex. modifier un document émis) — ou une requête identique (même Idempotency-Key) est encore en cours de traitement. |
| rate_limited | 429 | Trop de requêtes sur la fenêtre en cours — réessaie après une pause. |
| internal | 500 | Erreur côté Billies. Rejoue avec la même Idempotency-Key, sans risque. |
Idempotence : jamais deux factures pour un retry
Un timeout réseau ne te dit pas si l'appel a abouti. Sans protection, le retry naturel de ton code créerait un deuxième document — et deux numéros légaux. C'est pourquoi l'en-tête Idempotency-Key est obligatoire (sinon 400) sur les trois POST qui créent quelque chose d'irréversible ou de numéroté : POST /companies, POST …/documents et POST …/documents/{id}/issue. Sur POST …/payments et POST …/credit-note, l'en-tête est facultatif — mais recommandé.
Choisis une clé qui identifie l'opération côté chez toi (ex. facture-cmd-8842) : rejouer la même requête avec la même clé renvoie la réponse d'origine, sans rien ré-exécuter. Deux requêtes simultanées avec la même clé ne s'exécutent jamais deux fois : la seconde reçoit un 409 conflict tant que la première est en vol — réessaie quelques secondes plus tard pour obtenir la réponse stockée. Seules les réponses définitives sont stockées : après un 500, la clé reste rejouable.
Montants en centimes
Tous les montants sont des entiers en centimes d'euro : "unitPriceCents": 4500= 45,00 €. Jamais de flottants, donc jamais d'erreur d'arrondi. Les taux de TVA sont des pourcentages (20, 10, 5.5, 2.1, 0) et les totaux sont toujours calculés côté Billies.
Mode connecté : ton utilisateur garde son compte Billies
La marque grise (sous-comptes) convient quand tes utilisateurs n'ont pas de compte Billies : tu portes tout. Le mode connecté couvre l'autre cas : ton utilisateur a — ou prend — son propre compte Billies, et il autorise ton logiciel à créer et émettre des documents dessus. Le cas type : un back-office de vente qui délègue devis, factures et e-facturation à Billies.
Le flux, en cinq temps
- 1.
« Connecter Billies », chez toi
Tu génères un state opaque (un nonce, stocké côté serveur), puis tu rediriges l'utilisateur vers https://billies.fr/connect/<ton-slug> avec redirect_uri et state en paramètres.
- 2.
Il se connecte — ou s'inscrit
Écran Billies co-brandé à tes couleurs (ton nom, ton logo). S'il n'a pas encore de compte Billies, il en crée un au passage : c'est le sien, pas un sous-compte à toi.
- 3.
Il autorise
L'écran de consentement liste précisément ce que ton logiciel pourra faire sur son compte — et ce qu'il ne pourra pas. S'il refuse, il revient chez toi avec ?error=access_denied.
- 4.
Retour chez toi
Billies le renvoie sur ton redirect_uri avec ?state=…&billies_company_id=…. Ces paramètres ne sont que de l'UX : ne t'y fie pas pour ouvrir un accès.
- 5.
Ton serveur vérifie
GET /api/partner/v1/links?state=… est la source de vérité : il renvoie le companyId et les scopes consentis. Stocke le companyId — tous tes appels /companies/{companyId}/… passent ensuite par lui.
# 1. Chez toi : bouton « Connecter Billies » → redirection de l'utilisateur
https://billies.fr/connect/ton-slug?redirect_uri=https://ton-app.example/billies/callback&state=n-4f7a2b9c
# 2-3. Chez Billies : il se connecte (ou crée son compte), puis autorise
# — écrans co-brandés à tes couleurs.
# 4. Retour chez toi :
# autorisé → https://ton-app.example/billies/callback?state=n-4f7a2b9c&billies_company_id=1f6f9c2e-…
# refusé → https://ton-app.example/billies/callback?state=n-4f7a2b9c&error=access_denied
# 5. Côté SERVEUR, vérifie avec ton state — c'est la source de vérité :
curl "https://billies.fr/api/partner/v1/links?state=n-4f7a2b9c" \
-H "Authorization: Bearer $BILLIES_API_KEY"
# → 200 { "link": { "companyId": "1f6f9c2e-…", "scopes": […], "revokedAt": null } }Le redirect_uridoit figurer dans la liste d'URLs de retour déclarée pour ton compte partenaire (protection contre la redirection ouverte) — sinon le flux répond 400avant même l'écran de connexion. Pour déclarer tes URLs : écris à contact@billies.fr.
Ce que ça change
- Il paie son abonnement Billies, rien pour toi.Les documents émis sur un compte connecté ne comptent ni dans tes sous-comptes actifs, ni dans tes documents à l'acte — ils ne te sont jamais facturés.
- Il gère lui-même sa connexion e-facturationdans ses réglages Billies (plateforme de dématérialisation, Factur-X). Tu n'as rien à configurer : le même
POST …/issuesuit sa configuration. - Ton accès est limité à ce qu'il a consenti : documents, clients, paiements — jamais ses réglages (
PATCH /companies/{id}répond403) ni son IBAN. Et il peut révoquer l'accès à tout moment, depuis ses réglages. - Les documents vivent aussi chez lui.Un devis créé via ton logiciel apparaît dans son app Billies, web et mobile — il le retrouve, le suit, l'archive comme les autres.
- L'habillage suit son plan Billies: sur un compte gratuit, les documents gardent la mention « Fait avec billies.fr », comme ceux qu'il crée lui-même.
Une fois le companyIdrécupéré, tout le reste de l'API fonctionne à l'identique. Les deux endpoints du mode connecté sont détaillés dans la référence.
Référence des endpoints
Base : https://billies.fr/api/partner/v1. Tous les endpoints, famille par famille : sous-comptes, clients finaux, documents, émission, mode connecté, e-reporting, factures reçues, consommation.
Sous-comptes
Un sous-compte représente une entreprise cliente de ton logiciel : son identité légale, ses coordonnées bancaires, son habillage PDF. Chaque devis et chaque facture appartient à un sous-compte.
Créer un sous-compte
POST /api/partner/v1/companies
Scope companies:write · en-tête Idempotency-Key obligatoire
Crée l'entreprise cliente finale. Seul name est requis : tu peux compléter le SIRET, l'adresse, le régime de TVA ou les infos RCS plus tard via PATCH, avant la première émission. vatRegime vaut franchise_base (défaut), reel_simplifie ou reel_normal ; legalForm vaut auto_entrepreneur, ei, eurl, sarl, sas ou sasu. logoUrl (URL https publique) s'affiche en tête des PDF de facture. vatNumber est optionnel : à défaut, il est dérivé automatiquement du SIREN dès que le sous-compte est assujetti (régime ≠ franchise en base). Pour une société, tu peux poser rcsNumber, rcsCity et shareCapitalCents (capital en centimes) dès la création.
{
"name": "Plomberie Martin",
"logoUrl": "https://cdn.monlogiciel.fr/logos/plomberie-martin.png",
"siret": "73282932000074",
"legalForm": "ei",
"addressLine1": "12 rue des Ateliers",
"postalCode": "69003",
"city": "Lyon",
"country": "FR",
"vatRegime": "reel_normal"
}{
"company": {
"id": "1f6f9c2e-8d1a-4b6e-9f3d-2a7c5e8b1d40",
"name": "Plomberie Martin",
"logoUrl": "https://cdn.monlogiciel.fr/logos/plomberie-martin.png",
"legalForm": "ei",
"siret": "73282932000074",
"vatNumber": "FR44732829320",
"vatRegime": "reel_normal",
"addressLine1": "12 rue des Ateliers",
"addressLine2": null,
"postalCode": "69003",
"city": "Lyon",
"country": "FR",
"ibanLast4": null,
"einvoiceEnabled": false,
"createdAt": "2026-07-01T09:12:00.000Z"
}
}curl -X POST "https://billies.fr/api/partner/v1/companies" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Idempotency-Key: onboarding-martin-001" \
-H "Content-Type: application/json" \
-d '{ "name": "Plomberie Martin", "siret": "73282932000074", "vatRegime": "reel_normal", "postalCode": "69003", "city": "Lyon" }'- Un sous-compte ne coûte rien tant qu'il n'émet pas de document dans le mois.
- logoUrl doit être une URL http(s):// publique (500 caractères max), rendue telle quelle en tête des PDF émis — héberge le fichier chez toi et passe le lien. Les URL data: ou javascript: sont refusées.
- vatNumber est facultatif : fourni, il est normalisé (FR + clé + SIREN) ; omis, il est dérivé automatiquement du SIREN dès que le sous-compte est assujetti (reel_simplifie / reel_normal). En franchise_base aucun numéro n'est posé (art. 293 B du CGI).
- Piège à connaître : sans vatRegime, le sous-compte naît en franchise_base (TVA non applicable, art. 293 B du CGI) — ses documents sortent sans TVA, quel que soit le vatRate des lignes. Pour une entreprise qui facture la TVA, envoie reel_normal ou reel_simplifie.
- Sociétés (sarl, sas, sasu, eurl) : renseigne rcsNumber, rcsCity et shareCapitalCents (capital social en centimes) avant la première émission — sinon l'émission renvoie une erreur de conformité (art. R.123-237 Code commerce).
- Idempotence : seule une réponse de succès (2xx) est mémorisée puis rejouée à l'identique. Une erreur (ex. 400 SIRET invalide) n'est PAS mémorisée — corrige la donnée et rejoue la MÊME Idempotency-Key, la création aboutit.
Lister tes sous-comptes
GET /api/partner/v1/companies
Scope companies:read
Liste paginée de tous les sous-comptes rattachés à ta clé. Paramètres : limit (défaut 50) et offset.
{
"companies": [
{
"id": "1f6f9c2e-8d1a-4b6e-9f3d-2a7c5e8b1d40",
"name": "Plomberie Martin",
"siret": "73282932000074",
"city": "Lyon",
"createdAt": "2026-07-01T09:12:00.000Z"
}
],
"total": 1
}curl "https://billies.fr/api/partner/v1/companies?limit=20&offset=0" \
-H "Authorization: Bearer $BILLIES_API_KEY"Détail d'un sous-compte
GET /api/partner/v1/companies/{companyId}
Scope companies:read
Renvoie la fiche complète du sous-compte. 404 si l'identifiant n'existe pas ou n'appartient pas à ta clé.
{
"company": {
"id": "1f6f9c2e-8d1a-4b6e-9f3d-2a7c5e8b1d40",
"name": "Plomberie Martin",
"logoUrl": "https://cdn.monlogiciel.fr/logos/plomberie-martin.png",
"legalForm": "ei",
"siret": "73282932000074",
"vatNumber": "FR44732829320",
"vatRegime": "reel_normal",
"addressLine1": "12 rue des Ateliers",
"postalCode": "69003",
"city": "Lyon",
"country": "FR",
"ibanLast4": "0189",
"einvoiceEnabled": false,
"createdAt": "2026-07-01T09:12:00.000Z"
}
}curl "https://billies.fr/api/partner/v1/companies/1f6f9c2e-8d1a-4b6e-9f3d-2a7c5e8b1d40" \
-H "Authorization: Bearer $BILLIES_API_KEY"Modifier un sous-compte
PATCH /api/partner/v1/companies/{companyId}
Scope companies:write
Mise à jour partielle : n'envoie que les champs à changer. Éditables : name, logoUrl, siret (une seule fois), vatNumber, vatRegime, legalForm, rcsCity, rcsNumber, shareCapitalCents, addressLine1, addressLine2, postalCode, city, country, iban, bic, bankName, pdfTemplateKey, pdfBrandColor, pdfFooterText, legalMentionsCustom, einvoiceEnabled, einvoiceProfile (en16931 | extended), ereportingEnabled, hasVatOnDebits, vatFrequency (monthly | quarterly | null).
{
"logoUrl": "https://cdn.monlogiciel.fr/logos/plomberie-martin.png",
"vatRegime": "reel_normal",
"iban": "FR7630006000011234567890189",
"bic": "AGRIFRPP",
"bankName": "Crédit Agricole",
"pdfBrandColor": "#1d3a6b",
"pdfFooterText": "Merci pour votre confiance."
}{
"company": {
"id": "1f6f9c2e-8d1a-4b6e-9f3d-2a7c5e8b1d40",
"name": "Plomberie Martin",
"vatRegime": "reel_normal",
"ibanLast4": "0189",
"bankName": "Crédit Agricole",
"pdfBrandColor": "#1d3a6b",
"pdfFooterText": "Merci pour votre confiance."
}
}curl -X PATCH "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "vatRegime": "reel_normal", "pdfBrandColor": "#1d3a6b" }'- L'IBAN est chiffré au repos : il n'est jamais renvoyé en clair par l'API (ibanLast4 seulement).
- Le SIRET se pose une seule fois : le changer ensuite renvoie 409 (verrou de numérotation légale).
- Changer vatRegime n'affecte que les documents émis après le changement — les documents émis sont immuables.
- Sociétés (sarl, sas, sasu, eurl) : renseigne rcsNumber, rcsCity et shareCapitalCents (capital social en centimes) avant la première émission — sinon l'émission renvoie une erreur de conformité (art. R.123-237 Code commerce).
- logoUrl, pdfTemplateKey, pdfBrandColor et pdfFooterText pilotent l'habillage des PDF émis — c'est là que se joue la marque grise. Le logo se met à jour autant de fois que voulu (contrairement au SIRET) ; sans logo, le PDF affiche le nom de la société en texte. Attention : pdfBrandColor n'est appliquée que par les templates bold et elegant. bw, classic et modern ont une palette figée et l'ignorent. pdfBrandColor à null = chaque template reprend sa couleur d'origine.
- vatNumber : le poser explicitement écrase la valeur courante ; le laisser vide déclenche, sur un sous-compte assujetti, une dérivation automatique depuis le SIREN — et cette dérivation ne s'applique qu'une fois (elle n'écrase jamais un numéro déjà présent).
- Facturation électronique : einvoiceEnabled active le Factur-X sur les factures B2B, ereportingEnabled la déclaration e-reporting B2C. hasVatOnDebits et vatFrequency décrivent le régime de TVA — un changement est répercuté à la plateforme de dématérialisation (best-effort). L'objet company renvoie aussi pdpConnected et pdpMode (delegated | platform | none).
Lire la numérotation
GET /api/partner/v1/companies/{companyId}/numbering
Scope companies:read
Renvoie les préfixes de numérotation (devis / facture / avoir) et l'état des compteurs de séquence (par type et par année).
{
"numbering": {
"quotePrefix": "D",
"invoicePrefix": "F",
"creditNotePrefix": "AV",
"sequences": [
{ "type": "invoice", "year": 2026, "lastNumber": 42 },
{ "type": "credit_note", "year": 2026, "lastNumber": 3 }
]
}
}curl "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/numbering" \
-H "Authorization: Bearer $BILLIES_API_KEY"Configurer la numérotation
PUT /api/partner/v1/companies/{companyId}/numbering
Scope companies:write
Utilise le verbe PUT. Configure les préfixes et, surtout, AMORCE les compteurs pour continuer une série existante quand tu migres un client depuis un autre logiciel. Préfixes : 1 à 10 caractères A-Z, chiffres et tiret. seedCounters pose le dernier numéro atteint pour une année donnée : la prochaine facture repart à la valeur + 1.
{
"invoicePrefix": "F",
"creditNotePrefix": "AV",
"seedCounters": { "invoice": 42, "creditNote": 3, "year": 2026 }
}{
"numbering": {
"quotePrefix": "D",
"invoicePrefix": "F",
"creditNotePrefix": "AV",
"sequences": [
{ "type": "invoice", "year": 2026, "lastNumber": 42 },
{ "type": "credit_note", "year": 2026, "lastNumber": 3 }
]
}
}curl -X PUT "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/numbering" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "invoicePrefix": "F", "creditNotePrefix": "AV", "seedCounters": { "invoice": 42, "year": 2026 } }'- Amorcer un compteur bascule le sous-compte en numérotation annuelle (F-2026-0043) pour que l'année serve bien de clé de série.
- Un compteur peut AVANCER (re-semer plus haut est toujours accepté), jamais RECULER : amorcer sous un numéro déjà émis renvoie 409, avec le dernier numéro émis dans le message.
- Chaque valeur de seedCounters est le DERNIER numéro atteint : pose 42 pour que la prochaine facture soit la 43.
Clients finaux
Le carnet d'adresses d'un sous-compte : les particuliers et entreprises que ton utilisateur facture. Un document référence toujours un client de ce carnet.
Créer un client
POST /api/partner/v1/companies/{companyId}/clients
Scope clients:write
Seul displayName est requis. type vaut individual (particulier) ou business (professionnel). Pour un professionnel, renseigne siret et legalName : ils apparaissent sur les factures et servent à la e-facturation.
{
"type": "business",
"displayName": "SCI Les Tilleuls",
"legalName": "SCI Les Tilleuls",
"siret": "90123456700013",
"email": "compta@lestilleuls.example",
"phone": "0612345678",
"addressLine1": "8 avenue des Platanes",
"postalCode": "69006",
"city": "Lyon"
}{
"client": {
"id": "b8e64c1d-5a3f-4e2b-9c7d-1f0a2b3c4d5e",
"type": "business",
"displayName": "SCI Les Tilleuls",
"legalName": "SCI Les Tilleuls",
"siret": "90123456700013",
"email": "compta@lestilleuls.example",
"addressLine1": "8 avenue des Platanes",
"postalCode": "69006",
"city": "Lyon",
"country": "FR"
}
}curl -X POST "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/clients" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "type": "business", "displayName": "SCI Les Tilleuls", "email": "compta@lestilleuls.example" }'Lister les clients
GET /api/partner/v1/companies/{companyId}/clients
Scope clients:read
Liste paginée du carnet du sous-compte. q filtre sur le nom (recherche plein texte simple), limit et offset paginent.
{
"clients": [
{
"id": "b8e64c1d-5a3f-4e2b-9c7d-1f0a2b3c4d5e",
"type": "business",
"displayName": "SCI Les Tilleuls",
"email": "compta@lestilleuls.example",
"city": "Lyon"
}
],
"total": 1
}curl "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/clients?q=tilleuls" \
-H "Authorization: Bearer $BILLIES_API_KEY"Détail d'un client
GET /api/partner/v1/companies/{companyId}/clients/{clientId}
Scope clients:read
Renvoie la fiche complète du client.
{
"client": {
"id": "b8e64c1d-5a3f-4e2b-9c7d-1f0a2b3c4d5e",
"type": "business",
"displayName": "SCI Les Tilleuls",
"legalName": "SCI Les Tilleuls",
"siret": "90123456700013",
"email": "compta@lestilleuls.example",
"phone": "0612345678",
"addressLine1": "8 avenue des Platanes",
"postalCode": "69006",
"city": "Lyon",
"country": "FR"
}
}curl "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/clients/b8e64c1d-…" \
-H "Authorization: Bearer $BILLIES_API_KEY"Modifier un client
PATCH /api/partner/v1/companies/{companyId}/clients/{clientId}
Scope clients:write
Mise à jour partielle, mêmes champs qu'à la création. Les documents déjà émis ne sont pas retouchés : ils gardent les coordonnées du client au moment de l'émission.
{
"email": "facturation@lestilleuls.example",
"addressLine1": "10 avenue des Platanes"
}{
"client": {
"id": "b8e64c1d-5a3f-4e2b-9c7d-1f0a2b3c4d5e",
"displayName": "SCI Les Tilleuls",
"email": "facturation@lestilleuls.example",
"addressLine1": "10 avenue des Platanes"
}
}curl -X PATCH "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/clients/b8e64c1d-…" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "facturation@lestilleuls.example" }'Documents — brouillons
Un document naît toujours en brouillon (status draft) : sans numéro, modifiable, supprimable. Les totaux (HT, TVA, TTC) sont recalculés côté Billies à partir des lignes — tu n'envoies jamais de total.
Créer un devis ou une facture (brouillon)
POST /api/partner/v1/companies/{companyId}/documents
Scope documents:write · en-tête Idempotency-Key obligatoire
type vaut quote (devis) ou invoice (facture). Chaque ligne porte sa quantité, son prix unitaire HT en centimes et son taux de TVA (en pourcentage : 20, 10, 5.5, 2.1 ou 0). Le title est optionnel : il n'existe pas de champ titre sur le document — il est converti en ligne d'en-tête (kind section) en position 0, et c'est là qu'il ressort dans la réponse (pas de champ title). La réponse contient le document complet avec les totaux calculés.
{
"type": "quote",
"clientId": "b8e64c1d-5a3f-4e2b-9c7d-1f0a2b3c4d5e",
"title": "Rénovation salle de bain",
"notes": "Acompte de 30 % à la signature.",
"attachCgv": true,
"lines": [
{
"description": "Pose faïence murale",
"quantity": 12,
"unitPriceCents": 4500,
"vatRate": 10,
"unit": "m²"
},
{
"description": "Remplacement mitigeur thermostatique",
"quantity": 1,
"unitPriceCents": 18900,
"vatRate": 10,
"unit": "forfait"
}
]
}{
"document": {
"id": "7c9e4b2a-6d5f-4a1b-8e3c-9f0d1a2b3c4d",
"type": "quote",
"status": "draft",
"number": null,
"clientId": "b8e64c1d-5a3f-4e2b-9c7d-1f0a2b3c4d5e",
"issuedAt": "2026-07-09",
"dueAt": null,
"expiresAt": "2026-08-08",
"totalHtCents": 72900,
"totalVatCents": 7290,
"totalTtcCents": 80190,
"globalDiscountPct": null,
"creditNoteOfId": null,
"createdAt": "2026-07-09T10:04:00.000Z",
"updatedAt": "2026-07-09T10:04:00.000Z",
"notes": "Acompte de 30 % à la signature.",
"paymentTermsText": "Paiement sous 30 jours",
"pdpStatus": null,
"attachCgv": true,
"lines": [
{ "id": "1a2b3c4d-…", "position": 0, "kind": "section", "description": "Rénovation salle de bain", "quantity": 0, "unit": "u", "unitPriceCents": 0, "vatRate": 0, "discountPct": 0, "totalHtCents": 0, "totalVatCents": 0, "totalTtcCents": 0 },
{ "id": "2b3c4d5e-…", "position": 1, "kind": "item", "description": "Pose faïence murale", "quantity": 12, "unit": "m²", "unitPriceCents": 4500, "vatRate": 10, "discountPct": 0, "totalHtCents": 54000, "totalVatCents": 5400, "totalTtcCents": 59400 },
{ "id": "3c4d5e6f-…", "position": 2, "kind": "item", "description": "Remplacement mitigeur thermostatique", "quantity": 1, "unit": "forfait", "unitPriceCents": 18900, "vatRate": 10, "discountPct": 0, "totalHtCents": 18900, "totalVatCents": 1890, "totalTtcCents": 20790 }
],
"pdfUrl": null
}
}curl -X POST "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/documents" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Idempotency-Key: devis-sdb-tilleuls-01" \
-H "Content-Type: application/json" \
-d '{
"type": "quote",
"clientId": "b8e64c1d-5a3f-4e2b-9c7d-1f0a2b3c4d5e",
"lines": [
{ "description": "Pose faïence murale", "quantity": 12, "unitPriceCents": 4500, "vatRate": 10, "unit": "m²" }
]
}'- Remise globale : globalDiscountPct, un pourcentage entre 0 et 100. C'est le seul format accepté — pas de remise en montant. Chaque ligne accepte aussi son propre discountPct (0-100).
- title n'est PAS stocké comme champ du document : il devient une ligne kind section en position 0. La réponse ne contient donc pas de champ title — il ressort dans lines.
- Chaque ligne accepte un kind optionnel : item (défaut, chiffrée), section (en-tête) ou comment (note) — les lignes section et comment n'ont aucun montant. Au moins une ligne item est requise.
- Mode TTC « en dedans » (facturation B2C) : une ligne item peut porter totalTtcCents (montant TTC exact en centimes, entier ≠ 0) + vatRate au lieu de quantity/unitPriceCents — la TVA est alors extraite du TTC, si bien que le TTC facturé est au centime égal à ce que tu encaisses. Un totalTtcCents négatif est accepté pour déduire un acompte déjà facturé, tant que le total du document reste positif et comporte au moins une ligne positive. La ligne renvoie enteredTtcCents (null pour une ligne HT classique).
- Conditions générales de vente : attachCgv est un booléen optionnel qui décide si les CGV de l'entreprise sont annexées en pages supplémentaires du PDF. Omis (ou null), le défaut dépend du type — un devis part AVEC les CGV, une facture et un avoir SANS. Envoie true pour joindre les CGV à une facture, false pour les retirer d'un devis. Le champ ressort tel quel (attachCgv, null quand tu n'as rien tranché) dans la réponse de GET /documents/{documentId}. Les mentions légales obligatoires (pénalités de retard, indemnité de 40 €, TVA) ne dépendent PAS de ce flag : elles sont générées à part et figurent toujours sur le document.
- Un PDF de CGV importé par l'entreprise (au lieu d'un texte) n'est annexé qu'aux documents adressés à un client professionnel (client.type = business).
- Le brouillon ne consomme pas de numéro et ne compte pas dans ta facturation : seul un document émis rend le sous-compte actif.
Lister les documents
GET /api/partner/v1/companies/{companyId}/documents
Scope documents:read
Liste paginée des documents du sous-compte. Filtres : type (quote, invoice ou credit_note), status (draft, sent, accepted, rejected, expired, partially_paid, paid, late ou cancelled), limit (1-100, défaut 50), offset.
{
"documents": [
{
"id": "7c9e4b2a-6d5f-4a1b-8e3c-9f0d1a2b3c4d",
"type": "quote",
"status": "sent",
"number": "D-20260709-0001",
"clientId": "b8e64c1d-5a3f-4e2b-9c7d-1f0a2b3c4d5e",
"issuedAt": "2026-07-09",
"dueAt": null,
"expiresAt": "2026-08-08",
"totalHtCents": 72900,
"totalVatCents": 7290,
"totalTtcCents": 80190,
"globalDiscountPct": null,
"creditNoteOfId": null,
"createdAt": "2026-07-09T10:04:00.000Z",
"updatedAt": "2026-07-09T10:12:00.000Z"
}
],
"total": 1
}curl "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/documents?type=quote&status=sent" \
-H "Authorization: Bearer $BILLIES_API_KEY"- Il n'existe pas de statut signed : un devis signé passe en accepted.
- Le format du numéro suit les réglages de numérotation du sous-compte (par défaut : préfixe D pour les devis, F pour les factures, A pour les avoirs, date du jour puis compteur — ex. D-20260709-0001). number vaut null tant que le document est en brouillon.
Détail d'un document
GET /api/partner/v1/companies/{companyId}/documents/{documentId}
Scope documents:read
Document complet : lignes, totaux, statut, numéro. Si le document est émis, pdfUrl contient une URL signée temporaire vers le PDF (sinon null).
{
"document": {
"id": "7c9e4b2a-6d5f-4a1b-8e3c-9f0d1a2b3c4d",
"type": "quote",
"status": "sent",
"number": "D-20260709-0001",
"clientId": "b8e64c1d-5a3f-4e2b-9c7d-1f0a2b3c4d5e",
"issuedAt": "2026-07-09",
"dueAt": null,
"expiresAt": "2026-08-08",
"totalHtCents": 72900,
"totalVatCents": 7290,
"totalTtcCents": 80190,
"globalDiscountPct": null,
"creditNoteOfId": null,
"createdAt": "2026-07-09T10:04:00.000Z",
"updatedAt": "2026-07-09T10:12:00.000Z",
"notes": "Acompte de 30 % à la signature.",
"paymentTermsText": "Paiement sous 30 jours",
"pdpStatus": null,
"attachCgv": true,
"lines": [
{ "id": "1a2b3c4d-…", "position": 0, "kind": "section", "description": "Rénovation salle de bain", "quantity": 0, "unit": "u", "unitPriceCents": 0, "vatRate": 0, "discountPct": 0, "totalHtCents": 0, "totalVatCents": 0, "totalTtcCents": 0 },
{ "id": "2b3c4d5e-…", "position": 1, "kind": "item", "description": "Pose faïence murale", "quantity": 12, "unit": "m²", "unitPriceCents": 4500, "vatRate": 10, "discountPct": 0, "totalHtCents": 54000, "totalVatCents": 5400, "totalTtcCents": 59400 },
{ "id": "3c4d5e6f-…", "position": 2, "kind": "item", "description": "Remplacement mitigeur thermostatique", "quantity": 1, "unit": "forfait", "unitPriceCents": 18900, "vatRate": 10, "discountPct": 0, "totalHtCents": 18900, "totalVatCents": 1890, "totalTtcCents": 20790 }
],
"pdfUrl": "https://…/D-20260709-0001.pdf?token=…"
}
}curl "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/documents/7c9e4b2a-…" \
-H "Authorization: Bearer $BILLIES_API_KEY"Supprimer un brouillon
DELETE /api/partner/v1/companies/{companyId}/documents/{documentId}
Scope documents:write
Supprime un document en brouillon. Un document émis n'est jamais supprimable (409 conflict) : c'est une exigence légale française — passe par un avoir.
HTTP/1.1 204 No Contentcurl -X DELETE "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/documents/7c9e4b2a-…" \
-H "Authorization: Bearer $BILLIES_API_KEY"Documents — émission et suites
L'émission est le point de bascule : le document reçoit son numéro légal séquentiel, son PDF est généré, et il devient immuable. Tout ce qui suit — signature, paiement, avoir — s'applique à un document émis.
Émettre un document
POST /api/partner/v1/companies/{companyId}/documents/{documentId}/issue
Scope documents:issue · en-tête Idempotency-Key obligatoire
Attribue le numéro légal, génère le PDF et passe le document en sent. Aucun email n'est envoyé : c'est ton logiciel qui présente le document à l'utilisateur final. C'est cet appel qui rend le sous-compte actif pour le mois en cours.
{
"id": "7c9e4b2a-6d5f-4a1b-8e3c-9f0d1a2b3c4d",
"number": "DEV-2026-0042",
"status": "sent",
"pdfUrl": "https://billies.fr/…/DEV-2026-0042.pdf?token=…"
}curl -X POST "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/documents/7c9e4b2a-…/issue" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Idempotency-Key: emission-devis-sdb-01"- Rejouer l'appel avec la même Idempotency-Key renvoie la même réponse : jamais deux numéros pour un retry réseau. Seuls les succès (2xx) sont mémorisés — après une erreur, corrige et rejoue la même clé.
- Si la e-facturation est activée sur le sous-compte, la facture part aussi via la plateforme de dématérialisation raccordée.
Récupérer le PDF
GET /api/partner/v1/companies/{companyId}/documents/{documentId}/pdf
Scope documents:read
Renvoie une URL signée valable environ 1 heure vers le PDF du document émis. 409 si le document est encore en brouillon. Regénère une URL à chaque besoin plutôt que de la stocker.
{
"url": "https://billies.fr/…/DEV-2026-0042.pdf?token=…"
}curl "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/documents/7c9e4b2a-…/pdf" \
-H "Authorization: Bearer $BILLIES_API_KEY"Créer un lien de signature
POST /api/partner/v1/companies/{companyId}/documents/{documentId}/signature-link
Scope documents:write
Pour un devis émis, génère une page publique de signature en ligne (lecture du devis, acceptation, signature tracée avec horodatage). Tu présentes ce lien dans ton interface ou tu l'envoies toi-même au client final. 409 si le document n'est pas un devis émis.
{
"url": "https://billies.fr/q/9f8e7d6c5b4a3f2e1d0c"
}curl -X POST "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/documents/7c9e4b2a-…/signature-link" \
-H "Authorization: Bearer $BILLIES_API_KEY"- Client avec co-titulaires (coHolders) : la réponse contient en plus un tableau signatories [{ name, url }] — un lien nominatif PAR signataire, et le devis ne passe en accepted qu'à la dernière signature. Distribue chaque lien à la bonne personne ; url reste celui du titulaire principal. Champ absent pour un client mono-titulaire.
Enregistrer un paiement
POST /api/partner/v1/companies/{companyId}/documents/{documentId}/payments
Scope payments:write
Enregistre un règlement reçu sur une facture émise. Quand le cumul des paiements atteint le TTC, la facture passe en paid. Les paiements partiels sont acceptés. method accepte transfer, check, card ou other — cash est refusé (Billies est un logiciel de facturation, il n'enregistre pas d'encaissements en espèces).
{
"amountCents": 80190,
"method": "transfer",
"paidAt": "2026-07-15",
"reference": "VIR-2026-4821"
}{
"document": {
"id": "3a2b1c0d-9e8f-4a5b-8c7d-6e5f4a3b2c1d",
"type": "invoice",
"status": "paid",
"number": "FAC-2026-0117",
"totalTtcCents": 80190
}
}curl -X POST "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/documents/3a2b1c0d-…/payments" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "amountCents": 80190, "method": "transfer", "paidAt": "2026-07-15" }'Créer un avoir
POST /api/partner/v1/companies/{companyId}/documents/{documentId}/credit-note
Scope documents:write
Le seul verbe correctif sur une facture émise : l'avoir annule comptablement la facture d'origine, avec son propre numéro légal et des montants négatifs (il crédite ce que la facture avait débité). Sans corps, il crédite la totalité. Avec un corps { amountCents } (> 0), il crée un avoir PARTIEL : le montant TTC est ventilé au prorata des taux de TVA de la facture, plafonné à ce qu'il reste à créditer. L'avoir est créé et émis en un seul appel.
{
"amountCents": 40000
}{
"creditNote": {
"id": "e4d3c2b1-a0f9-4e8d-9c7b-6a5f4e3d2c1b",
"type": "credit_note",
"status": "sent",
"number": "AV-2026-0007",
"creditNoteOfId": "3a2b1c0d-9e8f-4a5b-8c7d-6e5f4a3b2c1d",
"totalTtcCents": -40000,
"pdfUrl": "https://billies.fr/…/AV-2026-0007.pdf?token=…"
}
}curl -X POST "https://billies.fr/api/partner/v1/companies/1f6f9c2e-…/documents/3a2b1c0d-…/credit-note" \
-H "Authorization: Bearer $BILLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "amountCents": 40000 }'- amountCents absent → avoir total (montants exactement opposés à la facture). amountCents présent → avoir partiel : une ligne par taux de TVA, TVA « en dedans ».
- Plafond : la somme des avoirs d'une facture ne peut pas dépasser son TTC. Un amountCents qui dépasse le restant créditable renvoie 409.
- Idempotency-Key optionnelle mais recommandée : elle évite un double avoir sur un retry réseau.
Mode connecté
Les connexions accordées par des utilisateurs Billies à ton logiciel via le flux /connect (voir la section Mode connecté plus haut). Chaque lien donne accès à une seule company — celle de l'utilisateur — avec les scopes qu'il a consentis. Une fois le companyId récupéré, tous les endpoints /companies/{companyId}/… fonctionnent à l'identique.
Lister tes connexions
GET /api/partner/v1/links
Scope companies:read
Liste paginée des comptes Billies connectés à ton logiciel, les plus récents d'abord. Paramètres : limit (défaut 50) et offset. Chaque lien expose la company accessible (companyId), les scopes consentis par l'utilisateur, et revokedAt — non null si l'utilisateur a coupé l'accès depuis ses réglages Billies.
{
"links": [
{
"id": "7c2d51e4-3b8f-4a19-b6c0-9e4d2f7a8c31",
"companyId": "1f6f9c2e-8d1a-4b6e-9f3d-2a7c5e8b1d40",
"scopes": [
"companies:read",
"clients:read",
"clients:write",
"documents:read",
"documents:write",
"documents:issue",
"received-invoices:read",
"payments:write"
],
"state": "n-4f7a2b9c",
"authorizedAt": "2026-07-09T14:03:00.000Z",
"revokedAt": null
}
],
"total": 1
}curl "https://billies.fr/api/partner/v1/links?limit=20&offset=0" \
-H "Authorization: Bearer $BILLIES_API_KEY"- Un lien révoqué (revokedAt non null) ferme l'accès : les endpoints /companies/{companyId}/… répondent alors 404, comme si le compte n'existait pas.
- Si l'utilisateur refait le flux /connect, le même lien est réactivé (revokedAt repasse à null, authorizedAt est rafraîchi) — pas de doublon.
Vérifier une connexion après le retour
GET /api/partner/v1/links?state={state}
Scope companies:read
L'étape serveur du flux /connect : quand l'utilisateur revient chez toi, appelle cet endpoint avec le state que tu avais généré avant la redirection. C'est la source de vérité — le billies_company_id présent dans l'URL de retour n'est que de l'UX et ne doit jamais être cru tel quel. Stocke le companyId renvoyé : c'est lui que tu utilises ensuite sur tous les endpoints /companies/{companyId}/….
{
"link": {
"id": "7c2d51e4-3b8f-4a19-b6c0-9e4d2f7a8c31",
"companyId": "1f6f9c2e-8d1a-4b6e-9f3d-2a7c5e8b1d40",
"scopes": [
"companies:read",
"clients:read",
"clients:write",
"documents:read",
"documents:write",
"documents:issue",
"received-invoices:read",
"payments:write"
],
"state": "n-4f7a2b9c",
"authorizedAt": "2026-07-09T14:03:00.000Z",
"revokedAt": null
}
}curl "https://billies.fr/api/partner/v1/links?state=n-4f7a2b9c" \
-H "Authorization: Bearer $BILLIES_API_KEY"- 404 si aucun lien ne porte ce state : l'utilisateur n'a pas terminé le flux, le state ne vient pas de chez toi, OU l'autorisation date de plus de 24 h (le state expire — anti-rejeu). Vérifie le state juste après le retour ; passé ce délai, retrouve le compte via GET /links (liste).
- Le lien est renvoyé même si l'utilisateur a révoqué entre-temps (revokedAt non null) — à toi de le traiter comme inactif.
- Génère un state opaque et unique par tentative de connexion (nonce), stocké côté serveur avant la redirection : c'est lui qui relie le retour à la bonne session chez toi.
E-reporting (ventes aux particuliers)
Journal des données de transaction et de paiement B2C transmises à l'administration (réforme e-facturation, obligatoire TPE/PME au 1ᵉʳ septembre 2027). La mise en file est automatique dès l'émission ou l'encaissement d'une facture à un particulier — aucun appel à faire de ton côté. Inclus, sans surcoût par déclaration.
Journal e-reporting d'un sous-compte
GET /api/partner/v1/companies/{companyId}/ereporting
Scope documents:read
Lecture seule : l'état d'activation et les déclarations du sous-compte, avec leur statut de transmission (pending → sending → sent, ou error). Une entrée transaction est créée à l'émission d'une facture ou d'un avoir à un particulier français (montants HT/TVA agrégés par taux — jamais le nom du client) ; une entrée payment à chaque encaissement (TTC ventilé). La transmission part toutes les heures, sous l'identité fiscale du sous-compte (jeton délégué). Filtres : status (pending, sending, sent, error) et kind (transaction, payment) ; pagination limit (≤ 100) et offset.
{
"mode": "live",
"ereportingEnabled": true,
"pdpConnected": true,
"pdpMode": "platform",
"entries": [
{
"id": "a1b2c3d4-…",
"documentId": "d4c3b2a1-…",
"documentNumber": "F-20260710-0012",
"kind": "transaction",
"status": "sent",
"providerId": "1593",
"errorMessage": null,
"date": "2026-07-10",
"categoryCode": "TPS1",
"amounts": { "htCents": 90000, "vatCents": 18000, "ttcCents": 108000 },
"createdAt": "2026-07-10T14:02:11.000Z",
"sentAt": "2026-07-10T14:30:04.000Z"
},
{
"id": "e5f6a7b8-…",
"documentId": "d4c3b2a1-…",
"documentNumber": "F-20260710-0012",
"kind": "payment",
"status": "sent",
"providerId": "668",
"errorMessage": null,
"date": "2026-07-10",
"categoryCode": null,
"amounts": { "htCents": null, "vatCents": null, "ttcCents": 50000 },
"createdAt": "2026-07-10T15:11:40.000Z",
"sentAt": "2026-07-10T15:30:02.000Z"
}
],
"limit": 50,
"offset": 0
}curl "https://billies.fr/api/partner/v1/companies/1f6f9c2e-8a4b-4c5d-9e0f-2a3b4c5d6e7f/ereporting?status=sent&kind=transaction" \
-H "Authorization: Bearer $BILLIES_API_KEY"- Rien à déclencher : l'émission d'une facture B2C (POST /documents + issue) et l'enregistrement d'un paiement (POST /payments) alimentent la file automatiquement. Cet endpoint sert à VÉRIFIER, pas à déclarer.
- Périmètre : factures et avoirs aux particuliers français uniquement. Les factures B2B (client avec SIRET) passent par le flux Factur-X, jamais par l'e-reporting — aucun double comptage possible.
- ereportingEnabled=false ou pdpConnected=false → aucune donnée ne part. pdpMode indique le raccordement effectif : delegated (l'artisan a connecté son propre accès PDP), platform (sous-compte marque grise déclaré via l'identité de la plateforme) ou none (non raccordé).
- categoryCode (transactions) : TPS1 prestations de services, TNT1 non taxable (TVA 0), norme AFNOR XP Z12-013. Les montants sont en centimes, négatifs pour un avoir ou une annulation d'encaissement.
- status=error : la déclaration a été refusée (définitif) — le détail est dans errorMessage. status=sending : transmission en cours de vérification, ne pas rejouer.
Factures reçues (réception e-facturation)
Les factures électroniques que le sous-compte REÇOIT de ses fournisseurs via le réseau de dématérialisation (réception obligatoire pour toutes les entreprises au 1ᵉʳ septembre 2026). Billies relève l'inbox de chaque sous-compte raccordé — rien à déclencher de ton côté. Ces deux endpoints te permettent de les afficher et de les servir directement dans ton back-office.
Factures reçues d'un sous-compte
GET /api/partner/v1/companies/{companyId}/received-invoices
Scope received-invoices:read
Liste des factures reçues, plus récentes d'abord. read indique si l'utilisateur l'a déjà ouverte sur billies.fr — cet appel ne modifie JAMAIS cet état (lecture non destructive, le badge de l'utilisateur reste intact). Filtre : unread=true|false (autre valeur → 400) ; pagination limit (≤ 100) et offset.
{
"einvoiceEnabled": true,
"pdpConnected": true,
"invoices": [
{
"id": "9c1e4f7a-5b2d-4e8f-a1c3-7d6e9f0b2a41",
"status": "delivered",
"senderName": "SARL Fournitures Pro",
"senderSiret": "88991234500017",
"receivedAt": "2026-07-09T08:14:52.000Z",
"read": false,
"createdAt": "2026-07-09T09:00:03.000Z"
}
],
"limit": 50,
"offset": 0
}curl "https://billies.fr/api/partner/v1/companies/1f6f9c2e-8a4b-4c5d-9e0f-2a3b4c5d6e7f/received-invoices?unread=true" \
-H "Authorization: Bearer $BILLIES_API_KEY"- Scope dédié received-invoices:read : les connexions (mode connecté) autorisées AVANT son introduction ne l'ont pas — l'appel répond 403 « non consenti » tant que l'utilisateur n'a pas ré-autorisé ton application via /connect (l'écran de consentement mentionne désormais les factures reçues). Même chose pour une clé API créée avant : recrée une clé.
- Prérequis côté sous-compte : facturation électronique activée (einvoiceEnabled) et compte raccordé à la plateforme (pdpConnected) — les deux champs sont renvoyés pour que tu puisses guider l'utilisateur. Sans raccordement, rien n'est relevé ; les factures déjà reçues avant une déconnexion restent listées.
- L'inbox est relevée périodiquement par Billies : une facture apparaît ici quelques minutes à quelques heures après son dépôt sur le réseau, pas en temps réel.
- senderName / senderSiret peuvent être null si la plateforme ne les expose pas pour ce dépôt.
Télécharger une facture reçue
GET /api/partner/v1/companies/{companyId}/received-invoices/{receivedInvoiceId}/download
Scope received-invoices:read
Renvoie le document lui-même en binaire (Content-Type: application/pdf pour un Factur-X, application/xml ou text/xml pour un CII pur — selon ce que le fournisseur a déposé), avec un Content-Disposition: attachment. Contrairement à …/documents/{id}/pdf qui renvoie une URL signée, la réponse est ici le flux binaire : le document vit chez la plateforme de dématérialisation, pas dans le Storage Billies.
— binaire —
Content-Type: application/pdf
Content-Disposition: attachment; filename="facture-recue-9c1e4f7a-….pdf"curl -OJ "https://billies.fr/api/partner/v1/companies/1f6f9c2e-8a4b-4c5d-9e0f-2a3b4c5d6e7f/received-invoices/9c1e4f7a-5b2d-4e8f-a1c3-7d6e9f0b2a41/download" \
-H "Authorization: Bearer $BILLIES_API_KEY"- Le téléchargement est fait côté serveur Billies avec l'accès de la société — son jeton plateforme ne transite jamais par toi. Ne mets pas cette URL en cache : sers le flux à ton utilisateur ou re-télécharge à la demande.
- 404 : l'id n'existe pas ou n'appartient pas à ce sous-compte (isolation stricte par société). 500 : erreur temporaire côté plateforme (panne, connexion du sous-compte à renouveler) — retente plus tard, ne conclus pas que la facture n'existe pas.
- 409 si la plateforme du sous-compte ne permet pas le téléchargement — cas limite, n'arrive pas avec le raccordement standard.
Consommation
Suis en temps réel ce que ton abonnement va facturer : sous-comptes actifs du mois et documents émis. Un sous-compte est actif dès qu'il a émis au moins un document dans le mois.
Consommation du mois
GET /api/partner/v1/usage
Scope usage:read
Paramètre month au format YYYY-MM (défaut : mois en cours). bill.mode reflète ton offre (flat, per_document ou custom) et bill.amountCents est l'estimation totale du mois. En offre à l'acte, la facturation porte sur billableDocuments (factures ET avoirs — un avoir consomme un numéro légal et un PDF, il compte comme un document émis). documentsIssued/creditNotesIssued détaillent les deux. Les documents des comptes connectés (linkedDocuments) ne te sont jamais facturés.
{
"month": "2026-07",
"activeCompanies": 14,
"documentsIssued": 82,
"ereportingDeclarationsSent": 31,
"creditNotesIssued": 5,
"billableDocuments": 87,
"linkedDocuments": 0,
"pricingMode": "flat",
"includedCompanies": 10,
"pricePerExtraCompanyCents": 500,
"bill": {
"mode": "flat",
"baseCents": 9900,
"extraCompanies": 4,
"extraAmountCents": 2000,
"amountCents": 11900
}
}curl "https://billies.fr/api/partner/v1/usage?month=2026-07" \
-H "Authorization: Bearer $BILLIES_API_KEY"- Offre Intégrée (mode flat) : le barème est dégressif par tranche de sous-comptes actifs — 5 € du 11ᵉ au 100ᵉ, 4 € du 101ᵉ au 500ᵉ, 3 € au-delà. includedCompanies (10) et pricePerExtraCompanyCents ne sont renseignés qu'en flat.
- Offre à l'acte (mode per_document) : bill.amountCents est calculé sur billableDocuments (factures + avoirs), pas sur documentsIssued seul. Réconcilie ta facturation sur billableDocuments.
- ereportingDeclarationsSent est purement INFORMATIF : les déclarations e-reporting (ventes aux particuliers) ne sont jamais facturées — ni au sous-compte actif, ni à l'acte. Le compteur porte sur les déclarations transmises dans le mois pour tes sous-comptes.
Règles métier à connaître
L'API applique le droit français de la facturation. Quatre règles structurent tout le reste — les connaître t'évite la plupart des 409.
Une facture émise est immuable
C'est une obligation légale française, pas un choix d'API : une facture émise ne se modifie pas et ne se supprime pas. Le seul verbe correctif est l'avoir (POST …/credit-note), qui annule la facture d'origine avec son propre numéro — puis tu refactures proprement. Toute mutation sur un document émis renvoie 409 conflict.
Cycle de vie : brouillon → émis → accepté / payé
Un document naît en draft: modifiable et supprimable à volonté, sans numéro. L'émission le fige en sent. Ensuite, un devis signé via le lien de signature passe accepted(il n'y a pas de statut signed), une facture passe partially_paid puis paid quand les paiements enregistrés couvrent le TTC.
La numérotation est séquentielle et légale
Le numéro est attribué au moment de l'émission, dans une séquence chronologique continue et sans trou, propre à chaque sous-compte. Tu ne peux ni choisir un numéro, ni en réserver un à l'avance — c'est ce qui rend les documents opposables en cas de contrôle.
E-facturation via plateforme de dématérialisation
Quand la e-facturation est activée sur un sous-compte, ses factures B2B partent au format Factur-X et sont transmises via la plateforme de dématérialisation à laquelle Billies est raccordé — sans rien changer à tes appels : c'est le même POST …/issue.
À voir aussi
Prêt à facturer depuis ton logiciel ?
Active l'API dans tes réglages, crée ta clé, émets ton premier devis dans l'heure. À l'acte (0 € par mois, 0,50 € par document) ou intégré (99 €/mois, 10 sous-comptes actifs inclus) — sans engagement.
Un sous-compte qui n'émet rien ne coûte rien
