Принимайте кредитные карты, цифровые платежи и купи сейчас, плати потом
Get access to 50+ payment options for online and in-store payments.
Don’t have an account with Pay. yet? Register now!
[!CAUTION] If you have subscribers listening to the event, update them to listen to the event instead. See below.
[!WARNING] This plugin creates orders in Medusa immediately, even if the payment has not yet been captured. If a payment expires, the associated order will be automatically canceled.
This change in flow is required to support asynchronous payment methods (e.g., SprayPay), where payment confirmation can take hours depending on customer input.
Visit the demo store here: https://pay-demo.webbers.com
Payment Method | Region(s) |
|---|---|
| iDEAL | 🇳🇱 Netherlands |
| Bancontact | 🇧🇪 Belgium |
| Vipps | 🇳🇴 Norway 🇸🇪 Sweden |
| Bizum | 🇪🇸 Spain |
| Payconiq | 🇧🇪 Belgium 🇱🇺 Luxembourg |
| Twint | 🇨🇭 Switzerland |
| MB Way | 🇵🇹 Portugal |
| Pay By Bank | 🇧🇪 Belgium 🇩🇪 Germany 🇮🇹 Italy 🇱🇺 Luxembourg 🇳🇱 Netherlands 🇪🇸 Spain |
| WeChat Pay | 🇨🇳 China |
Payment Method | Region(s) |
|---|---|
| Alipay Plus | 🇨🇳 China 🇭🇰 Hong Kong |
| MultiBanco | 🇵🇹 Portugal |
| Swish | 🇸🇪 Sweden |
| Satispay | 🇮🇹 Italy |
| Blik | 🇵🇱 Poland |
| EPS | 🇦🇹 Austria |
| Przelewy24 | 🇵🇱 Poland |
| MobilePay | 🇩🇰 Denmark 🇫🇮 Finland |
Would you like to integrate Pay. (Soft)P0S? Get in touch!
Add the provider to the module in your file & add it as plugin:
[!NOTE] You can get the API token & secret from your Pay dashboard: click Settings > Click sales channel > Copy api tokens
| Option | Description | Default |
|---|---|---|
| Your Pay AT code | Required | |
| Your Pay API token | Required | |
| Your Pay sales channel code | Required | |
| Your Pay sales channel secret | Required | |
| The URL to return to after payment | Required | |
| The URL of your Medusa server | Required | |
| Whether to enable test payments | Optional | |
| Pay TGU API Url | Optional, use if you want to use a specific or private TGU, see here. | |
| Your other Pay sales channel code and secrets | Optional, used for webhook signature validation when using multiple Pay. sales channels. Format |
Create or update your file with the following variables:
Once installed and configured, the Pay payment methods will be available in your Medusa admin. To enable them, log in to you Medusa Admin, browse to Settings > Regions, add or edit a region and select the desired Pay providers from the dropdown.
Make sure that the selected payment methods are enabled in your Pay origanization settings as well.
Pay.'s test environment does not process SEPA direct debits. With enabled the plugin therefore does not create a mandate at Pay. when a direct debit order is placed. It stores a simulated mandate on the payment session instead (code , logged as ), and the collection flow can be driven by posting the exchanges Pay. would normally send to the webhook route yourself. Exchanges for a simulated mandate are not re-fetched from Pay., the body is taken as the direct debit state. This only happens while is on and only for mandates that were created in test mode.
Other legacy actions (, ) and an explicit (failed) or work the same way. Add to the body when the order can not be resolved from the mandate code. The webhook route processes exchanges asynchronously (5 seconds by default), so give the server a moment before checking the order. The payment link opens the regular Pay. hosted checkout, so the outstanding amount can be paid with any test payment method.
When a chargeback or storno reverses a captured payment, the plugin refunds the payment in Medusa (without contacting Pay.), books the amount as outstanding again and opens a new payment collection, so the order offers "Copy payment link" and "Mark as paid". Medusa's own payment status can only call that "Refunded", so the plugin adds a "Payment reversed, action required" banner on top of the order page that names the cause (chargeback, storno, failed collection), the amount that went back to the customer and what is still outstanding.
The same exchanges can be triggered from the order detail page. Switch on SEPA testing in Settings > Pay (off by default, meant for staging servers) and a "Pay. direct debit simulator" panel appears in the sidebar of orders that hold a simulated mandate, with a button per exchange (pending, sent, collected, storno, failed, declined). The exchanges are processed synchronously, so the order refreshes right away. The switch is stored in the store's metadata (), so it applies to every admin user of that server. The panel is backed by and (), which only work while the switch and are on; the switch itself is read and written through / ().
The plugin currently supports the following Pay payment methods:
Payment Method | Provider ID |
|---|---|
| Pay. hosted checkout | |
| Creditcards Mastercard / VISA / American Express/ Carte Bancaire / Maestro / PostePay / DanKort / Nexi / Visa Mastercard | |
| Card-on-file / recurring card payments (tokenisation) | Coming soon |
| Apple Pay | |
| Google Pay | |
| iDEAL IN3 | |
| Billink | |
| SprayPay | |
| Riverty | |
| Mondu | |
| AlmaPAY | |
| Klarna | |
| PayPal | |
| SEPA Direct Debit | |
| iDEAL | |
| Bancontact | |
| Vipps | Get in touch |
| Bizum | Get in touch |
| Payconiq | |
| Twint | |
| MB Way | Get in touch |
| Pay by Bank | |
| WeChat Pay | |
| AliPay Plus | Get in touch |
| MultiBanco | Get in touch |
| Swish | Get in touch |
| Satispay | Get in touch |
| Blik | |
| EPS | |
| Przelewy24 | |
| MobilePAY | |
| SoftPOS | |
| Gift Card |
To integrate with your storefront, you'll need to implement the payment flow according to Pay's and Medusa's documentation. Here's a basic example:
Example integration using the Medusa Next.js Starter:
https://github.com/user-attachments/assets/742ee261-5e41-4e33-9a72-faf1a424fc52
[!TIP] Use the duplicate cart endpoint in your storefront
When a customer cancels a payment or returns to the storefront without completing the Pay. checkout, a new duplicate cart should automatically be created. This allows the customer to easily start a new transaction without losing the items they had selected.
API Route:
Alter your storefront retrieve cart function(s) and check if the returned cart.completed_at value is set. If so request a new cart with the duplicate cart endpoint and update cart id in cookies accordingly.
The duplicate cart endpoint is idempotent, so it can be called multiple times with the same cart id.
To add one of the missing Pay payment methods, create a new service in that extends the class:
Make sure to replace with the actual Pay payment method ID.
Export your new service from . Then add your new service to the list of services in .
We will be working on providing all the available Pay. options in the near future.
Searching for support for Medusa v1, we have a legacy plugin available. Get in touch
pnpm add @webbers/pay-payments-medusa1module.exports = defineConfig({2 projectConfig: {3 // ...4 },5 plugins: [6 // ... other plugins7 '@webbers/pay-payments-medusa'8 ],9 modules: [10 // ... other modules11 {12 resolve: "@medusajs/medusa/payment",13 options: {14 providers: [15 {16 resolve: "@webbers/pay-payments-medusa/providers/pay",17 id: "pay",18 options: {19 paymentDescription: "Your description", // optional20 atCode: process.env.PAY_AT_CODE,21 apiToken: process.env.PAY_API_TOKEN,22 slCode: process.env.PAY_SL_CODE,23 slSecret: process.env.PAY_SL_SECRET,24 returnUrl: process.env.PAY_RETURN_URL,25 testMode: process.env.PAY_TEST_MODE === 'true',26 tguApiUrl: process.env.PAY_TGU_API_URL, // defaults to https://connect.pay.nl/v127 otherSlCodes: process.env.PAY_OTHER_SL_CODE ? JSON.parse(process.env.PAY_OTHER_SL_CODE) : undefined,28 },29 },30 ]31 }32 }33 ]34})1PAY_AT_CODE="<your-pay-at-code>"2PAY_API_TOKEN="<your-pay-api-token>"3PAY_SL_CODE="<your-pay-sl-code>"4PAY_SL_SECRET="<your-pay-sl-secret>"5#PAY_TEST_MODE="true"6PAY_EXCHANGE_URL="https://your-store.com/checkout/payment"1# 1. Place an order with SEPA Direct Debit, the payment collection is now "awaiting".2# Copy the simulated mandate code from the server log.3MANDATE="TEST-payses_01JXXXXXXXXXXXXXXXXXXXXXXX"4
5# 2. The bank collected the money: the payment is captured and the order is paid.6curl -X POST http://localhost:9000/hooks/pay/pay-direct-debit_pay \7 -H "Content-Type: application/json" \8 -d "{\"action\":\"incassocollected\",\"mandateId\":\"$MANDATE\"}"9
10# 3. The customer reversed the debit (storno): the payment is refunded in Medusa only, the order11# shows the outstanding amount again and the admin offers "Copy payment link" / "Mark as paid".12curl -X POST http://localhost:9000/hooks/pay/pay-direct-debit_pay \13 -H "Content-Type: application/json" \14 -d "{\"action\":\"incassostorno\",\"mandateId\":\"$MANDATE\"}"1import {PaymentMethod} from "@Pay/api-client";2import PayBase from "../core/Pay-base";3import {PaymentOptions, PaymentProviderKeys} from "../types";4
5class PayNewMethodService extends PayBase {6 static identifier = "Pay-new-method";7
8 get paymentCreateOptions(): PaymentOptions {9 return {10 method: PaymentMethod.newMethod,11 };12 }13}14
15export default PayNewMethodService;