Medusa v2 Paystack plugin with per-store publishable key settings, storefront helpers, and an optional verified payment provider.
Medusa v2 plugin for Paystack with:
Helper mode only needs the Paystack publishable key.
It gives you:
In helper mode, the browser callback is only a UX signal. The plugin does not mark a Medusa order as paid from the client callback alone.
Verified mode uses the same browser checkout flow, but also registers the optional payment provider with a Paystack .
In verified mode:
npm install medusa-paystack-plugin
Register the plugin in your Medusa app:
module.exports = defineConfig({plugins: [{resolve: "medusa-paystack-plugin",options: {},},],})
If you want verified Medusa payment completion, also register the provider:
module.exports = defineConfig({plugins: [{resolve: "medusa-paystack-plugin",options: {secret_key: process.env.PAYSTACK_SECRET_KEY,},},],modules: [{resolve: "@medusajs/medusa/payment",options: {providers: [{resolve: "medusa-paystack-plugin/providers/paystack",id: "paystack",options: {secret_key: process.env.PAYSTACK_SECRET_KEY,},},],},},],})
After the plugin is installed, open the store details page in Medusa Admin. A widget is injected into .
Save the store-specific publishable key there. The widget stores it in:
store.metadata.paystack_publishable_key
Returns:
{"store_id": "store_123","publishable_key": "pk_test_xxx","verified_mode_enabled": true}
If your Medusa installation has more than one store, pass .
Returns a minimal HTML page that loads Paystack InlineJS and starts checkout inside a mobile webview or popup-style browser window.
Supported query params:
On success, cancel, or error the page:
Import the helper:
import {buildPaystackReference,buildPaystackWebviewUrl,createPaystackSuccessHandler,fetchPaystackConfig,launchPaystackCheckout,} from "medusa-paystack-plugin/frontend"
const config = await fetchPaystackConfig({baseUrl: process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL,storeId: "store_123",})const onSuccess = createPaystackSuccessHandler({mode: config.verified_mode_enabled ? "verified" : "helper",cartId: cart.id,sdk,redirectUrl: `${window.location.origin}/checkout/complete`,})await launchPaystackCheckout({key: config.publishable_key,email: cart.email!,amount: paymentSession.amount,currency: paymentSession.currency_code,reference:(paymentSession.data as { paystack_reference?: string })?.paystack_reference ??buildPaystackReference(),metadata: {cart_id: cart.id,},successHandler: onSuccess,})
const webviewUrl = buildPaystackWebviewUrl({baseUrl: process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL,callbackUrl: "myapp://checkout/complete",currency: cart.currency_code,email: cart.email!,amount: cart.total,metadata: {cart_id: cart.id,},storeId: "store_123",})
Load that URL in your mobile webview and listen for the message payload or the redirect to your callback URL.
npm run typechecknpm testnpm run build