Przelewy24
Support payments via Przelewy24
Przelewy24 Payments for Medusa
A comprehensive payment provider plugin that enables Przelewy24 payments on Medusa V2 projects.
Table of Contents
- Features
- Prerequisites
- Installation
- Configuration
- Configuration Options
- Environment Variables
- Usage
- Client-Side Integration
- Supported Payment Methods
- Payment Flows
- Webhook Configuration
- Extending the Plugin
- Local Development and Customization
- License
Features
- Multiple Payment Methods: Supports a wide range of Przelewy24 payment methods including:
- BLIK (Regular and One-Click)
- Credit/Debit Cards
- Bank Transfers
- White Label Integration
- Modular Architecture: Multiple services in a single module provider for easy management.
- Webhook Support: Full support for Przelewy24 webhooks for real-time payment status updates.
- TypeScript Support: Full TypeScript implementation with proper types.
- Sandbox Mode: Built-in sandbox support for testing.
[!WARNING] > This plugin has not been tested on a live store. Please conduct thorough testing before using it in a production environment. GMI Software is not responsible for any missed or failed payments resulting from the use of this plugin. If you encounter any issues, please report them here.
Prerequisites
- Medusa server v2.4.0 or later
- Node.js v20 or later
- A Przelewy24 merchant account with API credentials.
[!NOTE] > You can get your API credentials from your Przelewy24 merchant panel
Installation
1yarn add p24-medusa-plugin
Configuration
Add the provider to the Copy to clipboard@medusajs/payment module in your Copy to clipboardmedusa-config.ts file:
1234567891011121314151617181920import { Modules } from "@medusajs/framework/utils";module.exports = defineConfig({modules: [{resolve: "@medusajs/medusa/payment",options: {providers: [{resolve:"@gmisoftware/przelewy24-payments-medusa/providers/przelewy24",id: "przelewy24",options: {api_key: process.env.P24_API_KEY,merchant_id: process.env.P24_MERCHANT_ID,pos_id: process.env.P24_POS_ID,crc: process.env.P24_CRC,sandbox: process.env.P24_IS_SANDBOX,frontend_url: process.env.MEDUSA_STORE_URL,backend_url: process.env.MEDUSA_BACKEND_URL,
Configuration Options
Option Description Required Default Copy to clipboardmerchant_id P24 Merchant ID Yes - Copy to clipboardpos_id P24 POS ID Yes - Copy to clipboardapi_key P24 API Key Yes - Copy to clipboardcrc P24 CRC Key for signature verification Yes - Copy to clipboardsandbox Enable sandbox mode (Copy to clipboardtrue/Copy to clipboardfalse or Copy to clipboard"true"/Copy to clipboard"false") No Copy to clipboardfalse Copy to clipboardcard_channel P24 channel for card-only registration No Copy to clipboard4096 Copy to clipboardvisa_mobile_method_id P24 method id for Visa Mobile No Copy to clipboard198 Copy to clipboardfrontend_url Frontend URL for customer redirects No Copy to clipboardhttp://localhost:3000 Copy to clipboardbackend_url Backend URL for webhook notifications No Copy to clipboardhttp://localhost:9000
Environment Variables
Create or update your Copy to clipboard.env file with the following variables:
12345678910# P24 ConfigurationP24_MERCHANT_ID=your_merchant_idP24_POS_ID=your_pos_idP24_API_KEY=your_api_keyP24_CRC=your_crc_key# URL Configuration (use the same names as medusa-config.ts)MEDUSA_STORE_URL=https://your-frontend-domain.comMEDUSA_BACKEND_URL=https://your-backend-domain.com # public HTTPS — P24 webhooks hit this hostP24_IS_SANDBOX=false
Usage
Once installed and configured, the Przelewy24 payment methods will be available in your Medusa admin. To enable them, log in to your Medusa Admin, browse to Settings > Regions, add or edit a region and select the desired P24 providers from the dropdown.
Make sure that the selected payment methods are enabled in your Przelewy24 merchant panel as well.
Client-Side Integration
To integrate with your storefront, you'll need to implement the payment flow according to Przelewy24's and Medusa's documentation. Here's a basic example:
BLIK Payment
BLIK payments use a two-phase flow:
Phase 1: Create Payment Session
12345678910111213141516// Create payment session for BLIKconst paymentSession = await medusa.payment.createPaymentSession({provider_id: "pp_p24-blik_przelewy24",amount: 10000, // 100.00 PLN in groszecurrency_code: "PLN",data: {country: "PL", // Country code (defaults to "PL" if not provided)language: "pl", // Language code (defaults to "pl" if not provided)},context: {email: "customer@example.com",},});// Response includes session_id and token, but no redirect_urlconsole.log(paymentSession.data.session_id); // Use this for BLIK processing
Phase 2: Process BLIK Code
12345678910111213// Store API (publishable key + cart context)const blikResponse = await fetch("/store/payments/blik/charge", {method: "POST",headers: {"Content-Type": "application/json","x-publishable-api-key": publishableKey,},body: JSON.stringify({token: paymentSession.data.token,blikCode: "123456",payment_session_id: paymentSession.id,}),});
Legacy route Copy to clipboardPOST /payments/blik remains as a deprecated wrapper.Card Payment 2.0 (white-label iframe)
Per P24 Card Payment 2.0 docs:
1234567891011121314151617181920// 1) Create payment session — returns tokenization fields (no transaction register yet)const { payment_session } = await medusa.store.cart.createPaymentSession(cartId, {provider_id: "pp_p24-cards_przelewy24",});const { merchant_id, session_id, card_tokenization_sign } =payment_session.data;// 2) Load P24 Card 2.0 SDK and render iframe// https://{sandbox|secure}.przelewy24.pl/js/cardTokenizationIframe.min.js// new Przelewy24CardTokenization(merchant_id, session_id, card_tokenization_sign)// .render("form", "#container", { lang: "pl", ... })// On Pay: .tokenize("temporary") → listen for postMessage success with data.refId// 3) Register with refId, then run P24 whitelabel charge script in the browserconst cardResponse = await fetch("/store/payments/card/charge", {method: "POST",headers: {"Content-Type": "application/json","x-publishable-api-key": publishableKey,
Visa Mobile (redirect with pre-selected method)
1234567891011// 1) Create payment session — returns redirect_url with method 198 pre-selectedconst { payment_session } = await medusa.store.cart.createPaymentSession(cartId, {provider_id: "pp_p24-visa-mobile_przelewy24",});// 2) Redirect customer to P24 Visa Mobile flowwindow.location.href = payment_session.data.redirect_url;// 3) Customer completes payment on P24 hosted page// 4) Return to frontend_url / return_url// 5) Capture happens via P24 webhook to urlStatus (not via a separate confirm API)
Transaction status (poll timeout fallback)
12345678await fetch("/store/payments/transaction/status", {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({session_id: payment_session.data.session_id,provider_id: payment_session.provider_id,}),});
General P24 Payment
12345678910111213141516// Create payment session for general P24const paymentSession = await medusa.payment.createPaymentSession({provider_id: "pp_p24-provider_przelewy24",amount: 10000,currency_code: "PLN",data: {country: "PL", // Country code (defaults to "PL" if not provided)language: "pl", // Language code (defaults to "pl" if not provided)},context: {email: "customer@example.com",},});// Redirect user to P24 payment selectionwindow.location.href = paymentSession.data.redirect_url;
Supported Payment Methods
The plugin currently supports the following Przelewy24 payment methods:
Payment Method Provider ID Notes BLIK Copy to clipboardpp_p24-blik_przelewy24 White-label, channel 64 Cards Copy to clipboardpp_p24-cards_przelewy24 White-label iframe, channel 4096 Visa Mobile Copy to clipboardpp_p24-visa-mobile_przelewy24 Redirect with method Copy to clipboard198 General P24 Copy to clipboardpp_p24-provider_przelewy24 Redirect to P24 method picker
Payment Flows
1. BLIK (white-label)
- Create payment session (Copy to clipboard
initiatePayment) → Copy to clipboardtoken, Copy to clipboardsession_id - Customer enters 6-digit BLIK code
- Copy to clipboard
POST /store/payments/blik/charge→ P24 Copy to clipboardchargeByCode - Customer approves in banking app
- Storefront polls Copy to clipboard
POST /store/carts/{id}/completeuntil order is created - P24 sends webhook to Copy to clipboard
urlStatus→ verify + capture → Copy to clipboardpayment_collection.completed_at
BLIK does not use redirect URLs.
2. Cards (P24 Card 2.0 white-label)
- Create payment session → tokenization fields only (Copy to clipboard
merchant_id, Copy to clipboardsession_id, Copy to clipboardcard_tokenization_sign, Copy to clipboardamount_grosze) — no Copy to clipboardtransaction/registeryet - Load Copy to clipboard
cardTokenizationIframe.min.js, render iframe; regulation checkbox is inside the P24 widget - On Pay: Copy to clipboard
tokenize("temporary")→ Copy to clipboardrefIdvia postMessage - Copy to clipboard
POST /store/payments/card/chargewith Copy to clipboardref_id→ Copy to clipboardtransaction/register+ returns Copy to clipboardchargeScriptUrl - Browser runs Copy to clipboard
Przelewy24CardWhileLabelHandler(3DS in merchant UI) - Storefront polls Copy to clipboard
POST /store/carts/{id}/completeuntil order is created - P24 webhook → verify + capture
See P24 Card 2.0 docs.
3. Visa Mobile (redirect with pre-selected method)
- Create payment session → Copy to clipboard
redirect_url(P24 Copy to clipboardtransaction/registerincludes Copy to clipboardmethod: 198) - Customer pays on P24 hosted Visa Mobile page
- Return to Copy to clipboard
frontend_url/ Copy to clipboardreturn_url - Webhook confirms payment
4. General P24 (redirect)
- Create payment session → Copy to clipboard
redirect_url - Customer pays on P24 hosted page
- Return to Copy to clipboard
frontend_url/ Copy to clipboardreturn_url - Webhook confirms payment
Completion model (all white-label methods)
Step Mechanism Order creation Storefront polls Copy to clipboardcomplete; Medusa Copy to clipboardauthorizePayment queries P24 API; or Copy to clipboardcomplete-captured-carts-backstop (Medusa, every 2 min) when payment is already captured Capture + Copy to clipboardcompleted_at P24 webhook to Copy to clipboardurlStatus, or Copy to clipboardreconcile-p24-payments job (every 5 min)
Do not add a separate store “confirm” route to replace webhooks. Production capture is webhook-driven.
Body Chief monorepo: see Copy to clipboardMedusa/docs/P24_PAYMENTS.mdand Copy to clipboardMedusa/docs/adr/0009-p24-white-label-payments.md.
Webhook Configuration
Webhook URLs (auto-registered)
On each Copy to clipboardtransaction/register, the plugin sets:
1urlStatus: {backend_url}/hooks/payment/{service-identifier}_{payment-module-id}
With Copy to clipboardpayment-module config Copy to clipboardid: "przelewy24" (recommended):
Method Webhook URL Cards Copy to clipboard{backend_url}/hooks/payment/p24-cards_przelewy24 BLIK Copy to clipboard{backend_url}/hooks/payment/p24-blik_przelewy24 Visa Mobile Copy to clipboard{backend_url}/hooks/payment/p24-visa-mobile_przelewy24 General Copy to clipboard{backend_url}/hooks/payment/p24-provider_przelewy24
Medusa route: Copy to clipboardPOST /hooks/payment/:provider → Copy to clipboardgetWebhookActionAndData → Copy to clipboardprocessPaymentWorkflow.
- Copy to clipboard
backend_urlmust be the Medusa server URL (public HTTPS in production), not the storefront. - Webhooks are registered per transaction; you do not paste these into the P24 panel for white-label flows.
- Return URL for redirects: Copy to clipboard
{frontend_url}(and cart-specific Copy to clipboardreturn_urlin session data).
Production checklist
- Copy to clipboard
backend_urlreachable from the internet (P24 cannot call Copy to clipboardlocalhost) - Copy to clipboard
crcmatches merchant panel (signature verification) - P24 webhook source IPs allowed (see Copy to clipboard
P24_WEBHOOK_ALLOWED_IPS; sandbox allows localhost) - Region enables correct Copy to clipboard
pp_p24-*_przelewy24providers
Local development
Without a tunnel, webhooks will not arrive. Orders may still be created via poll Copy to clipboardcomplete, but Copy to clipboardpayment_collection can remain Copy to clipboardnot_paid until the reconcile job runs (~5 min). Use ngrok + public Copy to clipboardbackend_url for full webhook testing.
1cd P24-package && yarn build && yalc publish --push # Body Chief: update Medusa plugin
Related documentation (Body Chief monorepo)
Document Audience Medusa/docs/P24_PAYMENTS.md Backend / ops runbook Medusa/docs/adr/0009-p24-white-label-payments.md Architecture decisions Medusa/CART_PAYMENTS_AND_DISCOUNTS_GUIDE.md Store API integration web/docs/P24_CHECKOUT.md Next.js storefront
Extending the Plugin
To add support for additional Przelewy24 payment methods, create a new service in Copy to clipboardsrc/providers/przelewy24/services that extends the Copy to clipboardP24Base class:
1234567891011121314import P24Base from "../core/p24-base";import { PaymentOptions } from "../types";class P24NewMethodService extends P24Base {static identifier = "p24-new-method";get paymentCreateOptions(): PaymentOptions {return {method: "new_method",};}}export default P24NewMethodService;
Make sure to replace Copy to clipboardnew_method with the actual Przelewy24 payment method ID.
Export your new service from Copy to clipboardsrc/providers/przelewy24/services/index.ts. Then add your new service to the list of services in Copy to clipboardsrc/providers/przelewy24/index.ts.
Local development and customization
In case you want to customize and test the plugin locally, refer to the Medusa Plugin docs.
License
MIT License
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
