PSP payment ( psp_payment )
A psp_payment is Ormuz's record of a payment that went through a payment service provider (PSP). It carries the expected amount, amount actually received, payment method, and collection status — and acts as the bridge between the provider event and platform financial objects.
Role
Every incoming payment handled through a PSP — whether from a Stripe webhook, a bank transfer detected through open banking, or a manual record — is represented as a psp_payment. It documents raw collection: how much was received, by which method, and which order or receivable it relates to.
The psp_payment then feeds reconciliation: once applied through reconcile_payment, it updates the
settlement_status of the relevant invoices and triggers recalculation of the buyer's
receivable for the buyer.
Identifier and structure
Every PSP payment has a stable identifier prefixed with psp_.
{
"object": "psp_payment",
"id": "psp_7e3b9f2a1c4d8e5f",
"merchant_id": "mer_1a2b3c4d5e6f7a8b",
"buyer_id": "cmp_3a8f1d9c2b4e7f6a",
"checkout_session_id": null,
"order_id": null,
"invoice_id": "inv_4a7b2e9f1c3d8a5e",
"payment_id": null,
"basis": "invoice",
"basis_snapshot_at": null,
"basis_snapshot_amount": null,
"source_reference": "pi_3Nx8kLInvalidExample",
"metadata": {},
"amount": 120000,
"amount_received": 120000,
"currency": "eur",
"payment_method": "sepa_debit",
"status": "succeeded",
"created_at": "2026-06-17T12:00:00.000Z",
"updated_at": "2026-06-17T12:05:00.000Z"
}Fields
| Field | Type | Description |
|---|---|---|
id | string | PSP payment identifier (prefix `psp_`). |
object | string | Always "psp_payment". |
merchant_id | string | Owning merchant. |
buyer_id | string | null | Buyer company (`cmp_…`). May be derived from the order or invoice when not supplied explicitly. |
checkout_session_id | string | null | Associated payment session (`cs_…`). Optional. |
type | enum | Intent nature: `payment` or `refund`. |
source_psp_payment_id | string | null | Parent PSP payment when this is a refund. |
amount_refunded | integer | Amount of successful child PSP refunds on a payment. |
amount_refundable | integer | Remaining refundable capacity after successful refunds and active intents. |
reason | string | null | Business reason for a refund intent. |
order_id | string | null | Associated order (`ord_…`). Required when `basis = order`. |
invoice_id | string | null | Associated invoice (`inv_…`). Required when `basis = invoice`. |
payment_id | string | null | Linked platform payment (`pay_…`). Optional — establishes the bridge to the reconciled payment. |
basis | enum | null | Attachment basis: `order`, `invoice`, `receivable`, or null. |
basis_snapshot_at | datetime | null | Receivable snapshot timestamp (required when `basis = receivable`). |
basis_snapshot_amount | integer | null | Receivable amount at snapshot time (required when `basis = receivable`). |
source_reference | string | null | Provider reference written after intent creation, for example a Stripe PaymentIntent. It is unique per merchant and is no longer used as the key when creating the draft. |
metadata | object | Flat map of `string | number | boolean` scalars, following the API metadata convention. |
amount | integer | Total expected amount in cents (> 0). |
amount_received | integer | Amount actually received in cents (≥ 0). Cannot exceed `amount`. |
currency | string | ISO 4217 currency code in lowercase (for example `eur`). |
payment_method | string | Payment method used (for example `manual`, `sepa_debit`, `bank_transfer`, `card`). |
status | enum | Status: `draft`, `pending`, `partially_funded`, `succeeded`, `failed`, `cancelled`, or `disputed`. |
created_at | datetime | Creation date. |
updated_at | datetime | Last update date. |
Status
The status describes the lifecycle of the payment intent and then its collection state. A PSP payment normally starts in draft : Ormuz has defined the intent, but no provider payment has yet been established.
pending instead means that the provider created or accepted the intent and collection is still awaited.
| Status | Constraint on amount_received | Description |
|---|---|---|
draft | amount_received = 0 | Ormuz intent created before the provider established the payment. |
pending | amount_received < amount | The provider established the payment; collection is still awaited. |
partially_funded | 0 < amount_received < amount | Amount partially received. Common for bank transfers. |
succeeded | amount_received > 0 | Payment fully received. |
failed | — | Failed payment attempt. |
cancelled | — | Payment canceled before receipt. |
disputed | — | Open dispute (chargeback or contestation). |
Status may be set at creation — useful when the PSP signal has already been processed — or updated through POST /v1/psp-payments/:id. A transition to a status other than pending emits the corresponding event.
Attachment basis
The field basis qualifies the commercial intent of the payment. It determines which linking fields are required or forbidden and provides reconciliation context.
| basis | Required | Exclu | Description |
|---|---|---|---|
order | order_id | invoice_id | The payment is attached to a specific order. |
invoice | invoice_id | order_id | The payment is attached to a specific invoice. |
receivable | basis_snapshot_at, basis_snapshot_amount | order_id, invoice_id | The payment covers all or part of the buyer's open receivable. The snapshot captures the receivable at initiation time. |
null | — | — | No declared basis — free-form use. |
If buyer_id is supplied together with an order_id
or invoice_id, it must match the buyer_id of the order or invoice. Currency must also match. When
buyer_id is absent, it is automatically derived from the order or invoice.
Intent idempotency and provider reference
A nouveau psp_payment is first created as an Ormuz intent in status draft, without a provider reference. If a retry attempts to recreate the same draft before any external execution, Ormuz reuses the existing intent when its type, amount, currency, and business attachment key are identical.
source_reference is populated later, when the provider has actually created or identified its object. This reference is unique per merchant and written once; it then correlates provider updates and events to the same PSP payment. It does not replace draft deduplication before the external call.
Liaison payment
A psp_payment may be linked to a
payment plateforme via
payment_idobject. This link bridges raw PSP-side collection and the reconciled Ormuz-side payment.
Link constraints:
- The payment must belong to the same merchant and use the same currency.
- A PSP payment may be attached to only one payment; reassignment is blocked once linked.
- The PSP-payment amount must not exceed the capacity of the target payment.
- Setting
payment_idtonullunlinks the PSP payment.
PSP refunds
A PSP refund is also a persisted intent before the provider call. The node
refund_psp_payment creates a psp_payment of type refund with status
draft, linked through source_psp_payment_id to an already-successful source PSP payment. The PSP extension then materializes this refund and converges its status with the provider. The parent payment remains succeeded: its amount_refunded field aggregates successful child refunds; there is no parent status refunded.
For credit notes, create_credit_note_psp_refunds resolves the PSP payments that actually funded the relevant invoices, reserves remaining refundable capacity, and creates the corresponding intents. Creation may remain separate per credit note or be aggregated by source PSP payment according to process needs.
An active intent reserves its share of refundable capacity, so two concurrent processes cannot silently commit the same amount. Provider execution remains an explicit step, distinct from creating the Ormuz intent.
In processes
create_psp_payment
This helper creates or reuses an intent psp_payment draft from the supplied business basis. It does not request a provider source_reference reference at creation: that reference is attached later by the capability that actually executes or synchronizes the payment.
Main parameters
{
"company": "platform.company",
"order": "platform.order",
"invoice": "platform.invoice",
"receivable": "platform.receivable",
"checkout_session": "platform.checkout_session",
"amount": 120000,
"amount_received": 120000,
"currency": "eur",
"payment_method": "sepa_debit",
"status": "succeeded",
"source_reference": "pi_3Nx8kL"
}Output
{
"psp_payment": "platform.psp_payment"
}reconcile_payment
Allocates a PSP payment or bank payment to one or more Ormuz receivables according to an allocation proposal. Updates document statuses and receivable according to the received source.
Parameters
{
"payment": "platform.payment | platform.psp_payment",
"receivable_allocation": "common.receivable_allocation"
}Output
{
"payment_allocation": "platform.payment_allocation"
}The receivable_allocation is typically produced by the node
propose_payment_allocation which identifies candidate invoices for a given amount and company.
Nodes Stripe
Several Stripe integration nodes produce or consume a
psp_payment :
| Node | Role |
|---|---|
stripe.sync_psp_payment | Explicitly synchronizes a Stripe PaymentIntent into its Ormuz PSP payment. Useful for forcing a state refresh without waiting for the webhook. |
stripe.create_bank_transfer_payment_intent | Creates or reuses a bank-transfer PaymentIntent from an Ormuz PSP payment draft, then converges its state with the provider. |
stripe.trigger_sepa_debit | Triggers a SEPA direct debit from an Ormuz PSP payment draft and durably associates the Stripe PaymentIntent with that payment. |
Events
| Event | Trigger |
|---|---|
psp_payment.created | The PSP payment was just created. |
psp_payment.partially_funded | The status changed to `partially_funded`. |
psp_payment.succeeded | The status changed to `succeeded`. |
psp_payment.failed | The status changed to `failed`. |
psp_payment.cancelled | The status changed to `cancelled`. |
psp_payment.disputed | The status changed to `disputed`. |
When the PSP payment is created directly with a status other than
pending (ex. succeeded), both events
psp_payment.created and psp_payment.succeeded are emitted at creation. Later status transitions emit only the event for the new status.