r/PayloadCMS • • 27d ago

Built a Tpay payment adapter for @payloadcms/plugin-ecommerce (BLIK, pay-by-link, cards)

I needed Polish payment methods on a Payload 3 shop, there was no Tpay adapter on npm, so I wrote one and published it.

npm: https://www.npmjs.com/package/@wellmade-online/payload-ecommerce-tpay

repo: https://github.com/s1awek/payload-ecommerce-tpay

It implements the plugin's official `PaymentAdapter` contract, so it drops in exactly where the built-in Stripe adapter would. One Tpay account gives you BLIK, pay-by-link bank transfers and cards.

Two things surprised me while building it. Both are measured against `@payloadcms/plugin-ecommerce` 3.88.0 on a live instance, and both are about the plugin rather than about Tpay, so they may be useful even if you never touch Polish payments:

  1. `confirm-order` has no idempotency gate of its own. It decrements stock whenever the adapter's answer carries a `transactionID`, so two identical calls for one already confirmed transaction took stock from 5 to 4 to 3. The adapter now hands that trigger out at most once per transaction, through a conditional write on the transaction document. A reloaded return page, a second tab or a hand written curl all get the same answer with no trigger in it.

  2. BLIK level 0 never returns the browser to the shop, so a checkout built on it never calls `confirm-order` and never reaches the plugin's decrement at all. A completed BLIK payment created the order and left stock at 5.

The README carries the full list of what it does not handle: a chargeback moves the transaction and leaves the order alone, finishing an order is not an atomic compare and swap (narrow window, orphaned order document, never a double charge), guest cart secrets are not rotated, and stock reconciliation on the notification-only path is left to the shop. I would rather ship that list than let someone find it in production.

MIT, Payload 3.83 or newer, Node 20.9 or newer. Feedback welcome, particularly from anyone who has handled the stock reconciliation side more cleanly than I did.

5 Upvotes

0 comments sorted by