Payment allocation ( payment_allocation )
A payment_allocation traces how a receipt or disbursement is allocated across one or more financial documents. It is the object linking a psp_payment or a payment and the invoices to the document it settles.
Role
Whenever a payment is reconciled with one or more invoices, a
payment_allocation is created to materialize that allocation. It answers: how much of which payment was applied to which invoice?
The allocation is a two-level object:
L'header (
pal_) identifies the source and its overall allocation status (partialorcomplete).The lignes (
pai_) detail each individual allocation — how much was applied to which target (invoice, credit note, order, etc.).
Creating an allocation has immediate side effects: update of the
settlement_status of the relevant financial documents and update of the
status of the source payment. Invoice lifecycle remains independent.
Identifier and structure
The header uses prefix pal_ ; each line uses prefix
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"
}
]
}Header fields
| Field | Type | Description |
|---|---|---|
id | string | Allocation identifier (prefix `pal_`). |
object | string | Always "payment_allocation". |
merchant_id | string | Owning merchant. |
source_type | enum | Source type: `psp_payment`, `payment`, or `supplier_payment`. |
source_id | string | Source-object identifier (`psp_…`, `pay_…`, `spay_…`). |
source_reference | string | null | Optional source reference used notably for idempotency. |
reverses_allocation_id | string | null | Allocation compensated by this one when this is a reversal. |
reversed_by_allocation_id | string | null | Compensating allocation that reversed this one, if any. |
status | enum | `partial` or `complete`. |
created_at | datetime | Creation date. |
updated_at | datetime | Last update date. |
Lignes d'imputation
Each line (payment_allocation_item) describes allocation of a sub-amount from the source to one specific target document. An allocation may have several lines when the payment covers several invoices.
| Field | Type | Description |
|---|---|---|
id | string | Line identifier (prefix `pai_`). |
object | string | Always "payment_allocation_item". |
payment_allocation_id | string | Allocation parente (pal_…). |
target_type | enum | Target type: `invoice`, `credit_note`, `order`, `unallocated` (AR) or `supplier_invoice`, `supplier_credit_note`, `purchase_order`, `unallocated` (AP). |
target_id | string | Target identifier (`inv_…`, `ord_…`, `cmp_…` when `unallocated`). |
amount | integer | Allocated amount in the currency's minor unit. Positive for invoices, negative for credit notes. |
currency | string | Currency (lowercase ISO 4217). Must match source currency. |
created_at | datetime | Creation date. |
For a line targeting a credit_note, the amount field is negative — the credit note offsets part of the amount to settle rather than directly reducing it. The algebraic sum of the lines gives the net allocated amount.
Lines are available through GET /v1/payment-allocations/:id (returned in the parent object) or through the
GET /v1/payment-allocations?source_id=psp_….
Status
filter. The header status reflects whether the full source amount has been allocated.
| Status | Meaning |
|---|---|
partial | The sum of lines is lower than the source amount — part of the payment remains unallocated. The source payment moves to |
complete | The sum of lines equals the source amount — the payment is fully reconciled. The source payment moves to |
A payment_allocation is immutable after creation. Its status is determined at POST time from the total lines relative to the source amount. To allocate the remainder of a partially_matchedpayment, create a new allocation on the same source payment.
Sources and targets
Source types
| source_type | Constraint | Usage |
|---|---|---|
psp_payment | status = succeeded, buyer_id required | Collected PSP payment — automatic allocation to buyer invoices. |
payment | status ∈ {pending, partially_matched} | Platform payment being reconciled — manual or process-driven allocation. |
supplier_payment | status ∈ {pending, scheduled, executed} | Outbound disbursement — allocation to supplier invoices (AP flow). |
Target types
| target_type | Flux | Description |
|---|---|---|
invoice | AR | Open buyer invoice. The amount reduces the balance due. |
credit_note | AR | Buyer credit note. The negative amount increases the amount to settle. |
order | AR | Advance on an order before invoice issuance. |
unallocated | AR / AP | Unallocated provision — `target_id` is the company identifier. Used for advances with no known target. |
supplier_invoice | AP | Supplier invoice. The amount reduces payable debt. |
supplier_credit_note | AP | Supplier credit note. |
purchase_order | AP | Advance on a purchase order. |
Side effects on targets
Creating an allocation immediately updates statuses of the relevant objects.
| Target / affected object | Effet |
|---|---|
invoice | `settlement_status` → `partially_paid` or `paid` according to total applied. Document `status` remains unchanged. |
credit_note | `credit_note.applied` event emitted. No status change. |
order | `order.advance_received` event emitted. No status change. |
payment (source) | `status` → `matched` or `partially_matched` according to total amount allocated. |
supplier_invoice | `settlement_status` → `scheduled`, `partially_paid`, or `paid` according to disbursement state. Document `status` remains unchanged. |
Creation
A payment_allocation is created through
POST /v1/payment-allocations. The request describes the source and the list of allocation lines.
POST /v1/payment-allocations
{
"source_type": "psp_payment",
"source_id": "psp_7e4b2d9f1c3a8e5f",
"items": [
{
"target_type": "invoice",
"target_id": "inv_4a7b2e9f1c3d8a5e",
"amount": 120000,
"currency": "eur"
}
]
}The platform validates that:
- The source is in an eligible status (see source table).
- All targets belong to the same merchant and use the same currency as the source.
- No target is over-allocated (total applied ≤ document amount).
- The sum of lines does not exceed the source amount.
- AR targets belong to the same buyer as the source when the source carries a
buyer_id.
The read endpoints:
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
In processes
In practice, payment_allocation are not created manually — they are produced by reconciliation nodes.
| Node | Produced source_type | Role |
|---|---|---|
reconcile_payment | payment or psp_payment | Receives a bank or PSP payment and an allocation proposal (output of |
The usual flow for a PSP receipt is:
psp_payment.succeeded → propose_payment_allocation →
reconcile_payment → payment_allocation created → invoices settled.
Correct an allocation
An allocation is an immutable fact: it is neither edited nor deleted. To correct it, reverse it. contre-passe.
POST /v1/payment-allocations/:id/reverse
The call creates a compensating allocation — the exact mirror of the named allocation, aggregated by target, with opposite amounts. No breakdown is chosen. All relevant statuses are recalculated: source payment, invoices, credit notes, refund rollups.
Correcting an amount therefore happens in two steps:
reverse then a new allocation. Reversal frees source capacity, so reallocating is an ordinary operation — there is deliberately no reversal of a reversal.
Refus
- an allocation that has already been reversed;
- a compensating allocation, which itself cannot be reversed;
the mirror created by
POST /v1/payments/:id/reverse: it is imposed by the payment it reverses. A disputed SEPA debit returned to the buyer leaves nothing to allocate.
The call accepts an source_reference : replay after a timeout returns the existing compensation instead of creating a second one.
Identify the reversal. Negative amounts alone are not enough to know which allocation is undone when several target the same document. The relationship is therefore explicit in both directions:
{
"id": "pal_compensation",
"reverses_allocation_id": "pal_origine",
"reversed_by_allocation_id": null
}reverses_allocation_id is populated on the compensation and points to the allocation being undone; reversed_by_allocation_id is populated on the original and points to its compensation. Both are null on an ordinary allocation, so a connector never needs to scan the list to determine whether an allocation was reversed.
Canceled or written-off documents. Reversing an allocation that targeted them lowers their settlement level but does not reopen
never the document: reopening a written_off
document would silently change the receivable based on a decision belonging to the merchant. The platform emits invoice.terminal_settlement_changed and lets a process or operator take the decision.
Events
| Event | Trigger |
|---|---|
payment_allocation.partial | The allocation was created with `status=partial`: source amount is not fully allocated. |
payment_allocation.complete | The allocation was created with `status=complete`: source amount is fully allocated. |
invoice.paid | An invoice was fully settled through this allocation (`settlement_status` → `paid`). |
invoice.partially_paid | An invoice was partially settled (`settlement_status` → `partially_paid`). |
payment.matched | The source payment (`pay_`) was fully reconciled (`status` → `matched`). |
Events payment_allocation.partial and
payment_allocation.complete are mutually exclusive — only one is emitted per creation. Events on target documents (invoice.paid,
invoice.partially_paid, payment.matched…) are emitted in the same transaction.