Aller au contenu

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.

Votre serveur crée la facture, Wajub héberge la page sur laquelle elle est payée, puis le cycle recommence. Transmettre l'adresse au client reste de votre ressort.

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.

BesoinSolution
Facturer une fois un client et être payé en ligneFactures
Facturer le même client à intervalle fixeUne facture récurrente : un nouveau brouillon à chaque cycle, qui reste à envoyer et à payer
Débiter automatiquement un portefeuille enregistré selon un calendrierAucune pour le moment, consultez Abonnements
Accepter un paiement lancé par votre propre checkoutPaiements, pas la facturation

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.

POSThttps://api.wajub.com/invoices
customer_namestringobligatoire
Le destinataire de la facture. Un nom suffit, aucun enregistrement client n'est obligatoire.
itemsarrayobligatoire
Au moins une ligne. Chacune contient name, quantity et unit_price.
invoice_datestring (date)obligatoire
La date imprimée sur le document. Elle est obligatoire et ne possède aucune valeur par défaut.
currencystringobligatoire
Code ISO 4217 d'une devise que Wajub prend en charge ; toute autre renvoie 422. Tous les montants de la facture utilisent cette devise.
languageenumfacultatif
fr 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_idstringfacultatif
Associe la facture à l'un de vos [clients](/payments/customers), par son identifiant cus_. Ses coordonnées sont copiées dans le document lors de la création.
customer_emailstringfacultatif
Adresse à laquelle /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)facultatif
Date égale ou postérieure à invoice_date. La facture passe à overdue une fois cette date passée.
payment_terms_daysintegerfacultatif
Définit due_date à ce nombre de jours après aujourd'hui, uniquement en l'absence de due_date.
items[].tax_ratenumberfacultatif
Pourcentage appliqué à cette ligne, de 0 à 100. Il est calculé par ligne, pas par facture.
items[].discount_typeenumfacultatif
percentage ou fixed, associé à items[].discount_value.
items[].discount_valuenumberfacultatif
Montant déduit de cette ligne. Les remises s'appliquent par ligne. L'API n'en définit aucune au niveau de la facture.
document_typeenumfacultatifdéfaut : invoice
invoice, quote ou estimate. L'API liste et récupère uniquement les factures.
is_recurringbooleanfacultatif
Marque le document comme récurrent. Lisez la section sur les factures récurrentes avant de vous y fier.
notesstringfacultatif
Texte libre sous les lignes, limité à 5 000 caractères. terms 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.

Réponse · 201 Created
{
"code": 201,
"status": "Created",
"message": "Invoice created",
"invoice": {
"id": "inv_LRQqYvlhrgUOE225KMKU",
"invoice_number": null,
"document_type": "invoice",
"status": "draft",
"customer_name": "Amina Traoré",
"customer_email": "[email protected]",
"invoice_date": "2026-09-11",
"due_date": "2026-09-25",
"currency": "XAF",
"subtotal": 450000,
"discount_amount": 0,
"tax_amount": 0,
"total": 450000,
"amount_paid": 0,
"amount_due": 450000,
"is_recurring": false,
"sent_at": null,
"paid_at": null,
"created_at": "2026-09-11T14:00:00+00:00"
}
}

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

POSThttps://api.wajub.com/invoices/{id}/send

Sur 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.

URL du client
https://invoice.wajub.com/inv_LRQqYvlhrgUOE225KMKU

Cette 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.

POSThttps://api.wajub.com/invoices/{id}/mark-paid

Omettez 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énementDéclencheur
invoice.createdUne facture est créée avec draft : une seule fois, avec ses lignes et ses totaux
invoice.updatedUn 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_succeededUn paiement effectué sur la page de la facture réussit, chaque échéance comprise
invoice.paidLa facture est réglée en totalité, en ligne ou avec mark-paid
invoice.deletedUne 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.

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_paid de la facture de son montant, et un paiement ultérieur sur la facture en tient compte : la facture passe à paid quand 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.

Que pensez-vous de ce contenu ?