Devis
L'objet quote représente une proposition commerciale envoyée au client avant émission de la facture définitive.
À la différence des factures, les devis n'ont pas de numérotation opposable et peuvent être modifiés tant qu'ils ne sont pas acceptés.
Endpoints
| Méthode | Chemin | Description |
|---|---|---|
| POST | /v1/quotes | Créer un devis |
| GET | /v1/quotes | Lister les devis |
| GET | /v1/quotes/:id | Récupérer un devis |
| PATCH | /v1/quotes/:id | Modifier (drafts uniquement) |
| DELETE | /v1/quotes/:id | Supprimer un brouillon |
| POST | /v1/quotes/:id/send | Passer en sent (attribue le numéro, planifie le rappel J-7) |
| POST | /v1/quotes/:id/email | Renvoyer par email |
| POST | /v1/quotes/:id/accept | Marquer comme accepté |
| POST | /v1/quotes/:id/refuse | Marquer comme refusé |
| POST | /v1/quotes/:id/convert | Convertir en brouillon commercial (TVA non décidée) |
| POST | /v1/quotes/:id/clone | Dupliquer en brouillon |
| GET | /v1/quotes/:id/pdf | Télécharger le PDF |
Créer un devis
$ curl -X POST https://facturino.com/api/v1/quotes \
-H "Authorization: Bearer fac_test_..." \
-H "Idempotency-Key: quote-create-opportunity-1842" \
-H "Content-Type: application/json" \
-d '{
"customerId": "cus_8f2k4m9n",
"lines": [
{
"description": "Refonte du site corporate",
"quantity": "1", "unit": "flat_rate",
"unitPrice": 1250000, "vatRate": 2000, "vatCode": "S"
}
],
"dates": { "issued": "2026-04-22", "validUntil": "2026-05-22" },
"notes": "Devis valable 30 jours, signature électronique acceptée."
}' La structure des lignes (lines), des totaux (totals) et des montants suit exactement la même convention que les factures — des centimes entiers aussi bien en requête qu'en réponse (symétrie entrée/sortie).
La fenêtre de validité est obligatoire et se fournit de deux façons exclusives : soit une date absolue
dates.validUntil, soit validityDays (entier 1–365) — un nombre de jours à partir de la date d'émission.
Fournir l'un ou l'autre (mais pas les deux). Si dates.issued est omis, il prend par défaut la date du jour.
Cycle de vie
| Statut | Description | Transitions |
|---|---|---|
draft | Brouillon éditable | → sent, suppression |
sent | Envoyé au client | → viewed, accepted, refused, expired |
viewed | Consulté par le client | → accepted, refused, expired |
accepted | Accepté par le client | → converted |
refused | Refusé par le client | → draft (correction) |
expired | Date de validité dépassée | → sent (renvoi) |
converted | Converti en facture | (terminal) |
Le suivi viewed repose sur le lien public envoyé par email — il s'active dès la première consultation, idempotent ensuite.
Un rappel automatique est envoyé avant la date de validité (J-7 avant dates.validUntil), tant que le devis reste en attente (sent ou viewed).
Envoyer au client
$ curl -X POST https://facturino.com/api/v1/quotes/quo_a740665b/email \
-H "Authorization: Bearer fac_test_..." \
-H "Content-Type: application/json" \
-d '{
"recipientEmail": "marie@durand.fr",
"customMessage": "Bonjour Marie, voici notre proposition comme convenu."
}'
L'envoi joint le PDF en pièce attachée et inclut un lien public unique (token opaque, sans compte) permettant au client de consulter le devis, puis de l'accepter ou le refuser en ligne — l'action déclenche la transition de statut (accepted / refused) et l'événement webhook correspondant.
Si le PDF n'a pas encore été généré (création récente), la réponse retourne 202 Accepted avec un identifiant de job (id) à poller —
relancez l'envoi quand le PDF est prêt.
Convertir, décider, adosser, finaliser
Le cycle du devis se déroule sur un seul document :
convertir → décider → adosser → finaliser.
Ne créez jamais une seconde facture : cela abandonnerait le brouillon converti et romprait
la filiation devis → facture.
1. Convertir
Quand le client accepte, la conversion produit un brouillon commercial : il
énonce l'opération du devis et aucune conclusion fiscale. La TVA du devis était
indicative ; le brouillon porte donc taxSource: null, un items vide
et des totals à zéro — parce que rien n'est décidé, jamais parce que la TVA serait nulle.
L'opération se lit dans commercialDraft.
$ curl -X POST https://facturino.com/api/v1/quotes/quo_a740665b/convert \
-H "Authorization: Bearer fac_test_..."
# Réponse — brouillon COMMERCIAL créé à partir du devis
# (la facture seule est retournée, pas le couple { quote, invoice })
# taxSource null : l'opération est énoncée, aucune TVA n'est encore décidée.
{
"id": "inv_new_draft",
"object": "invoice",
"status": "draft",
"taxSource": null,
"items": [],
"commercialDraft": {
"priceMode": "tax_exclusive",
"totalCents": 80000,
"lines": [{ "reference": "li_a1", "unitPrice": 80000, "quantity": "1", ... }]
},
"sourceQuoteId": "quo_a740665b"
} 2. Décider
Prenez une décision fiscale sur exactement l'opération que le brouillon énonce :
reprenez ses commercialDraft.lines — mêmes reference, mêmes montants — et
donnez à effectiveAt la date d'émission du brouillon. Les références de ligne sont
attribuées côté serveur à la conversion : relisez-les, ne les inventez pas. Voir
Décisions fiscales.
3. Adosser la décision au brouillon
POST /v1/invoices/:id/bind-tax-decision fige la décision sur ce même brouillon.
L'appel est idempotent sur la décision : le rejouer renvoie la même facture.
Adosser une autre décision à une facture déjà adossée, ou la même décision à une seconde
facture, répond 409.
$ curl -X POST https://facturino.com/api/v1/invoices/inv_new_draft/bind-tax-decision \
-H "Authorization: Bearer fac_test_..." \
-H "Content-Type: application/json" \
-d '{
"taxDecisionId": "taxdec_9c1f",
"decisionLines": [{ "taxLineRef": "li_a1", "unit": "hour" }]
}'
# Réponse — LE MÊME brouillon, désormais adossé à sa décision.
# Il reste en statut draft : la finalisation est un appel distinct.
{
"id": "inv_new_draft",
"status": "draft",
"taxSource": "facturino",
"taxDecisionId": "taxdec_9c1f",
"sourceQuoteId": "quo_a740665b"
} 4. Finaliser
Adosser fige la TVA ; POST /v1/invoices/:id/finalize émet la facture — numéro,
mentions légales, cycle de dépôt. La facture conserve sourceQuoteId=quo_... ;
retrouvez les factures issues d'un devis via GET /v1/invoices?convertedFrom=quo_....
Acceptation explicite ou implicite ? L'endpoint convert exige que le devis soit en statut accepted. Pour passer en accepted sans interaction client (cas d'usage interne, importation de données existantes), appelez POST /v1/quotes/:id/accept (sans corps de requête) — la réponse est { id, object: "quote", status: "accepted" } et l'événement quote.accepted est émis.
Lister et filtrer
Filtres supportés :
| Paramètre | Description |
|---|---|
status | Filtrer par statut (draft, sent, accepted…) |
date_from / date_to | Plage de dates ISO (sur created par défaut, ou updated selon sort) |
sort | created (défaut) ou updated |
limit, starting_after | Pagination cursor-based (défaut 25, max 100) |
Conformité
Les devis ne sont pas soumis à la facturation électronique obligatoire (article 289 bis du CGI vise uniquement les factures). Ils restent toutefois soumis à l'article L.441-9 du Code de commerce sur les mentions obligatoires entre professionnels :
- Identité et SIRET du vendeur
- Désignation des prestations / produits
- Quantités et prix unitaires HT
- Date d'émission et durée de validité
- Modalités de paiement (acompte, échelonnement)
- Conditions générales de vente (annexées ou référencées)
Le générateur PDF Facturino applique automatiquement ces mentions à partir des données de l'entreprise (paramétrables depuis Paramètres → Facturation).
Étapes suivantes
- Factures — finaliser après conversion
- Webhooks — événements
quote.* - Référence interactive