Facturation et abonnements
Les factures, leur paiement par un client et le fonctionnement actuel de la facturation récurrente.
Les paiements et la facturation demandent des fonds de deux façons différentes. Votre code lance un paiement : vous appelez l'API, le téléphone s'allume et le client confirme dans la minute. Une facture est un document que vous remettez au client. Il la règle quand il le décide.
Cette section traite du second cas.
Contenu de la section
Un produit est disponible : Factures. Il produit un document numéroté, héberge la page de paiement du client et suit les fonds encaissés pour cette facture. Un abonnement, au sens d'un plan auquel un client souscrit et d'un portefeuille débité chaque mois sans intervention, n'est pas encore disponible.
| Besoin | Solution |
|---|---|
| Facturer une fois un client et être payé en ligne | Factures |
| Facturer le même client à intervalle fixe | Une facture récurrente : un nouveau brouillon à chaque cycle, qui reste à envoyer et à payer |
| Débiter automatiquement un portefeuille enregistré selon un calendrier | Aucune pour le moment, consultez Abonnements |
| Accepter un paiement lancé par votre propre checkout | Paiements, pas la facturation |
Mode live uniquement et accès selon le plan
Toutes les routes /invoices sont réservées au mode live. Une clé sandbox renvoie donc 403
avec This feature is only available in live mode., y compris pour les appels GET. La
fonctionnalité s'appelle Invoicing : 10 factures au total avec Pay as you go, et non dix par
mois, puis un nombre illimité à partir de Growth. Une fois ce plafond atteint, la création renvoie
un code 403 avec une invitation à changer de plan.
Une facture est un document, pas un débit
Créer une facture ne déplace aucun fonds et n'envoie aucune notification. L'opération enregistre un document numéroté avec ses lignes, ses totaux et un statut, puis s'arrête. L'envoi, le paiement et les relances constituent trois opérations distinctes effectuées ensuite.
https://api.wajub.com/invoicescustomer_namestringobligatoireitemsarrayobligatoirename, quantity et unit_price.invoice_datestring (date)obligatoirecurrencystringobligatoire422. Tous les montants de la facture utilisent cette devise.languageenumfacultatiffr ou en, la langue de l'e-mail et du PDF. Par défaut, la langue préférée du client lié, sinon la langue de votre compte (**Settings → Regional → Language**), sinon en.customer_idstringfacultatifcus_. Ses coordonnées sont copiées dans le document lors de la création.customer_emailstringfacultatif/send envoie la facture et son PDF, et adresse utilisée pour son paiement et son reçu. Facultatif : une facture sans e-mail reste payable, et [sa page demande une adresse au payeur](#where-the-customer-pays).due_datestring (date)facultatifinvoice_date. La facture passe à overdue une fois cette date passée.payment_terms_daysintegerfacultatifdue_date à ce nombre de jours après aujourd'hui, uniquement en l'absence de due_date.items[].tax_ratenumberfacultatifitems[].discount_typeenumfacultatifpercentage ou fixed, associé à items[].discount_value.items[].discount_valuenumberfacultatifdocument_typeenumfacultatifdéfaut : invoiceinvoice, quote ou estimate. L'API liste et récupère uniquement les factures.is_recurringbooleanfacultatifnotesstringfacultatifterms et footer se trouvent à côté.Les totaux sont calculés à partir des lignes. Vous n'envoyez donc jamais subtotal ou total.
Envoyez la facture avec une clé secrète live.
curl https://api.wajub.com/invoices \
-H "Authorization: sk.xxxxxxxxxxxxxxxx…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: invoice-amina-september" \
-d '{
"customer_name": "Amina Traoré",
"customer_email": "[email protected]",
"invoice_date": "2026-09-11",
"due_date": "2026-09-25",
"currency": "XAF",
"items": [
{ "name": "Consulting, September", "quantity": 3, "unit_price": 150000 }
]
}'La réponse est 201 Created. Tous les autres appels utilisent l'id. invoice_number vaut encore
null : la référence lisible imprimée sur le document est attribuée à l'envoi de la facture, selon
la numérotation de votre compte, la même séquence que celle du Dashboard : INV- (ou le préfixe que
vous avez choisi), l'année, puis un compteur qui repart à 0001 chaque année.
Cycle de vie d'une facture
La répétition sur ces flèches est volontaire. Chaque transition effectuée par l'API arrive sous la
forme invoice.updated, et le champ status du payload indique laquelle. Deux événements en disent
plus : invoice.paid quand la facture est réglée en totalité, et invoice.payment_succeeded pour
chaque paiement effectué sur sa page, échéance comprise. Il n'existe aucun invoice.sent,
invoice.cancelled ou invoice.overdue.
Deux états changent automatiquement. viewed est écrit lors de la première ouverture de la page de
paiement par le client. Une facture passe à overdue pendant la nuit une fois sa due_date passée.
Vous ne définissez aucun de ces deux états.
Envoyer une facture
https://api.wajub.com/invoices/{id}/sendSur un brouillon, l'appel attribue le invoice_number, passe la facture en sent, renseigne
sent_at et envoie à customer_email un e-mail avec le lien de la facture et une copie PDF en pièce
jointe, dans la language de la facture. Rappelé sur une facture déjà envoyée, il renvoie l'e-mail et
renseigne de nouveau sent_at, sans changer son statut.
L'appel a besoin d'un destinataire : customer_email, ou l'e-mail du client que désigne
customer_id. Sans l'un ni l'autre, il répond 422 sur customer_email et ne change rien, même
sur un brouillon. Une facture déjà paid, cancelled ou refunded répond 400 : il n'y a plus
rien à réclamer. Un brouillon adressé à un nom seulement peut être envoyé depuis le Dashboard, qui
le numérote et ouvre sa page sans envoyer d'e-mail ; partagez vous-même le lien, et la page demande
un e-mail au payeur.
C'est aussi l'envoi qui ouvre la page de paiement. Un draft répond 404 Invoice not found. à toute
personne qui ouvre son URL, comme s'il n'existait pas, et seuls quatre statuts sont payables :
sent, viewed, overdue et partial. Tout autre statut répond 403 This invoice is not available for payment.
Page de paiement du client
La page de paiement possède son propre domaine et utilise l'id de la facture comme chemin complet.
https://invoice.wajub.com/inv_LRQqYvlhrgUOE225KMKUCette adresse ne figure pas dans la réponse de l'API. Construisez-la à partir de l'id reçu ou
copiez-la depuis le Dashboard. C'est aussi le seul endroit où elle peut changer : un marchand qui
héberge ses factures sur un domaine personnalisé vérifié utilise ce domaine au lieu de
invoice.wajub.com.
La page s'ouvre dans la language de la facture, celle de son e-mail et de son PDF. Le payeur peut
l'afficher dans l'autre langue en ajoutant ?locale=fr ou ?locale=en à l'adresse.
La page constitue un checkout ordinaire. Elle affiche votre marque, les lignes de la facture et les
opérateurs disponibles pour sa devise. Un paiement effectué sur cette page reste un paiement
ordinaire : il apparaît dans votre liste Payments, émet payment.succeeded, rejoint votre solde et
peut être remboursé comme les autres. Après sa réussite, la facture passe à paid. Elle passe à
partial si elle est divisée en plusieurs échéances et qu'une seule a été réglée. Le paiement
désigne la facture dans son champ invoice, l'id de la facture.
Remboursez ce paiement en totalité, ou tous les paiements faits sur la facture, et la facture passe à
refunded, avec refunded_at renseigné et l'envoi de invoice.updated. Cela vaut aussi pour une
facture payée en partie, partial ou overdue avec une part réglée : dès que tout ce qui est entré
en ligne est rendu, elle est refunded. Un remboursement partiel laisse la facture en l'état. Une
facture qui porte de l'argent enregistré avec mark-paid garde son statut : cet argent n'est jamais
passé par Wajub, un remboursement Wajub ne peut donc pas le rendre. Émettez un avoir depuis le
Dashboard pour cette part.
Une facture n'a pas besoin d'e-mail pour être payée. Quand elle n'en porte aucun, c'est-à-dire sans
customer_email ni customer_id, la page affiche au payeur un champ e-mail au-dessus du bouton de
paiement et n'ouvre le paiement qu'avec une adresse valide. Cette adresse reçoit la confirmation du
paiement et son reçu, et le paiement est rattaché à celui de vos clients qui
la porte, créé avec le nom de la facture si vous n'en avez pas encore. L'adresse est aussi inscrite sur
la facture comme son customer_email, et invoice.updated vous en informe : l'échéance suivante ne
la redemande pas, et /send comme les relances du Dashboard ont désormais un destinataire. Seule la
première adresse donnée est conservée, et un e-mail que vous avez mis sur la facture n'est jamais
remplacé.
La page ne demande rien quand la facture porte un e-mail, et le payeur ne peut pas lui en substituer un autre. Elle ne demande rien non plus quand la facture est associée à un client : c'est ce client qui paie, que sa fiche comporte un e-mail ou non.
La page sert aussi la facture au format PDF, pour que le client la conserve, à l'adresse
https://api.wajub.com/i/{id}/pdf, dans la language de la facture sauf si ?locale=fr ou
?locale=en demande l'autre. Toute personne qui détient l'id peut ouvrir les deux : partagez-le
comme vous partageriez le lien lui-même.
Enregistrer des fonds encaissés ailleurs
De nombreuses factures sont payées en espèces ou par un virement bancaire extérieur à Wajub. Vous pouvez enregistrer ce paiement sur le document sans créer un faux paiement.
https://api.wajub.com/invoices/{id}/mark-paidOmettez amount pour régler intégralement la facture. Si vous le transmettez, supérieur à zéro, il
est ajouté à amount_paid. La facture reste alors partial jusqu'au règlement du total. La facture
doit être ouverte : un brouillon répond 400, puisqu'il n'a jamais été envoyé, de même qu'une
facture déjà paid, qui garde son paid_at. Une facture cancelled ou refunded refuse aussi
l'appel avec un code 400. Un document fermé par son propre parcours ne peut donc pas être réactivé.
Un amount nul répond 422.
État actuel des factures récurrentes
La création accepte is_recurring et recurring_interval. L'intervalle peut valoir daily,
weekly, monthly, quarterly ou yearly. Chaque nuit à 02:00 UTC, Wajub génère les copies
arrivées à échéance : chaque facture récurrente dont la prochaine occurrence est arrivée est copiée
dans un nouveau document avec de nouvelles dates et les coordonnées actuelles du client. La première
copie est due un intervalle après la date de la facture elle-même, et chaque cycle est généré une
seule fois.
Deux points définissent la récurrence sur Wajub. Chaque facture générée est créée avec draft. La
chaîne produit donc des documents, et non des débits. Chaque document doit encore être envoyé et
payé. Elle nécessite la fonctionnalité Recurring billing, disponible à partir de Growth. Sans elle,
aucune copie n'est générée et la facture parente est conservée. Les renouvellements reprennent
automatiquement si un compte ayant changé pour un plan inférieur repasse ensuite au plan requis.
La création d'une facture récurrente via l'API réussit avec tous les plans. Sans la fonctionnalité, c'est la génération qui est ignorée. Factures récurrentes détaille le calendrier, ce qu'une copie reprend et la façon dont une récurrence se termine.
Événements envoyés à votre webhook
Cinq événements portent la facture, pas les fonds.
| Événement | Déclencheur |
|---|---|
invoice.created | Une facture est créée avec draft : une seule fois, avec ses lignes et ses totaux |
invoice.updated | Un champ ou un statut change via l'API, y compris viewed et un paiement. Un seul par PUT, avec ses lignes et ses totaux, et aucun pour un PUT qui ne change rien |
invoice.payment_succeeded | Un paiement effectué sur la page de la facture réussit, chaque échéance comprise |
invoice.paid | La facture est réglée en totalité, en ligne ou avec mark-paid |
invoice.deleted | Une facture draft est supprimée |
Les fonds produisent un événement distinct. Lorsqu'un client paie une facture en ligne, vous recevez
payment.succeeded pour le paiement, puis invoice.updated et invoice.payment_succeeded pour le
document, et invoice.paid une fois la facture réglée. Livrez la commande avec payment.succeeded,
car il contient le montant, le canal et la référence du prestataire, et son champ invoice désigne
la facture payée.
Seule l'API émet ces événements
Une modification effectuée dans le Dashboard n'envoie aucun webhook. L'envoi, le marquage comme
payée ou l'annulation d'une facture depuis l'interface restent silencieux. Les factures passent à
overdue pendant la nuit, et ce changement n'envoie aucun webhook non plus. Utilisez le polling sur GET /invoices si vous devez les détecter.
Dans le Dashboard
Billing → Invoices fournit l'interface complète, plus large que l'API. En plus de ce que fait l'API, elle suit les relances et exporte la liste au format CSV, et propose quatre outils que l'API n'a pas :
- Import crée des factures à partir d'un fichier CSV ou Excel, de 10 Mo au plus.
- Actions groupées envoie, annule ou supprime jusqu'à 100 factures à la fois.
- Dupliquer copie une facture dans une nouvelle, ouverte en modification.
- Avoir émet un avoir sur une facture qui a reçu un paiement, jusqu'au montant payé, avec un
motif. C'est un document : il ne déplace aucun argent. Il diminue le
amount_paidde la facture de son montant, et un paiement ultérieur sur la facture en tient compte : la facture passe àpaidquand ce qui a été payé, moins ses avoirs, couvre le total.
Une facture impayée passe à overdue pendant la nuit une fois sa due_date passée, et les relances
partent d'elles-mêmes vers les clients dont la facture reste ouverte.
Pages associées
- FacturesTous les champs, le calcul des totaux et les huit appels.
- Démarrage rapideÉmettez votre première facture et faites-la payer.
- ClientsAssociez une facture à un client enregistré plutôt qu'à un simple nom.
- WebhooksÉcoutez payment.succeeded et rapprochez la facture.
- Référence API des facturesTous les champs et les huit endpoints.