Allocation de paiement (payment_allocation)
Une payment_allocation trace l'imputation d'un encaissement (ou d'un décaissement) sur un ou plusieurs documents financiers. Elle est l'objet qui fait le lien entre un psp_payment ou un payment et les factures qu'il solde.
Rôle
Chaque fois qu'un paiement est rapproché d'une ou plusieurs factures, unepayment_allocation est créée pour matérialiser cette imputation. Elle répond à la question : quel montant de quel paiement a été appliqué sur quelle facture ?
L'allocation est un objet à deux niveaux :
- L'en-tête (
pal_) identifie la source et son statut global d'imputation (partialoucomplete). - Les lignes (
pai_) détaillent chaque imputation unitaire — quel montant a été appliqué sur quelle cible (facture, avoir, commande, etc.).
La création d'une allocation produit des effets de bord immédiats : mise à jour dusettlement_status des documents financiers concernés et mise à jour du status du paiement source. Le cycle de vie des factures reste indépendant.
Identifiant et structure
L'en-tête porte le préfixe pal_ ; chaque ligne porte le préfixe pai_.
{
"object": "payment_allocation",
"id": "pal_3c8f1a9b2d4e7f6a",
"merchant_id": "mer_1a2b3c4d5e6f7a8b",
"source_type": "psp_payment",
"source_id": "psp_7e4b2d9f1c3a8e5f",
"source_reference": null,
"reverses_allocation_id": null,
"reversed_by_allocation_id": null,
"status": "complete",
"created_at": "2026-06-17T14:30:00.000Z",
"updated_at": "2026-06-17T14:30:00.000Z",
"items": [
{
"object": "payment_allocation_item",
"id": "pai_1a3f2b9c4d8e5f7a",
"payment_allocation_id": "pal_3c8f1a9b2d4e7f6a",
"target_type": "invoice",
"target_id": "inv_4a7b2e9f1c3d8a5e",
"amount": 120000,
"currency": "eur",
"created_at": "2026-06-17T14:30:00.000Z"
}
]
}Champs de l'en-tête
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant de l'allocation (préfixe pal_). |
object | string | Toujours "payment_allocation". |
merchant_id | string | Marchand propriétaire. |
source_type | enum | Type de la source : psp_payment, payment, ou supplier_payment. |
source_id | string | Identifiant de l'objet source (psp_…, pay_…, spay_…). |
source_reference | string | null | Référence source optionnelle utilisée notamment pour l’idempotence. |
reverses_allocation_id | string | null | Allocation compensée par celle-ci lorsqu’il s’agit d’une inversion. |
reversed_by_allocation_id | string | null | Allocation de compensation qui a inversé celle-ci, si elle existe. |
status | enum | partial ou complete. |
created_at | datetime | Date de création. |
updated_at | datetime | Date de dernière mise à jour. |
Lignes d'imputation
Chaque ligne (payment_allocation_item) décrit l'imputation d'un sous-montant de la source sur un document cible spécifique. Une allocation peut avoir plusieurs lignes si le paiement couvre plusieurs factures.
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant de la ligne (préfixe pai_). |
object | string | Toujours "payment_allocation_item". |
payment_allocation_id | string | Allocation parente (pal_…). |
target_type | enum | Type de la cible : invoice, credit_note, order, unallocated (AR) ou supplier_invoice, supplier_credit_note, purchase_order, unallocated (AP). |
target_id | string | Identifiant de la cible (inv_…, ord_…, cmp_ si unallocated…). |
amount | integer | Montant imputé dans l’unité mineure de la devise. Positif pour les factures, négatif pour les avoirs. |
currency | string | Devise (ISO 4217 minuscules). Doit correspondre à la devise source. |
created_at | datetime | Date de création. |
credit_note, le champ amount est négatif — l'avoir compense une partie du solde à régler plutôt que de le réduire directement. La somme algébrique des lignes donne le montant net imputé.Les lignes sont accessibles via GET /v1/payment-allocations/:id (retourné dans l'objet parent) ou via le filtre GET /v1/payment-allocations?source_id=psp_….
Statut
Le statut de l'en-tête reflète si la totalité du montant source a été imputée.
| Statut | Signification |
|---|---|
partial | La somme des lignes est inférieure au montant source — une partie du paiement reste non imputée. Le paiement source passe à partially_matched. |
complete | La somme des lignes est égale au montant source — le paiement est entièrement rapproché. Le paiement source passe à matched. |
payment_allocation est immuable après création. Son statut est déterminé au moment du POST selon le total des lignes par rapport au montant source. Pour imputer le reliquat d'un paiement partially_matched, créez une nouvelle allocation sur le même paiement source.Sources et cibles
Types de source
| source_type | Contrainte | Usage |
|---|---|---|
psp_payment | status = succeeded, buyer_id requis | Paiement PSP encaissé — imputation automatique sur les factures de l'acheteur. |
payment | status ∈ {pending, partially_matched} | Paiement plateforme en cours de rapprochement — imputation manuelle ou via processus. |
supplier_payment | status ∈ {pending, scheduled, executed} | Décaissement sortant — imputation sur des factures fournisseur (flux AP). |
Types de cible
| target_type | Flux | Description |
|---|---|---|
invoice | AR | Facture acheteur ouverte. Le montant réduit le solde dû. |
credit_note | AR | Avoir acheteur. Le montant (négatif) augmente le solde à régler. |
order | AR | Avance sur commande, avant émission de facture. |
unallocated | AR / AP | Provision non allouée — target_id est l'identifiant de la company. Utilisée pour les avances sans cible connue. |
supplier_invoice | AP | Facture fournisseur. Le montant réduit la dette à payer. |
supplier_credit_note | AP | Avoir fournisseur. |
purchase_order | AP | Avance sur bon de commande. |
Effets de bord sur les cibles
La création d'une allocation met à jour immédiatement les statuts des objets concernés.
| Cible / objet impacté | Effet |
|---|---|
invoice | settlement_status → partially_paid ou paid selon le total appliqué. Le status du document reste inchangé. |
credit_note | Événement credit_note.applied émis. Pas de changement de statut. |
order | Événement order.advance_received émis. Pas de changement de statut. |
payment (source) | status → matched ou partially_matched selon le montant total imputé. |
supplier_invoice | settlement_status → scheduled, partially_paid ou paid selon l’état du décaissement. Le status du document reste inchangé. |
Création
Une payment_allocation se crée via POST /v1/payment-allocations. La requête décrit la source et la liste des lignes d'imputation.
POST /v1/payment-allocations
{
"source_type": "psp_payment",
"source_id": "psp_7e4b2d9f1c3a8e5f",
"items": [
{
"target_type": "invoice",
"target_id": "inv_4a7b2e9f1c3d8a5e",
"amount": 120000,
"currency": "eur"
}
]
}La plateforme valide que :
- La source est dans un statut éligible (voir tableau des sources).
- Toutes les cibles appartiennent au même marchand et ont la même devise que la source.
- Aucune cible n'est sur-imputée (total appliqué ≤ montant du document).
- La somme des lignes ne dépasse pas le montant source.
- Les cibles AR appartiennent au même acheteur que la source lorsque la source porte un
buyer_id.
Les endpoints de lecture :
GET /v1/payment-allocations/:id GET /v1/payment-allocations?source_type=psp_payment&source_id=psp_7e4b GET /v1/payment-allocations?target_type=invoice&target_id=inv_4a7b
Dans les processus
En pratique, les payment_allocation ne sont pas créées manuellement — elles sont produites par les nodes de rapprochement.
| Node | source_type produit | Rôle |
|---|---|---|
reconcile_payment | payment ou psp_payment | Reçoit un paiement bancaire ou PSP et une proposition d'allocation (sortie de propose_payment_allocation), puis crée lapayment_allocation avec le type de source correspondant. |
Le flux habituel pour un encaissement PSP est :psp_payment.succeeded → propose_payment_allocation → reconcile_payment → payment_allocation créée → factures soldées.
Corriger une imputation
Une imputation est un fait immuable : elle ne se modifie pas et ne se supprime pas. Pour la corriger, on la contre-passe.
POST /v1/payment-allocations/:id/reverse
L'appel crée une allocation compensatoire — le miroir exact de l'allocation nommée, agrégé par cible, montants opposés. Aucune ventilation n'est choisie. Tous les statuts concernés se recalculent : paiement source, factures, avoirs, rollups de remboursement.
Corriger un montant se fait donc en deux temps : reverse puis une nouvelle allocation. Contre-passer libère la capacité de la source, si bien que réimputer est une opération ordinaire — il n'existe volontairement pas d'annulation d'annulation.
Refus
- une allocation déjà contre-passée ;
- une allocation compensatoire, qui ne peut pas l'être à son tour ;
- le miroir créé par
POST /v1/payments/:id/reverse: il est imposé par le paiement qu'il contre-passe. Un prélèvement SEPA contesté et retourné à l'acheteur ne laisse rien à lettrer.
L'appel accepte un source_reference : un rejeu après timeout retourne la compensation existante au lieu d'en créer une seconde.
Identifier la contre-passation. Les montants négatifs ne suffisent pas à savoir quelle imputation est défaite lorsque plusieurs visent le même document. La relation est donc explicite, dans les deux sens :
{
"id": "pal_compensation",
"reverses_allocation_id": "pal_origine",
"reversed_by_allocation_id": null
}reverses_allocation_id est renseigné sur la compensation et pointe l'allocation défaite ; reversed_by_allocation_id est renseigné sur l'originale et pointe sa compensation. Les deux sont nuls sur une allocation ordinaire, et un connecteur n'a donc jamais à parcourir la liste pour savoir si une imputation a été défaite.
Documents annulés ou passés en perte. Contre-passer une imputation qui les visait fait redescendre leur règlement mais ne rouvre jamais le document : rouvrir un written_offmodifierait la créance en silence, sur une décision qui appartient au marchand. La plateforme émet invoice.terminal_settlement_changed et laisse un processus ou un opérateur reprendre la décision.
Événements
| Événement | Déclencheur |
|---|---|
payment_allocation.partial | L'allocation a été créée avec status=partial : le montant source n'est pas entièrement imputé. |
payment_allocation.complete | L'allocation a été créée avec status=complete : le montant source est entièrement imputé. |
invoice.paid | Une facture a été entièrement réglée via cette allocation (settlement_status → paid). |
invoice.partially_paid | Une facture est partiellement réglée (settlement_status → partially_paid). |
payment.matched | Le paiement source (pay_) a été entièrement rapproché (status → matched). |
Les événements payment_allocation.partial et payment_allocation.complete sont mutuellement exclusifs — un seul est émis par création. Les événements sur les documents cibles (invoice.paid, invoice.partially_paid, payment.matched…) sont émis dans la même transaction.