UNPKG

@gmisoftware/przelewy24-payments-medusa

Version:

Przelewy24 (P24) payment integration plugin for Medusa e-commerce with BLIK, cards, and general P24 support.

424 lines (319 loc) 15.9 kB
# Przelewy24 Payments for Medusa A comprehensive payment provider plugin that enables [Przelewy24](https://www.przelewy24.pl/) payments on [Medusa](https://medusajs.com/) V2 projects. <p align="center"> <a href="https://gmi.software/"> <img src="https://img.shields.io/badge/Website-gmi.software-blue?style=flat&logo=world" alt="Website" /> </a> <a href="https://pl.linkedin.com/company/gmisoftware"> <img src="https://img.shields.io/badge/LinkedIn-gmisoftware-blue?style=flat&logo=linkedin" alt="LinkedIn" /> </a> </p> ## Table of Contents - [Features](#features) - [Prerequisites](#prerequisites) - [Installation](#installation) - [Configuration](#configuration) - [Configuration Options](#configuration-options) - [Environment Variables](#environment-variables) - [Usage](#usage) - [Client-Side Integration](#client-side-integration) - [Supported Payment Methods](#supported-payment-methods) - [Payment Flows](#payment-flows) - [Webhook Configuration](#webhook-configuration) - [Extending the Plugin](#extending-the-plugin) - [Local Development and Customization](#local-development-and-customization) - [License](#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](https://github.com/gmi-software/p24-medusa-plugin/issues)._ ## Prerequisites - Medusa server v2.4.0 or later - Node.js v20 or later - A [Przelewy24](https://www.przelewy24.pl/) merchant account with API credentials. > [!NOTE] > _You can get your API credentials from your Przelewy24 merchant panel_ ## Installation ```bash yarn add p24-medusa-plugin ``` ## Configuration Add the provider to the `@medusajs/payment` module in your `medusa-config.ts` file: ```typescript import { 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, }, }, ], }, }, ], plugins: ["@gmisoftware/przelewy24-payments-medusa"], }); ``` ## Configuration Options | Option | Description | Required | Default | | -------------- | -------------------------------------- | -------- | ----------------------- | | `merchant_id` | P24 Merchant ID | Yes | - | | `pos_id` | P24 POS ID | Yes | - | | `api_key` | P24 API Key | Yes | - | | `crc` | P24 CRC Key for signature verification | Yes | - | | `sandbox` | Enable sandbox mode (`true`/`false` or `"true"`/`"false"`) | No | `false` | | `card_channel` | P24 channel for card-only registration | No | `4096` | | `visa_mobile_method_id` | P24 method id for Visa Mobile | No | `198` | | `frontend_url` | Frontend URL for customer redirects | No | `http://localhost:3000` | | `backend_url` | Backend URL for webhook notifications | No | `http://localhost:9000` | ## Environment Variables Create or update your `.env` file with the following variables: ```bash # P24 Configuration P24_MERCHANT_ID=your_merchant_id P24_POS_ID=your_pos_id P24_API_KEY=your_api_key P24_CRC=your_crc_key # URL Configuration (use the same names as medusa-config.ts) MEDUSA_STORE_URL=https://your-frontend-domain.com MEDUSA_BACKEND_URL=https://your-backend-domain.com # public HTTPS — P24 webhooks hit this host P24_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** ```typescript // Create payment session for BLIK const paymentSession = await medusa.payment.createPaymentSession({ provider_id: "pp_p24-blik_przelewy24", amount: 10000, // 100.00 PLN in grosze 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", }, }); // Response includes session_id and token, but no redirect_url console.log(paymentSession.data.session_id); // Use this for BLIK processing ``` **Phase 2: Process BLIK Code** ```typescript // 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 `POST /payments/blik` remains as a deprecated wrapper. #### Card Payment 2.0 (white-label iframe) Per [P24 Card Payment 2.0 docs](https://developers.przelewy24.pl/extended/index.php?pl#tag/Inicjalizacja-formularza): ```typescript // 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 browser const cardResponse = await fetch("/store/payments/card/charge", { method: "POST", headers: { "Content-Type": "application/json", "x-publishable-api-key": publishableKey, }, body: JSON.stringify({ ref_id: refIdFromTokenization, payment_session_id: payment_session.id, }), }); const { token, chargeScriptUrl } = await cardResponse.json(); // 4) Load chargeScriptUrl and run Przelewy24CardWhileLabelHandler (3DS in merchant modal) // 5) Poll POST /store/carts/{cartId}/complete until type === "order" // 6) Capture happens via P24 webhook to urlStatus (not via a separate confirm API) ``` #### Visa Mobile (redirect with pre-selected method) ```typescript // 1) Create payment session — returns redirect_url with method 198 pre-selected const { payment_session } = await medusa.store.cart.createPaymentSession(cartId, { provider_id: "pp_p24-visa-mobile_przelewy24", }); // 2) Redirect customer to P24 Visa Mobile flow window.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) ```typescript await 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 ```typescript // Create payment session for general P24 const 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 selection window.location.href = paymentSession.data.redirect_url; ``` ### Supported Payment Methods The plugin currently supports the following Przelewy24 payment methods: | Payment Method | Provider ID | Notes | | -------------- | ----------------------------------- | ------------------------------ | | BLIK | `pp_p24-blik_przelewy24` | White-label, channel 64 | | Cards | `pp_p24-cards_przelewy24` | White-label iframe, channel 4096 | | Visa Mobile | `pp_p24-visa-mobile_przelewy24` | Redirect with method `198` | | General P24 | `pp_p24-provider_przelewy24` | Redirect to P24 method picker | ## Payment Flows ### 1. BLIK (white-label) 1. Create payment session (`initiatePayment`) → `token`, `session_id` 2. Customer enters 6-digit BLIK code 3. `POST /store/payments/blik/charge` → P24 `chargeByCode` 4. Customer approves in banking app 5. Storefront polls `POST /store/carts/{id}/complete` until order is created 6. P24 sends webhook to `urlStatus` → verify + capture → `payment_collection.completed_at` BLIK does not use redirect URLs. ### 2. Cards (P24 Card 2.0 white-label) 1. Create payment session → tokenization fields only (`merchant_id`, `session_id`, `card_tokenization_sign`, `amount_grosze`) — **no** `transaction/register` yet 2. Load `cardTokenizationIframe.min.js`, render iframe; regulation checkbox is **inside** the P24 widget 3. On Pay: `tokenize("temporary")``refId` via postMessage 4. `POST /store/payments/card/charge` with `ref_id``transaction/register` + returns `chargeScriptUrl` 5. Browser runs `Przelewy24CardWhileLabelHandler` (3DS in merchant UI) 6. Storefront polls `POST /store/carts/{id}/complete` until order is created 7. P24 webhook → verify + capture See [P24 Card 2.0 docs](https://developers.przelewy24.pl/extended/index.php?pl#tag/Inicjalizacja-formularza). ### 3. Visa Mobile (redirect with pre-selected method) 1. Create payment session → `redirect_url` (P24 `transaction/register` includes `method: 198`) 2. Customer pays on P24 hosted Visa Mobile page 3. Return to `frontend_url` / `return_url` 4. Webhook confirms payment ### 4. General P24 (redirect) 1. Create payment session → `redirect_url` 2. Customer pays on P24 hosted page 3. Return to `frontend_url` / `return_url` 4. Webhook confirms payment ### Completion model (all white-label methods) | Step | Mechanism | |------|-----------| | Order creation | Storefront polls `complete`; Medusa `authorizePayment` queries P24 API; or `complete-captured-carts-backstop` (Medusa, every 2 min) when payment is already captured | | Capture + `completed_at` | P24 webhook to `urlStatus`, or `reconcile-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 `Medusa/docs/P24_PAYMENTS.md` and `Medusa/docs/adr/0009-p24-white-label-payments.md`. ## Webhook Configuration ### Webhook URLs (auto-registered) On each `transaction/register`, the plugin sets: ```text urlStatus: {backend_url}/hooks/payment/{service-identifier}_{payment-module-id} ``` With `payment-module` config `id: "przelewy24"` (recommended): | Method | Webhook URL | |--------|-------------| | Cards | `{backend_url}/hooks/payment/p24-cards_przelewy24` | | BLIK | `{backend_url}/hooks/payment/p24-blik_przelewy24` | | Visa Mobile | `{backend_url}/hooks/payment/p24-visa-mobile_przelewy24` | | General | `{backend_url}/hooks/payment/p24-provider_przelewy24` | Medusa route: `POST /hooks/payment/:provider` → `getWebhookActionAndData` → `processPaymentWorkflow`. - **`backend_url`** must 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: `{frontend_url}` (and cart-specific `return_url` in session data). ### Production checklist - [ ] `backend_url` reachable from the internet (P24 cannot call `localhost`) - [ ] `crc` matches merchant panel (signature verification) - [ ] P24 webhook source IPs allowed (see `P24_WEBHOOK_ALLOWED_IPS`; sandbox allows localhost) - [ ] Region enables correct `pp_p24-*_przelewy24` providers ### Local development Without a tunnel, webhooks will not arrive. Orders may still be created via poll `complete`, but `payment_collection` can remain `not_paid` until the **reconcile** job runs (~5 min). Use ngrok + public `backend_url` for full webhook testing. ```bash cd P24-package && yarn build && yalc publish --push # Body Chief: update Medusa plugin ``` ## Related documentation (Body Chief monorepo) | Document | Audience | |----------|----------| | [Medusa/docs/P24_PAYMENTS.md](../Medusa/docs/P24_PAYMENTS.md) | Backend / ops runbook | | [Medusa/docs/adr/0009-p24-white-label-payments.md](../Medusa/docs/adr/0009-p24-white-label-payments.md) | Architecture decisions | | [Medusa/CART_PAYMENTS_AND_DISCOUNTS_GUIDE.md](../Medusa/CART_PAYMENTS_AND_DISCOUNTS_GUIDE.md) | Store API integration | | [web/docs/P24_CHECKOUT.md](../web/docs/P24_CHECKOUT.md) | Next.js storefront | ## Extending the Plugin To add support for additional Przelewy24 payment methods, create a new service in `src/providers/przelewy24/services` that extends the `P24Base` class: ```typescript import 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 `new_method` with the actual Przelewy24 payment method ID. Export your new service from `src/providers/przelewy24/services/index.ts`. Then add your new service to the list of services in `src/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](https://docs.medusajs.com/learn/fundamentals/plugins/create#3-publish-plugin-locally-for-development-and-testing). ## License MIT License ## Contributing 1. Fork the repository 2. Create a feature branch 3. Make your changes 4. Add tests 5. Submit a pull request