Paiement PSP (psp_payment)
Un psp_payment est l'enregistrement côté Ormuz d'un paiement ayant transité par un prestataire de services de paiement (PSP). Il porte le montant attendu, le montant effectivement encaissé, la méthode de paiement et le statut d'encaissement — et sert de pont entre l'événement provider et les objets financiers de la plateforme.
Rôle
Chaque paiement entrant traité via un PSP — qu'il provienne d'un webhook Stripe, d'un virement bancaire détecté par open banking ou d'un enregistrement manuel — est représenté sous la forme d'un psp_payment. Il documente l'encaissement brut : combien a été reçu, via quelle méthode, et à quelle commande ou créance il se rapporte.
Le psp_payment alimente ensuite le rapprochement : une fois appliqué via reconcile_payment, il met à jour le settlement_status des factures concernées et déclenche le recalcul du receivable de l'acheteur.
Identifiant et structure
Chaque PSP payment porte un identifiant stable préfixé par 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"
}Champs
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant du PSP payment (préfixe psp_). |
object | string | Toujours "psp_payment". |
merchant_id | string | Marchand propriétaire. |
buyer_id | string | null | Entreprise acheteuse (cmp_…). Peut être déduit de l'order ou de l'invoice si non fourni explicitement. |
checkout_session_id | string | null | Session de paiement associée (cs_…). Optionnel. |
type | enum | Nature de l’intention : payment ou refund. |
source_psp_payment_id | string | null | Paiement PSP parent lorsqu’il s’agit d’un remboursement. |
amount_refunded | integer | Montant des remboursements PSP enfants réussis sur un paiement. |
amount_refundable | integer | Capacité encore remboursable après remboursements réussis et intentions actives. |
reason | string | null | Motif métier d’une intention de remboursement. |
order_id | string | null | Commande associée (ord_…). Requis si basis = "order". |
invoice_id | string | null | Facture associée (inv_…). Requis si basis = "invoice". |
payment_id | string | null | Paiement plateforme lié (pay_…). Optionnel — établit le pont vers le paiement rapproché. |
basis | enum | null | Base de rattachement : order, invoice, receivable, ou null. |
basis_snapshot_at | datetime | null | Horodatage du snapshot de receivable (requis si basis = "receivable"). |
basis_snapshot_amount | integer | null | Montant du receivable au moment du snapshot (requis si basis = "receivable"). |
source_reference | string | null | Référence provider écrite après création de l’intention, par exemple un PaymentIntent Stripe. Elle est unique par marchand et ne sert plus de clé à la création du draft. |
metadata | object | Map plate de scalaires `string | number | boolean`, selon la convention metadata de l’API. |
amount | integer | Montant total attendu en centimes (> 0). |
amount_received | integer | Montant effectivement encaissé en centimes (≥ 0). Ne peut pas dépasser amount. |
currency | string | Code devise ISO 4217 en minuscules (ex. eur). |
payment_method | string | Méthode de paiement utilisée (ex. manual, sepa_debit, bank_transfer, card). |
status | enum | Statut : draft, pending, partially_funded, succeeded, failed, cancelled ou disputed. |
created_at | datetime | Date de création. |
updated_at | datetime | Date de dernière mise à jour. |
Statut
Le status décrit le cycle de vie de l'intention de paiement puis son état d'encaissement. Un PSP payment commence normalement en draft : Ormuz a défini l'intention, mais aucun paiement provider n'est encore établi.pending signifie au contraire que le provider a créé ou accepté cette intention et que l'encaissement reste attendu.
| Statut | Contrainte sur amount_received | Description |
|---|---|---|
draft | amount_received = 0 | Intention Ormuz créée avant que le provider ait établi le paiement. |
pending | amount_received < amount | Le provider a établi le paiement ; l’encaissement reste attendu. |
partially_funded | 0 < amount_received < amount | Montant partiellement encaissé. Fréquent pour les virements bancaires. |
succeeded | amount_received > 0 | Paiement entièrement encaissé. |
failed | — | Tentative de paiement échouée. |
cancelled | — | Paiement annulé avant encaissement. |
disputed | — | Litige ouvert (chargeback ou contestation). |
Le statut peut être fixé à la création (utile quand le signal PSP est déjà traité) ou mis à jour via POST /v1/psp-payments/:id. Une transition vers un statut différent de pending émet l'événement correspondant.
Base de rattachement
Le champ basis qualifie l'intention commerciale du paiement. Il détermine quels champs de liaison sont requis ou interdits, et fournit du contexte pour le rapprochement.
| basis | Requis | Exclu | Description |
|---|---|---|---|
order | order_id | invoice_id | Le paiement est rattaché à une commande spécifique. |
invoice | invoice_id | order_id | Le paiement est rattaché à une facture spécifique. |
receivable | basis_snapshot_at, basis_snapshot_amount | order_id, invoice_id | Le paiement couvre tout ou partie de la créance ouverte de l'acheteur. Le snapshot capture le receivable au moment de l'initiation. |
null | — | — | Aucune base déclarée — usage libre. |
buyer_id est fourni en même temps qu'un order_id ou invoice_id, il doit correspondre au buyer_id de l'order ou de la facture. La devise doit également correspondre. Si buyer_id est absent, il est déduit automatiquement de l'order ou de la facture.Idempotence de l’intention et référence provider
Un nouveau psp_payment est d’abord créé comme intention Ormuz au statut draft, sans référence provider. Si une reprise tente de recréer le même draft avant toute exécution externe, Ormuz réutilise l’intention existante lorsque son type, son montant, sa devise et sa clé métier de rattachement sont identiques.
source_reference est renseigné ensuite, lorsque le provider a réellement créé ou identifié son objet. Cette référence est unique par marchand et écrite une seule fois ; elle permet ensuite de corréler les mises à jour et événements provider au même PSP payment. Elle ne remplace pas la déduplication du draft avant l’appel externe.
Liaison payment
Un psp_payment peut être lié à un objet payment plateforme via payment_id. Ce lien établit le pont entre l'encaissement brut côté PSP et le paiement rapproché côté Ormuz.
Contraintes du lien :
- Le paiement doit appartenir au même marchand et avoir la même devise.
- Un PSP payment ne peut être rattaché qu'à un seul payment (réassignation bloquée une fois lié).
- Le montant du PSP payment ne doit pas dépasser la capacité du payment cible.
- Mettre
payment_idànulldélie le PSP payment.
Remboursements PSP
Un remboursement PSP est lui aussi une intention persistée avant l’appel provider. Le noderefund_psp_payment crée un psp_payment de type refund au statutdraft, lié par source_psp_payment_id à un paiement PSP source déjà réussi. L’extension PSP matérialise ensuite ce remboursement et fait converger son statut avec le provider. Le paiement parent reste succeeded : son champ amount_refunded agrège les remboursements enfants réussis, il n’existe pas de statut parent refunded.
Pour des avoirs, create_credit_note_psp_refunds résout les paiements PSP qui ont réellement financé les factures concernées, réserve la capacité encore remboursable et crée les intentions correspondantes. La création peut rester séparée par avoir ou être agrégée par paiement PSP source selon le besoin du processus.
Une intention active réserve sa part du montant remboursable : deux processus concurrents ne peuvent donc pas engager silencieusement le même montant. L’exécution provider reste une étape explicite, distincte de la création de l’intention Ormuz.
Dans les processus
create_psp_payment
Ce helper crée ou réutilise une intention psp_payment draft à partir de la base métier fournie. Il ne demande pas de source_reference provider à la création : cette référence est attachée plus tard par la capacité qui exécute ou synchronise réellement le paiement.
Paramètres principaux
{
"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"
}Sortie
{
"psp_payment": "platform.psp_payment"
}reconcile_payment
Impute un PSP payment ou un payment bancaire sur une ou plusieurs créances Ormuz selon une proposition d'allocation. Met à jour les statuts des documents et le receivable selon la source reçue.
Paramètres
{
"payment": "platform.payment | platform.psp_payment",
"receivable_allocation": "common.receivable_allocation"
}Sortie
{
"payment_allocation": "platform.payment_allocation"
}La receivable_allocation est typiquement produite par le node propose_payment_allocation qui identifie les factures candidates pour un montant et une company donnés.
Nodes Stripe
Plusieurs nodes d'intégration Stripe produisent ou consomment un psp_payment :
| Node | Rôle |
|---|---|
stripe.sync_psp_payment | Synchronise explicitement un PaymentIntent Stripe vers son PSP payment Ormuz. Utile pour forcer un refresh d'état sans attendre le webhook. |
stripe.create_bank_transfer_payment_intent | Crée ou réutilise un PaymentIntent de virement bancaire à partir d’un PSP payment Ormuz draft, puis fait converger son état avec le provider. |
stripe.trigger_sepa_debit | Déclenche un prélèvement SEPA à partir d’un PSP payment Ormuz draft et associe durablement le PaymentIntent Stripe à ce paiement. |
Événements
| Événement | Déclencheur |
|---|---|
psp_payment.created | Le PSP payment vient d'être créé. |
psp_payment.partially_funded | Le statut est passé à partially_funded. |
psp_payment.succeeded | Le statut est passé à succeeded. |
psp_payment.failed | Le statut est passé à failed. |
psp_payment.cancelled | Le statut est passé à cancelled. |
psp_payment.disputed | Le statut est passé à disputed. |
Si le PSP payment est créé directement avec un statut autre que pending (ex. succeeded), les deux événements psp_payment.created et psp_payment.succeeded sont émis à la création. Les transitions de statut ultérieures n'émettent que l'événement du nouveau statut.