/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 ».
Un tarif, pas de grille
99 € par mois · 10 sous-comptes actifs inclus ·puis 5 € par sous-compte actif
Le prix par sous-compte actif est dégressif : 5 € par mois jusqu'à 100 sous-comptes actifs, 4 € au-delà de 100, 3 € au-delà de 500. 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.
Pas d'engagement, pas de frais de mise en service. Le détail de ta consommation est disponible à tout moment via GET /usage.
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.
Référence des endpoints
Base : https://billies.fr/api/partner/v1. Dix-huit endpoints, quatre familles : sous-comptes, clients finaux, documents, 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. Pour une société, tu peux poser rcsNumber, rcsCity et shareCapitalCents (capital en centimes) dès la création.
{
"name": "Plomberie Martin",
"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",
"legalForm": "ei",
"siret": "73282932000074",
"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.
- 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).
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",
"legalForm": "ei",
"siret": "73282932000074",
"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, siret (une seule fois), vatRegime, legalForm, rcsCity, rcsNumber, shareCapitalCents, addressLine1, addressLine2, postalCode, city, country, iban, bic, bankName, pdfTemplateKey, pdfBrandColor, pdfFooterText, legalMentionsCustom.
{
"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).
- pdfTemplateKey, pdfBrandColor et pdfFooterText pilotent l'habillage des PDF émis — c'est là que se joue la marque grise.
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.",
"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,
"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.
- 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,
"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.
- 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 paiement reçu sur une facture émise (virement, chèque, espèces…). Quand le cumul des paiements atteint le TTC, la facture passe en paid. Les paiements partiels sont acceptés.
{
"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é). Pour corriger une erreur, crée l'avoir puis refacture proprement. L'avoir est créé et émis en un seul appel.
{
"creditNote": {
"id": "e4d3c2b1-a0f9-4e8d-9c7b-6a5f4e3d2c1b",
"type": "credit_note",
"status": "sent",
"number": "AV-2026-0007",
"creditNoteOfId": "3a2b1c0d-9e8f-4a5b-8c7d-6e5f4a3b2c1d",
"totalTtcCents": -80190,
"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"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 détaille ce que le mois te coûte : abonnement de base plus la part variable (extraAmountCents) calculée sur les sous-comptes actifs au-delà des includedCompanies inclus.
{
"month": "2026-07",
"activeCompanies": 14,
"documentsIssued": 87,
"includedCompanies": 10,
"pricePerExtraCompanyCents": 500,
"bill": {
"extraCompanies": 4,
"extraAmountCents": 2000,
"amountCents": 11900
}
}curl "https://billies.fr/api/partner/v1/usage?month=2026-07" \
-H "Authorization: Bearer $BILLIES_API_KEY"- pricePerExtraCompanyCents est le prix de la première tranche. 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à — bill.extraAmountCents applique déjà ces tranches.
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. 99 €/mois, 10 sous-comptes actifs inclus, sans engagement.
Un sous-compte qui n'émet rien ne coûte rien
