Documentation API · v1

Intégrer Flow étape par étape

Guide prêt à l’emploi : créer une clé, authentifier vos appels, créer clients & factures, récupérer les PDF et vérifier les webhooks. Exemples curl inclus.

Plan Business · Base URL /api/v1

1. Démarrer en 5 minutes

  1. Compte Business — inscription ou upgrade depuis Profil.
  2. Profil société complet dans l’app (raison sociale, adresse, SIRET, mentions légales) — requis pour émettre une facture.
  3. Ouvrez l’app → menu API développeurs (/developer).
  4. Créez une clé LIVE (ou TEST pour le préfixe nf_test_). Copiez-la immédiatement — elle n’est plus réaffichée.
  5. Exportez-la dans votre shell :
    export NF_KEY="nf_live_…"

Les clés nf_test_* pointent vers les mêmes données que LIVE (préfixe distinct uniquement — pas de sandbox isolée pour l’instant).

2. Authentification

Chaque requête /api/v1/** exige une clé API. Un JWT de session web est refusé sur cette API.

Headers acceptés

Authorization: Bearer nf_live_<secret>

# ou
X-Api-Key: nf_live_<secret>

Scopes

Par défaut, une clé a tous les scopes. Vous pouvez restreindre à la création :

  • clients:read / clients:write
  • invoices:read / invoices:write
  • quotes:read / quotes:write

Sans le bon scope → 403 avec code: "insufficient_scope".

3. Concepts importants

Isolation

Toutes les ressources sont limitées au compte propriétaire de la clé. Impossible de lire / modifier les données d’un autre tenant.

Pagination

Les listes renvoient { data, page, size, total, totalPages }. Utilisez ?page=0&size=50 (max 100).

Rate limit

~60 requêtes / minute / clé. Au-delà → 429rate_limited. Headers X-RateLimit-* fournis.

Base URL

Local : /api/v1
Prod : https://<votre-hôte>/api/v1

4. Parcours type (recommandé)

Enchaînement classique pour facturer depuis votre application :

  1. A
    Créer ou retrouver un client

    POST /clients puis stockez le id.

  2. B
    Créer la facture

    POST /invoices avec clientId, taxRate et lines.

  3. C
    Émettre / envoyer

    POST /invoices/{id}/send → numéro officiel + email.

  4. D
    PDF (optionnel)

    GET /invoices/{id}/pdf → URL temporaire à télécharger.

  5. E
    Écouter les webhooks

    invoice.* et quote.* (créée, envoyée, payée, acceptée, convertie, annulée…) pour garder votre système à jour.

5. Référence — Clients

Ressource de base. Créez d’abord un client pour obtenir un clientId utilisable sur les factures.

GET/clientsclients:read

Lister les clients

Retourne la page de clients du compte lié à la clé API.

Quand l’utiliser : Pour synchroniser un CRM, afficher une liste, ou retrouver un clientId avant de facturer.

Query :page (défaut 0), size (défaut 50, max 100)

Réponse

{
  "data": [{ "id": 12, "name": "ACME", "email": "contact@acme.fr", ... }],
  "page": 0,
  "size": 50,
  "total": 1,
  "totalPages": 1
}

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/clients?page=0&size=50"
GET/clients/{id}clients:read

Détail d’un client

Récupère un client par son identifiant interne Flow.

Quand l’utiliser : Après une création, ou pour vérifier SIRET / adresse avant d’émettre une facture.

Réponse

{
  "id": 12,
  "name": "ACME",
  "legalName": "ACME SAS",
  "email": "contact@acme.fr",
  "phone": "+33102030405",
  "address": "10 rue de Rivoli",
  "postalCode": "75001",
  "city": "Paris",
  "country": "France",
  "siret": "12345678900012",
  "vatNumber": "FR12345678900",
  "createdAt": "2026-07-25T10:00:00",
  "updatedAt": "2026-07-25T10:00:00"
}

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/clients/12"
  • 404 si le client n’appartient pas à votre compte (isolation stricte).
POST/clientsclients:write

Créer un client

Ajoute un client à votre carnet Flow. L’email doit être unique **dans votre compte**.

Quand l’utiliser : Avant de créer une facture : vous aurez besoin du `id` renvoyé.

Body JSON

{
  "name": "ACME",
  "email": "contact@acme.fr",
  "customerKind": "B2B",
  "legalName": "ACME SAS",
  "phone": "+33102030405",
  "address": "10 rue de Rivoli",
  "postalCode": "75001",
  "city": "Paris",
  "country": "France",
  "siret": "12345678900012",
  "vatNumber": "FR12345678900"
}

Réponse

Même forme que le détail client (avec `id`).

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"ACME","email":"contact@acme.fr","city":"Paris","vatNumber":"FR12345678900"}' \
  "/api/v1/clients"
  • `name` et `email` sont obligatoires.
  • `customerKind` : `B2B` (défaut) ou `B2C`. `vatNumber` (n° TVA) obligatoire uniquement pour un client `B2B`.
  • Champs optionnels : legalName, phone, adresse, SIRET, livraison, routingEndpointId.
  • 409 (conflict) si l’email existe déjà chez vous.
PATCH/clients/{id}clients:write

Mettre à jour un client

Met à jour partiellement les champs fournis (les autres restent inchangés).

Quand l’utiliser : Correction d’adresse, téléphone, SIRET, etc.

Body JSON

{ "phone": "+33102030405", "city": "Lyon" }

Exemple curl

curl -s -X PATCH -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone":"+33102030405"}' \
  "/api/v1/clients/12"
DELETE/clients/{id}clients:write

Supprimer un client

Supprime un client sans facture, devis ni facture récurrente associés.

Quand l’utiliser : Nettoyer un doublon ou un client créé par erreur.

Réponse

{ "message": "Client supprimé" }

Exemple curl

curl -s -X DELETE -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/clients/12"
  • 400 si le client a des factures, devis ou factures récurrentes liés.

6. Référence — Factures

Créez, émettez, récupérez le PDF. Les totaux HT/TTC sont calculés côté Flow à partir des lignes et du taux de TVA.

GET/invoicesinvoices:read

Lister les factures

Liste paginée des factures du compte. Filtre optionnel par statut.

Quand l’utiliser : Tableau de bord externe, sync comptable, suivi des impayés.

Query :page, size, status (ex. Brouillon, A_Envoyer, En_Attente_de_Paiement, Payée, Annulée…)

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices?page=0&size=50&status=En_Attente_de_Paiement"
GET/invoices/{id}invoices:read

Détail d’une facture

Retourne la facture avec lignes, totaux HT/TTC, client et statut.

Quand l’utiliser : Afficher une facture dans votre UI, ou vérifier l’état avant envoi / PDF.

Réponse

{
  "id": 10,
  "number": "BROUILLON-…",
  "status": "Brouillon",
  "type": "FACTURE",
  "clientId": 12,
  "clientName": "ACME",
  "emissionDate": "2026-07-25",
  "dueDate": "2026-08-25",
  "totalHt": 1950.00,
  "totalTtc": 2340.00,
  "taxRate": 20,
  "lines": [
    { "id": 1, "name": "Conseil", "quantity": 3, "unitPrice": 650, "taxRate": 20 }
  ],
  "createdAt": "2026-07-25T11:00:00"
}

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10"
POST/invoicesinvoices:write

Créer une facture

Crée une facture rattachée à un client existant. Les prestations (lignes) sont créées / réutilisées dans votre catalogue.

Quand l’utiliser : Depuis votre outil métier (CRM, ERP, marketplace) dès qu’une prestation est facturable.

Body JSON

{
  "clientId": 12,
  "taxRate": 20,
  "emissionDate": "2026-07-25",
  "dueDate": "2026-08-25",
  "status": "Brouillon",
  "lines": [
    { "name": "Conseil", "quantity": 3, "unitPrice": 650 }
  ]
}

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": 12,
    "taxRate": 20,
    "status": "Brouillon",
    "lines": [{"name":"Conseil","quantity":3,"unitPrice":650}]
  }' \
  "/api/v1/invoices"
  • `clientId`, `taxRate` et au moins une ligne (`name`) sont obligatoires.
  • `quantity` = entier > 0 ; `unitPrice` ≥ 0.
  • `status` à la création : uniquement `Brouillon` (défaut) ou `A_Envoyer`.
  • Déclenche le webhook `invoice.created` si configuré.
  • Le profil société doit être complet dans l’app (SIRET, adresse, mentions…) pour pouvoir émettre.
  • La création **ne** transmet **pas** à la PA (e-facture). Voir `/send` + auto-PA B2B.
POST/invoices/{id}/readyinvoices:write

Passer un brouillon en « À envoyer »

Numérote si besoin et passe `Brouillon` → `A_Envoyer`. Obligatoire avant `/send` si vous avez créé un brouillon.

Quand l’utiliser : Validation métier du brouillon avant émission.

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10/ready"
  • Refuse si le statut n’est pas `Brouillon`.
  • Optionnel si vous créez déjà en `A_Envoyer`, ou si vous appelez `/send` (qui prépare le brouillon automatiquement).
POST/invoices/{id}/sendinvoices:write

Émettre / envoyer une facture

Passe en `En_Attente_de_Paiement`, attribue un numéro officiel si besoin, webhook `invoice.sent`, notification in-app. Si la facture est encore en brouillon, elle est d’abord passée en « À envoyer » automatiquement.

Quand l’utiliser : Quand la facture est validée côté métier et doit être considérée comme émise.

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10/send"
  • Déclenche le webhook `invoice.sent`.
  • Pas d’e-mail SMTP client automatique via cette route seule.
  • Si auto-transmission PA activée + client B2B + checklist OK : tentative de dépôt PA (même logique UI).
  • Contrôle manuel PA : `POST /invoices/{id}/einvoice/transmit`.
  • Une facture déjà émise ne se modifie plus comme un brouillon (avoirs dans l’UI).
GET/einvoice/painvoices:read

État de la Plateforme Agréée

Indique si la transmission PA est disponible pour le compte (mode, stub, adresse vendeur…).

Quand l’utiliser : Avant d’intégrer un flux e-facture.

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/einvoice/pa"
GET/invoices/{id}/einvoice/readinessinvoices:read

Checklist e-facture d’une facture

Retourne `readyForExport`, `paApplicable`, la liste des checks et la validation EN16931 le cas échéant.

Quand l’utiliser : Avant `transmit`, pour savoir ce qui bloque.

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10/einvoice/readiness"
  • Client B2C : `paApplicable=false` (pas de transmission).
  • Corrigez les checks `ok:false` (SIRET vendeur, adresse client, etc.) dans l’app si besoin.
GET/invoices/{id}/einvoice/transmissioninvoices:read

Statut de transmission PA

Dernier dépôt PA pour la facture (`NOT_SENT`, `SUBMITTED`, `REJECTED`…).

Quand l’utiliser : Suivi après transmit ou auto-PA au `/send`.

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10/einvoice/transmission"
POST/invoices/{id}/einvoice/transmitinvoices:write

Transmettre à la PA

Dépose la facture électronique chez la Plateforme Agréée. Facture déjà émise (après `/send`), client B2B, checklist OK.

Quand l’utiliser : Contrôle explicite du dépôt PA depuis votre intégration.

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10/einvoice/transmit"
  • Refuse les brouillons et les factures « À envoyer » non encore émises via `/send`.
  • En cas de checklist incomplète : corrigez puis rappellez readiness.
  • Sandbox Super PDP : client type Tricatel (`siret` 000000001 + `routingEndpointId` 315143296_42513).
GET/invoices/{id}/pdfinvoices:read

Obtenir le PDF

Génère (ou régénère) le PDF et renvoie une **URL de téléchargement temporaire** signée.

Quand l’utiliser : Archivage, pièce jointe dans votre outil, ou affichage au client hors Flow.

Réponse

{
  "downloadUrl": "https://…/api/invoices/pdf/download/<token>",
  "expiresInSeconds": 300
}

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10/pdf"
  • Téléchargez ensuite `downloadUrl` (GET, sans clé API — le token suffit).
  • L’URL expire rapidement : ne la stockez pas durablement.
PUT/invoices/{id}invoices:write

Éditer un brouillon de facture

Remplace client, taxe, dates et lignes d’un brouillon. Mêmes règles que la création.

Quand l’utiliser : Corriger un brouillon avant émission (montant, ligne oubliée, mauvais client…).

Body JSON

{
  "clientId": 12,
  "taxRate": 20,
  "emissionDate": "2026-07-25",
  "dueDate": "2026-08-25",
  "lines": [
    { "name": "Conseil", "quantity": 4, "unitPrice": 650 }
  ]
}

Exemple curl

curl -s -X PUT -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  -d '{"clientId":12,"taxRate":20,"lines":[{"name":"Conseil","quantity":4,"unitPrice":650}]}' \
  "/api/v1/invoices/10"
  • 400 si la facture n’est plus au statut `Brouillon` (utilisez un avoir pour corriger une facture émise).
  • Remplacement complet des lignes : renvoyez toutes les lignes voulues, pas seulement celle qui change.
DELETE/invoices/{id}invoices:write

Supprimer un brouillon de facture

Supprime définitivement un brouillon sans paiement.

Quand l’utiliser : Nettoyer un brouillon créé par erreur.

Réponse

{ "message": "Facture supprimee" }

Exemple curl

curl -s -X DELETE -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10"
  • 400 si la facture est émise ou a un paiement enregistré — annulez-la ou créez un avoir.
POST/invoices/{id}/cancelinvoices:write

Annuler une facture émise

Passe une facture émise en `Annulée`. Restitue le stock lié si applicable.

Quand l’utiliser : La prestation n’aura finalement pas lieu et aucun paiement n’a été encaissé.

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10/cancel"
  • Déclenche le webhook `invoice.cancelled`.
  • 400 si la facture est déjà payée ou a un paiement partiel — créez un avoir dans ce cas.
POST/invoices/{id}/credit-noteinvoices:write

Créer un avoir

Avoir total (body vide ou `lines` omis) ou partiel (`lines` avec quantités à créditer) sur une facture émise.

Quand l’utiliser : Correction après émission, retour partiel, geste commercial.

Body JSON

{
  "lines": [
    { "sourceLineItemId": 1, "quantity": 1 }
  ]
}

Réponse

Une facture de type `AVOIR` (mêmes champs qu’une facture, montants négatifs).

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  "/api/v1/invoices/10/credit-note"
  • Body omis ou `lines` vide = avoir total (tout le restant créditable).
  • Déclenche le webhook `invoice.credit_note.created`.
  • 400 sur un brouillon, un avoir, ou une facture déjà entièrement créditée.
GET/invoices/{id}/paymentsinvoices:read

Lister les paiements d’une facture

Historique des paiements (manuels ou Stripe) enregistrés sur la facture.

Quand l’utiliser : Rapprochement comptable, affichage du solde restant.

Réponse

[{
  "id": 3,
  "invoiceId": 10,
  "amount": 1000.00,
  "paidAt": "2026-08-01T10:00:00",
  "method": "MANUAL",
  "note": "Acompte"
}]

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/invoices/10/payments"
POST/invoices/{id}/paymentsinvoices:write

Enregistrer un paiement

Ajoute un paiement manuel sur une facture émise et renvoie la facture à jour (statut, montant restant dû).

Quand l’utiliser : Paiement reçu hors Stripe (virement, chèque, espèces…) à rapprocher.

Body JSON

{ "amount": 1000.00, "method": "MANUAL", "note": "Acompte" }

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount":1000.00,"method":"MANUAL"}' \
  "/api/v1/invoices/10/payments"
  • `amount` doit être positif ; `paidAt` par défaut maintenant, `method` par défaut `MANUAL`.
  • Passe la facture en `Payée` dès que le cumulé atteint le TTC ; déclenche `invoice.paid`.

7. Référence — Devis

Créez, éditez, envoyez et convertissez des devis rattachés à un client existant — du brouillon jusqu’à la facture. Seules l’acceptation et le refus restent réservés à l’app / au portail client (parcours signé, pas un simple changement de statut par API).

GET/quotesquotes:read

Lister les devis

Liste paginée des devis du compte. Filtre optionnel par statut.

Quand l’utiliser : Tableau de bord externe, suivi des devis en attente de réponse client.

Query :page, size, status (ex. Brouillon, A_Envoyer, Envoyé, Accepté, Refusé, Converti)

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/quotes?page=0&size=50&status=Envoyé"
GET/quotes/{id}quotes:read

Détail d’un devis

Retourne le devis avec lignes, totaux HT/TTC, client et statut.

Quand l’utiliser : Afficher un devis dans votre UI, ou vérifier son statut avant relance.

Réponse

{
  "id": 4,
  "number": "DEV-2026-07-4",
  "status": "Brouillon",
  "clientId": 12,
  "clientName": "ACME",
  "emissionDate": "2026-07-25",
  "validUntilDate": "2026-08-25",
  "totalHt": 1950.00,
  "totalTtc": 2340.00,
  "taxRate": 20,
  "lines": [
    { "id": 1, "name": "Conseil", "quantity": 3, "unitPrice": 650, "taxRate": 20 }
  ],
  "createdAt": "2026-07-25T11:00:00"
}

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/quotes/4"
POST/quotesquotes:write

Créer un devis

Crée un devis rattaché à un client existant. Les prestations (lignes) sont créées / réutilisées dans votre catalogue, comme pour les factures.

Quand l’utiliser : Depuis votre outil métier dès qu’un chiffrage doit être proposé au client.

Body JSON

{
  "clientId": 12,
  "taxRate": 20,
  "emissionDate": "2026-07-25",
  "validUntilDate": "2026-08-25",
  "status": "Brouillon",
  "lines": [
    { "name": "Conseil", "quantity": 3, "unitPrice": 650 }
  ]
}

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": 12,
    "taxRate": 20,
    "status": "Brouillon",
    "lines": [{"name":"Conseil","quantity":3,"unitPrice":650}]
  }' \
  "/api/v1/quotes"
  • `clientId`, `taxRate` et au moins une ligne (`name`) sont obligatoires.
  • `quantity` = entier > 0 (max 1 000 000) ; `unitPrice` ≥ 0.
  • `validUntilDate` optionnelle ; si fournie, ne peut pas être antérieure à `emissionDate`.
  • `status` à la création : uniquement `Brouillon` (défaut) ou `A_Envoyer`.
  • Déclenche le webhook `quote.created` si configuré.
PUT/quotes/{id}quotes:write

Éditer un devis brouillon

Remplace client, taxe, dates et lignes d’un devis brouillon.

Quand l’utiliser : Corriger un devis avant de le passer « À envoyer ».

Body JSON

{
  "clientId": 12,
  "taxRate": 20,
  "emissionDate": "2026-07-25",
  "validUntilDate": "2026-08-25",
  "lines": [
    { "name": "Conseil", "quantity": 4, "unitPrice": 650 }
  ]
}

Exemple curl

curl -s -X PUT -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  -d '{"clientId":12,"taxRate":20,"lines":[{"name":"Conseil","quantity":4,"unitPrice":650}]}' \
  "/api/v1/quotes/4"
  • 400 si le devis n’est plus au statut `Brouillon`.
DELETE/quotes/{id}quotes:write

Supprimer un devis brouillon

Supprime définitivement un devis brouillon.

Quand l’utiliser : Nettoyer un devis créé par erreur.

Réponse

{ "message": "Devis supprimé" }

Exemple curl

curl -s -X DELETE -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/quotes/4"
PATCH/quotes/{id}/statusquotes:write

Brouillon ⇄ À envoyer

Change le statut entre `Brouillon` et `A_Envoyer` uniquement. L’envoi, l’acceptation et le refus suivent un parcours dédié (e-mail signé / portail client), pas un simple changement de statut.

Quand l’utiliser : Repasser un devis « À envoyer » en brouillon pour le corriger, ou l’y préparer.

Body JSON

{ "status": "A_Envoyer" }

Exemple curl

curl -s -X PATCH -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"A_Envoyer"}' \
  "/api/v1/quotes/4/status"
  • 400 pour toute autre valeur (Envoyé, Accepté, Refusé, Converti — non pilotables par cette route).
POST/quotes/{id}/sendquotes:write

Envoyer le devis par e-mail

Génère le PDF et l’envoie au client (ou à `recipientEmail`). Passe `A_Envoyer` → `Envoyé` automatiquement.

Quand l’utiliser : Le devis est prêt et doit partir au client.

Body JSON

{ "recipientEmail": "client@exemple.fr" }

Réponse

{ "sent": true, "recipientEmail": "client@exemple.fr", "status": "Envoyé", "numQuote": "DEV-2026-07-4" }

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  -H "Content-Type: application/json" \
  "/api/v1/quotes/4/send"
  • `recipientEmail` optionnel : par défaut l’e-mail du client.
  • Déclenche le webhook `quote.sent`.
  • 400 sur un brouillon (passez d’abord en `A_Envoyer`), un devis converti ou refusé.
GET/quotes/{id}/pdfquotes:read

Télécharger le PDF du devis

Retourne directement le fichier PDF (pas de lien intermédiaire, contrairement aux factures).

Quand l’utiliser : Archivage ou aperçu côté intégration.

Exemple curl

curl -s -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/quotes/4/pdf" -o devis-4.pdf
POST/quotes/{id}/convert-to-invoicequotes:write + invoices:write

Convertir un devis accepté en facture

Crée une facture (`A_Envoyer`) à partir d’un devis `Accepté` et marque le devis `Converti`.

Quand l’utiliser : Le client a accepté (portail ou en direct) : passez à la facturation sans ressaisie.

Réponse

La facture créée (même forme que `GET /invoices/{id}`).

Exemple curl

curl -s -X POST -H "Authorization: Bearer $NF_KEY" \
  "/api/v1/quotes/4/convert-to-invoice"
  • Nécessite les deux scopes (`quotes:write` et `invoices:write`) puisque l’action crée une facture.
  • 400 si le devis n’est pas `Accepté`, ou déjà `Converti`.
  • Déclenche `quote.converted` puis `invoice.created` (sur la facture créée).
  • Pour une facture brouillon éditable avant envoi, sans changer le statut du devis : utilisez l’app (`Créer un brouillon` depuis le devis) — non exposé en API pour l’instant.

8. Webhooks

Configurez une URL HTTPS depuis API développeurs dans l’app. Flow POST le JSON d’événement et signe le corps pour que vous puissiez vérifier l’origine.

Événements

invoice.created

Après POST /invoices réussi.

invoice.sent

Après POST /invoices/{id}/send.

invoice.paid

Quand la facture passe au statut Payée (manuel ou Stripe).

invoice.cancelled

Après POST /invoices/{id}/cancel.

invoice.credit_note.created

Après POST /invoices/{id}/credit-note (avoir total ou partiel).

quote.created

Après POST /quotes réussi.

quote.sent

Après POST /quotes/{id}/send.

quote.accepted

Quand le client accepte le devis (app ou portail).

quote.converted

Après POST /quotes/{id}/convert-to-invoice.

Payload type

{
  "id": "evt_…",
  "type": "invoice.paid",
  "createdAt": "2026-07-25T12:00:00",
  "data": {
    "invoiceId": 10,
    "number": "FAC-2026-0001",
    "status": "Payée",
    "totalTtc": 2340.00
  }
}

Signature

Header : X-Flow-Signature: t=<unix_seconds>,v1=<hex>

Calcul : v1 = HMAC_SHA256(secret, t + "." + raw_body) où secret est celui affiché une seule fois à la création du webhook (whsec_…).

Exemple Node.js (vérification)

const crypto = require('crypto');

function verify(sigHeader, rawBody, secret, maxSkewSec = 300) {
  const parts = Object.fromEntries(
    sigHeader.split(',').map((p) => p.trim().split('='))
  );
  const t = parts.t;
  const v1 = parts.v1;
  if (!t || !v1) return false;
  if (Math.abs(Date.now() / 1000 - Number(t)) > maxSkewSec) return false;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(t + '.' + rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}
  • URL : HTTPS obligatoire (HTTP seulement vers localhost).
  • IPs privées / metadata cloud refusées (anti-SSRF).
  • Retry automatique jusqu’à 3 fois avec backoff ; pas de suivi des redirects.
  • Répondez 2xx rapidement (< 10 s).

9. Erreurs & limites

Format commun :

{ "error": "message lisible", "code": "…" }
codeHTTPSignification
api_key_required401Pas de clé API (ou JWT seul)
unauthorized401Clé invalide / révoquée
plan_required403Plan Business requis
insufficient_scope403Scope manquant sur la clé
not_found404Ressource absente ou hors compte
conflict409Ex. email client déjà présent
bad_request400Payload / paramètres invalides
rate_limited429> 60 req/min sur la clé

Limites V1

  • Max 10 clés actives et 10 webhooks par compte.
  • E-facture / PA disponible — voir §6, E-facture. Devis : création et consultation disponibles — voir §7, Devis (envoi, acceptation et conversion en facture restent réservés à l’app).
  • Toujours pas d’avoirs ni d’IA via cette API (utilisez l’app).
  • Auth = clés API uniquement (pas d’OAuth2 partenaire pour l’instant).

Prêt à brancher ?

Créez un compte Business, générez une clé dans l’app, puis rejouez le parcours client → facture → send → PDF.