E-commerce

Stablecoin payments for headless commerce: is there a plugin for Medusa, Saleor or Vendure?

Short answer: Yes. For stablecoin payments in headless commerce, Payzum publishes open-source (MIT) integrations for Medusa v2, Saleor 3.20+, Vendure 3 and Sylius 2. Each sends the buyer to a hosted checkout to pay in USDC or USDT; a signed webhook marks the order paid. Funds settle non-custodially to your own wallet.

Key takeaways

  • One package per framework, all public. Medusa v2 installs @payzum/medusa-payment-payzum from npm. Saleor installs a payment app from a hosted manifest, or you self-host it. Vendure installs @payzum/vendure-plugin-payzum from npm, and Sylius 2 installs payzum/sylius-payzum-plugin from Packagist.
  • Each one uses the framework's own payment hook. That means a Payment Module Provider in Medusa, the Transactions API in Saleor, a PaymentMethodHandler in Vendure and Payment Requests in Sylius 2. None of them goes around your checkout.
  • The webhook marks the order paid, not the browser. Every integration verifies an HMAC-SHA-512 signature over the raw request bytes, with a replay window, before reading a field. A closed tab never loses a paid order. A faked return visit never pays an unpaid one.
  • Charge only, no refund button. A confirmed stablecoin payment is final, so none of the four exposes refunds in your admin. You send a refund from your own wallet as a separate payment.
  • Check your runtime. The Node.js packages need Node 20.19 or later. Sylius needs PHP 8.2 or later. The Saleor app needs Saleor 3.20 or later, plus a channel set to the CHARGE flow.

Payzum is a non-custodial, stablecoin-first crypto payment processor: payments settle directly to wallets the merchant controls. This guide covers stablecoin payments in headless commerce. It is for teams that run their store on Medusa, Saleor, Vendure or Sylius and build their own storefront on top. It explains why a headless checkout needs a payment integration built for its framework, and gives six checks for any crypto plugin. Then it walks through how Payzum's integration hooks into each framework's checkout, with the code you actually write. All four are listed with their licenses in our index of open-source crypto payment plugins. This post goes one level deeper.

Why headless stores need stablecoin payments built for their framework

In a headless store, checkout is your code. On WooCommerce or Magento, a payment gateway is something you upload and switch on. On a headless stack, a payment touches three places you own. The backend module creates the payment. The storefront sends the buyer somewhere and brings them back. And a webhook route has to find the right order when the money arrives. A crypto option that only ships as a cart plugin leaves headless teams with a REST API and a lot of glue code to write.

These are serious frameworks with active releases. On 4 October 2026, GitHub showed about 36,600 stars for Medusa, 23,400 for Saleor, and about 8,500 each for Vendure and Sylius. All four shipped a release in the last five weeks. Medusa v2.21.2 came out on 28 September 2026, Saleor 3.23.38 on 2 October, Vendure v3.7.3 on 2 September, and Sylius v2.3.0 on 28 September. Teams pick these frameworks because they sell across regions, channels and currencies. Medusa has regions, and Saleor and Vendure have channels. That is exactly where card payments get expensive.

Cross-border cards cost real margin. Take Stripe's published euro pricing, checked on 4 October 2026. A standard EEA card costs 1.5% + €0.25. A card issued outside the EEA and the UK costs 3.15% + €0.25, plus 2% when currency conversion is needed. A €120 order from a US card, charged in dollars, pays €6.43 in fees. If the buyer disputes it, that's €20 to receive the dispute and another €20 to respond to it. The second fee comes back only if you win.

Some buyers already hold the money in USDC or USDT. Think of developers, crypto-native customers, and buyers in countries where foreign cards are often declined or carry steep FX charges. They will pay in stablecoins happily if your checkout lets them. Without that option, they leave or switch to a slower transfer.

What a hand-rolled crypto integration costs a headless team

Calling a crypto API from your backend takes an afternoon. Getting the edge cases right takes much longer. Every item below is a failure mode we ran into while building our own integrations:

  • Orders marked paid by the return page. Crypto confirms after the redirect. If your code trusts the buyer landing on /thank-you, anyone can fake that visit.
  • Signatures that pass only some of the time. Most web frameworks parse JSON before your handler runs. If you check the HMAC against re-serialised JSON, 2.50 comes back as 2.5 and the signature no longer matches. Orders with round totals pass in testing, and real orders fail in production. We reproduced this on Vendure 3.7.2.
  • A paid order downgraded by a late webhook. Payment providers send more than one notification and retry them. A properly signed, late expired event for an invoice the buyer did pay is normal traffic. In an end-to-end test on Saleor, one took a transaction's charged amount from 3.0 back to 0.0.
  • Twin invoices. A retried request without an idempotency key creates a second invoice. The buyer may pay both.
  • Amounts that drift. Vendure stores prices in minor units, while Medusa v2 uses major units. Dividing by 100 with floats, or ignoring each currency's decimals, produces invoices that are a fraction off.
  • A webhook that never finds the order. One case is a reference that doesn't map back to the session. Another is a route the framework doesn't match. Before v2.21.2, Medusa failed to resolve the pp_-prefixed form of its webhook route. And under Express 5, a mount path without a leading slash never runs. Either way, the buyer pays and the order sits unpaid.

Each of these failures either ships unpaid goods or leaves a paid customer waiting while someone reads logs. And they tend to surface on a Saturday, not in the sprint review.

Why card plugins, custodial gateways and a raw API fall short in a headless checkout

Card plugins are mature, but the money isn't final. Medusa, Saleor, Vendure and Sylius all have solid card integrations, and you should keep yours. But the acquirer holds the funds first, cross-border fees stack up, and a payment can be clawed back months after the goods have shipped.

Custodial crypto gateways solve acceptance but not custody. The buyer pays the gateway's address. The gateway credits a balance, and you withdraw on its schedule, subject to its minimums and its freeze policy. Many of them also ship only cart plugins, which puts you back on the raw API.

A raw API or SDK leaves all of the above to you. Payzum ships official SDKs for Node.js/TypeScript, PHP, Python and Rust, and they are the right tool for custom flows. Our guide to choosing a crypto payment gateway with a REST API covers that path. But a framework integration is the SDK plus everything in the previous section, already written and tested.

A self-hosted crypto server is a fair option if you want no third party at all and have someone to run it. The plugins below are for teams that want the same custody without operating payment infrastructure.

How to choose a stablecoin payment plugin for a headless store: six checks

Ask these six questions of any crypto integration for a headless framework, including ours:

  1. Does it use the framework's native payment extension point? A provider, an app, a handler or a gateway that the framework calls is a payment method. Your admin, order states and other integrations all see it. A side route that writes to orders directly is a liability.
  2. What marks the order paid? Look for a server-to-server notification whose signature is checked over the raw request bytes, with a replay window, before any field is read. The buyer's return should only ever display a status.
  3. Can a late or repeated webhook undo or double a paid order? Redelivered events should change nothing. A failure event should be checked against the live invoice before it downgrades anything.
  4. Are amounts exact? Look for strings or integer arithmetic, each currency's own decimals, and the framework's own unit, whether minor or major.
  5. Where do the funds settle? In your own wallet, or in a balance the provider holds? Only the first leaves nobody able to freeze the money.
  6. Can you read the code, and what does it send? Under an open license, your team can audit the webhook path. Check that it sends no customer personal data that the payment doesn't need.

The signed webhooks guide explains checks 2 and 3 in engineering detail.

How Payzum plugs into each headless framework's checkout

All four integrations follow one model, adapted to each framework's payment API:

  1. Create. When the buyer chooses crypto, the backend creates a Payzum invoice for the order total in the order's currency, with an idempotency key so a retry can't create a twin.
  2. Redirect. The framework hands your storefront a hosted-checkout URL. The buyer picks the coin and network there, scans a QR code or copies the address, and pays from any wallet. No wallet or card data touches your servers.
  3. Confirm. Payzum sends a signed notification in its NOWPayments-compatible IPN format. The integration verifies the HMAC-SHA-512 over the raw bytes, with a replay window, and only then moves the payment to paid.
  4. Settle. The money is already in your wallet: Solana confirms in about 0.4 seconds, Base and Polygon in about two. There is no Payzum balance to withdraw, and the integrations contain no wallet address.

The checkout only offers the tokens you accept, which you set in your Payzum dashboard, and Payzum enforces that list on its side. Most stores choose USDC and USDT on low-fee networks. If you accept other crypto as well, optional auto-convert to USDC or USDT is available on most supported networks. Why custody matters here is covered in what a non-custodial crypto payment processor is.

The four integrations at a glance

MedusaSaleorVendureSylius
Framework stackNode.js, TypeScriptPython core; payments run in appsNode.js, TypeScript (NestJS)PHP, Symfony
Payzum packagenpm @payzum/medusa-payment-payzum 1.2.0App saleor-app-payment-payzum (hosted or self-hosted)npm @payzum/vendure-plugin-payzum 1.2.0Packagist payzum/sylius-payzum-plugin v0.2.0
Extension pointPayment Module ProviderTransactions API sync webhooksPaymentMethodHandler + controllerPayment Requests (not Payum)
Supported versionsMedusa v2, Node ≥ 20.19Saleor 3.20+Vendure 3.x, Node ≥ 20.19Sylius 2.x, PHP ≥ 8.2
Where the webhook lands/hooks/payment/payzum_payzumThe app's /api/webhooks/payzum-ipn/payzum/webhookSylius's own /payment-methods/{code}
What "paid" becomesSession captured; cart completedCHARGE_SUCCESSPayment SettledPayment completed
LicenseMITMITMITMIT

Versions as published on npm and Packagist on 4 October 2026.

Medusa v2: a Payment Module Provider

Medusa v2 adds payment methods as providers of its Payment Module. Payzum's provider extends AbstractPaymentProvider with the identifier payzum. You register it in medusa-config.ts:

// medusa-config.ts (apps/backend/ in a create-medusa-app monorepo)
modules: [
  {
    resolve: "@medusajs/medusa/payment",
    options: {
      providers: [
        {
          resolve: "@payzum/medusa-payment-payzum",
          id: "payzum",
          options: {
            apiKey: process.env.PAYZUM_API_KEY,
            webhookSecret: process.env.PAYZUM_WEBHOOK_SECRET,
            payCurrency: "all",
            ipnCallbackUrl: "https://your-store.example/hooks/payment/payzum_payzum",
          },
        },
      ],
    },
  },
]

How it hooks into checkout. When the storefront starts a payment session with the provider, initiatePayment() creates a Payzum invoice. The invoice reference is the Medusa payment session ID, which is the one thing the notification carries back. The provider returns invoiceUrl in the session data, and your storefront redirects the buyer there. payCurrency: "all" lets the buyer choose the coin, limited to the tokens your account accepts.

How it's confirmed. Medusa ships a webhook route, /hooks/payment/[identifier]_[id], which for this provider is /hooks/payment/payzum_payzum. The provider's getWebhookActionAndData() verifies the signature over the raw bytes in constant time and rejects anything outside a 10-minute window. A finished payment is reported as captured. According to Medusa's webhook documentation, Medusa then marks the session captured and, if the cart isn't completed yet, completes it. So the order exists even if the buyer closed the tab.

Late failures are re-checked. An expired or failed event triggers a live lookup of the invoice first, and it never downgrades a payment that has been made. Version 1.2.0 fixed exactly that case. And authorizePayment() asks the Payzum API for the invoice status itself rather than trusting a webhook body.

Things to know. Enable the provider in each region where you want it, in the Medusa admin under Settings → Regions. The Payzum SDK is ESM-only, so you need Node 20.19 or later, or 22.12 or later. refundPayment() deliberately throws: refunds happen outside Medusa. The provider sends Payzum the cart total, the currency, the session reference and your callback URL, and no customer personal data.

Saleor: a payment app on the Transactions API

Saleor runs payments in apps, which are separate services that Saleor calls through webhooks. The Payzum app is a small Next.js service. You can install the instance Payzum hosts or run your own.

Install. In the Saleor Dashboard, go to Apps → Install external app and paste https://saleor.payzum.com/api/manifest, or your own host's /api/manifest. Open the app and save your API key, your webhook secret and the environment. The credentials are stored AES-256-GCM-encrypted in the app's private metadata. The app asks for one permission, HANDLE_PAYMENTS. As Saleor's payment-app documentation puts it, without that permission "Saleor will not call your payment webhooks."

How it hooks into checkout. The app subscribes to three sync webhooks: PAYMENT_GATEWAY_INITIALIZE_SESSION, TRANSACTION_INITIALIZE_SESSION and TRANSACTION_PROCESS_SESSION. Your storefront calls transactionInitialize with the gateway ID payzum.app.payment:

mutation {
  transactionInitialize(
    id: "<checkout-or-order-id>"
    paymentGateway: {
      id: "payzum.app.payment"
      data: { successUrl: "https://shop.example/thanks", cancelUrl: "https://shop.example/cart" }
    }
  ) {
    transaction { id }
    data            # { payzum: { paymentId, paymentUrl } }: redirect the buyer to paymentUrl
    transactionEvent { type message }
  }
}

The app creates the invoice, using the Saleor transaction ID as the reference, and answers CHARGE_ACTION_REQUIRED with the checkout URL.

How it's confirmed. Each invoice carries its own notification URL, so there's nothing to paste into the Payzum dashboard. The IPN endpoint reads the raw body without letting Next.js parse it, then verifies the signature and reports the result with transactionEventReport. finished becomes CHARGE_SUCCESS, and expired or failed becomes CHARGE_FAILURE. A partially_paid invoice stays CHARGE_ACTION_REQUIRED, so an underpaid order never ships and the buyer is never pushed into paying twice. Saleor deduplicates retried reports, and if Saleor is unreachable the app answers with a 5xx so that Payzum redelivers. When the buyer returns, transactionProcess reads the invoice from the API and reports its current state.

Things to know. Payzum has no authorize-then-capture step, so set your channel's default transaction flow to CHARGE under Configuration → Channels → Payment settings. The app advertises no refund action. Fulfil orders from transaction events, never from the buyer reaching successUrl. If you self-host, any Node 20+ host that runs Next.js works, and the repository also ships a Cloudflare Workers deployment.

Vendure: a PaymentMethodHandler plus a signed webhook

Vendure models payments with a PaymentMethodHandler and a payment state machine. The Payzum plugin registers three things: a handler, a webhook controller at /payzum/webhook, and the raw-body middleware the signature check needs. Add it to your config:

// vendure-config.ts
import { PayzumPlugin } from "@payzum/vendure-plugin-payzum"

export const config: VendureConfig = {
  // ...
  plugins: [PayzumPlugin],
}

Configure. In the Admin UI, create a payment method that uses the Crypto / Stablecoins (Payzum) handler. Give it the code payzum, which is also the method your storefront passes to addPaymentToOrder. Then fill in the API key, the webhook secret, the settlement currency (all lets the buyer choose), the environment, and the IPN callback URL https://<your-vendure-host>/payzum/webhook. Point the Payzum dashboard webhook at that same URL.

How it hooks into checkout. When the storefront calls addPaymentToOrder, createPayment() creates a Payzum invoice for the order code. It converts Vendure's minor units into an exact decimal string. It returns the payment as Authorized, with the checkout URL in metadata.public.invoiceUrl, and your storefront redirects the buyer there. Vendure's payment guide calls this a two-step flow: authorize at checkout, settle later. Here, "later" is the signed webhook. If Payzum rejects the invoice, for example because of a bad key or an amount below the network minimum, the payment comes back Declined with the reason in its metadata. Nothing throws inside the checkout.

How it's confirmed. The controller verifies the signature over the bytes captured by its middleware, and answers 401 to anything forged, stale or unsigned. On finished, it settles the authorized Payzum payment and the order moves to PaymentSettled. In the current npm release (1.2.0), the plugin also records the coin, network and amount received on the payment. It cancels an authorization on expired or failed only after the Payzum API confirms that state. And if Vendure refuses the transition, it answers 503 so that Payzum retries.

Things to know. The plugin targets Vendure 3.x on Node 20.19 or later, and works with both Express 4 and 5. Install it from npm, which carries the current release. There is no refund handler.

Sylius 2: a gateway on Payment Requests

Sylius 2.0, released on 12 November 2024, introduced Payment Requests as its new payment layer and moved Payum to a separate bundle. Payzum's plugin is built on Payment Requests, not Payum, and follows the structure of Sylius's official Stripe plugin.

composer require payzum/sylius-payzum-plugin

// config/bundles.php
return [
    // ...
    Payzum\SyliusPayzumPlugin\PayzumSyliusPayzumPlugin::class => ['all' => true],
];

Configure. In the admin, go to Configuration → Payment methods → Create and choose the Payzum (crypto & stablecoins) gateway. Fill in your API key and webhook secret, and tick Sandbox mode to use staging. Two settings are optional, and the other frameworks don't have them: Pay currency pins one asset, such as usdc, and Network pins one chain, such as polygon. Leave both empty to let the buyer choose.

How it hooks into checkout. The capture handler creates the invoice, moves the payment request to processing, and redirects the buyer to the hosted checkout. The payment request hash travels as the Payzum reference. That way a verified notification is matched to its payment without trusting anything else in the payload. When the buyer comes back, the pay page shows the real state, and a payment still confirming stays in processing.

How it's confirmed. Notifications arrive on Sylius's own sylius_payment_method_notify route, /payment-methods/{code}. The plugin sends that URL with every invoice, so there's nothing to configure in the dashboard. It verifies the signature over the raw bytes, with a replay window. Then it re-checks the invoice amount and currency against the payment before completing it. finished completes the payment, expired or failed fails it, and a redelivered notification changes nothing.

Things to know. It needs PHP 8.2 or later and Sylius 2.x. Amounts are converted with exact string arithmetic and each currency's own number of decimals. The repository includes PHPUnit tests for the signature check, the amount conversion and the status mapping.

How to set up stablecoin payments in a headless store, step by step

Whichever framework you run, the rollout has the same shape. Most of the time goes into steps 5 and 6.

  1. Check your stack. You need Medusa v2, Saleor 3.20+, Vendure 3.x or Sylius 2.x. For the Node packages, check that you run Node 20.19 or later; for Sylius, PHP 8.2 or later. Your webhook endpoint must be reachable over HTTPS from the internet. A staging environment behind basic auth or an IP allowlist will never hear back.
  2. Set up your Payzum merchant account. Sign up at merchant.payzum.com and add the wallet you want to be paid into. Choose the tokens you accept, for example USDC on Base, Solana and Polygon, plus USDT. Then create an API key and note your webhook (IPN) secret. Staging has its own keys.
  3. Install the integration. That's npm install for Medusa and Vendure and composer require for Sylius. For Saleor, it's the hosted manifest, or a deployment of your own.
  4. Configure it. Paste the key, the secret and the environment. For Medusa and Vendure, also set the callback URL in the integration and in the Payzum dashboard. Saleor and Sylius send theirs with every invoice. On Saleor, set the channel to the CHARGE flow. On Medusa, enable the provider in your regions.
  5. Wire the storefront redirect. Read the checkout URL your framework returns and send the buyer there. That's invoiceUrl in Medusa session data, data.payzum.paymentUrl in Saleor, metadata.public.invoiceUrl in Vendure, and the capture redirect in Sylius. Your return page should show the order status, not create the order.
  6. Test on staging. Pay a test order. Then pay another and close the tab before the payment confirms: the order should still turn paid. Replay a notification and check that nothing changes. Underpay one invoice and check that the order doesn't ship.
  7. Go live. Switch to your production key and secret, and pay one small real order.

What these integrations don't do

  • No refunds through the framework. A confirmed stablecoin payment is final. If you refund, you send the stablecoins back from your wallet and record it in your admin.
  • No automatic recurring charges. Crypto is pushed from the buyer's wallet and can't be pulled. For recurring revenue, see crypto subscriptions without chargebacks.
  • Partial payments wait. An underpaid invoice stays open until the buyer pays the rest or it expires. No integration marks it paid.
  • No marketplace listing. As of 4 October 2026, the integrations are distributed through GitHub, npm, Packagist and Payzum's hosted Saleor manifest.

Use cases: headless stores taking USDC and USDT

The plumbing is the same for everyone. What changes is which part of it pays for itself.

  • A skincare brand in Barcelona on Medusa. It has a Next.js storefront, and a third of its orders come from Mexico, Colombia and the US. A €120 order paid with a US card in dollars costs €6.43 at Stripe's published pricing, and that is before any dispute. Paid in USDC on Base instead, the session is captured from the signed webhook. Medusa completes the cart even when the buyer closes the tab. The money sits in the brand's wallet seconds after confirmation.
  • An electronics retailer on Saleor with one channel per region. The team doesn't want another service to run, so it installs the app from Payzum's hosted manifest. It shows the stablecoin option only in its Latin American storefront and sets that channel to the CHARGE flow. A buyer in Buenos Aires pays in USDT on Solana, confirmed in about 0.4 seconds. When someone underpays, the transaction stays "action required" and the warehouse never sees the order.
  • A coffee-equipment wholesaler on Vendure. It sells espresso machines to cafés across Latin America, with orders around $4,000. Wires used to take days and often arrived short after intermediary fees. Now the café pays USDT on Polygon, and the Vendure payment moves from Authorized to Settled when the signed webhook arrives. The warehouse picks settled orders only, so nothing ships on a promise.
  • An agency building a Sylius 2 store for a hi-fi retailer in Germany. The retailer's accountant wants exactly one asset, so the agency pins Pay currency to usdc and Network to polygon. The notification route is Sylius's own, so there's no webhook to configure. Before go-live, the agency reads the plugin's tests and the webhook verifier as part of its normal code review.

Payzum on a headless stack vs a card plugin, a custodial crypto gateway and a DIY integration

Compared on neutral criteria. Card figures are Stripe's published euro pricing, checked on 4 October 2026.

CriterionCard plugin (Stripe)Custodial crypto gatewayDIY on a raw APIPayzum headless integration
Where the funds settleWith the acquirer, then paid out to your bankIn the gateway's wallet, then withdrawnDepends on the API you build onIn your own wallet, directly
What marks the order paidThe plugin's capture or webhookThe gateway's callbackWhatever you writeA signed webhook verified over the raw bytes, with a replay window
Time until you hold the fundsDays, on the payout scheduleDepends on the provider's payoutsDepends on the railSeconds after on-chain confirmation (Solana ~0.4 s, Base and Polygon ~2 s)
ChargebacksYes: €20 per dispute, +€20 to respondNone on-chainNone on-chainNone: payments are final
Cost per payment1.5% + €0.25 (standard EEA) to 3.15% + €0.25 (international), +2% conversionVaries by providerYour engineering time, plus network feesNetwork cost in cents on Base, Polygon or Solana
Who can freeze the moneyThe acquirerThe gatewayDepends on custodyNo one at Payzum: there is no Payzum balance
Framework fitOfficial plugins existOften cart plugins onlyYou build the provider, routes and statesNative extension point in Medusa, Saleor, Vendure and Sylius
Refunds in the adminYesVariesIf you build themNo: sent from your wallet
Source codeCheck the vendorVariesYoursPublic on GitHub, MIT

Most stores don't replace anything. They add stablecoins as one more payment method next to cards, and let buyers choose.

Common objections, answered

"We'd rather call the API ourselves."

That's a reasonable choice for an unusual flow, and the official SDKs exist for exactly that. But read the failure list above first. The framework integrations are the same SDK plus the raw-body capture, the idempotency keys, the late-event guard and the unit conversion, all already in place. Under the MIT license you can also fork one and change only the part you need.

"Our ops team needs a refund button."

For crypto, it won't have one. Nobody can pull a stablecoin payment back, and that is also why chargebacks don't exist. Refunds become an outgoing payment from your wallet, recorded in your admin. Most stores keep cards for buyers who expect one-click refunds and offer stablecoins to buyers who want to pay that way.

"What about volatility?"

Your prices stay in your store currency. The invoice is created for the order total, and the buyer pays the equivalent in the coin they choose. If you accept only USDC and USDT, you receive dollar stablecoins. If you accept other crypto too, optional auto-convert to USDC or USDT is available on most supported networks. USDT vs USDC for payments helps you choose between the two.

"Will it survive our next framework upgrade?"

The integrations declare the ranges they target: Medusa ^2.0.0, Vendure ^3.0.0, Sylius core ^2.0, and Saleor 3.20 or later. Framework payment APIs do evolve between minor versions, so test on staging before every upgrade, as you would with any payment code. Because the code is public, your team can check a diff instead of waiting on a vendor.

Frequently asked questions

Is there a stablecoin payment plugin for Medusa, Saleor or Vendure?

Yes. Payzum publishes open-source integrations under MIT for all three, and for Sylius 2. Medusa v2 installs @payzum/medusa-payment-payzum from npm. Saleor 3.20+ installs a payment app from a hosted manifest or a self-hosted instance. Vendure 3 installs @payzum/vendure-plugin-payzum from npm. Buyers pay USDC or USDT on a hosted checkout, and funds settle to the merchant's own wallet.

How do I accept USDC payments in a Medusa v2 store?

Install @payzum/medusa-payment-payzum, register it under the Payment Module in medusa-config.ts with your API key, webhook secret and callback URL /hooks/payment/payzum_payzum, and enable it in your regions. The storefront redirects the buyer to the invoiceUrl in the payment session. The signed webhook captures the session, and Medusa completes the cart if it isn't completed yet.

Do I need to host the Saleor payment app myself?

No. You can install Payzum's hosted instance from https://saleor.payzum.com/api/manifest under Apps → Install external app. If you prefer to run it yourself, the app is open source (MIT), deploys to any Node 20+ host that runs Next.js, and also ships a Cloudflare Workers deployment. Either way, set your channel's transaction flow to CHARGE.

Is there a crypto payment plugin for Sylius 2?

Yes. payzum/sylius-payzum-plugin on Packagist is built on Sylius 2's Payment Requests, not Payum. It needs PHP 8.2 or later. Register the bundle, create a payment method with the Payzum gateway, and paste your API key and webhook secret. You can optionally pin one asset and one network, for example USDC on Polygon.

Can a headless store refund a stablecoin payment through these plugins?

No. A confirmed stablecoin payment is final, so none of the four integrations offers a refund action in the framework admin. To refund, send the stablecoins back from your own wallet and record the refund in your store. Finality is also why there are no chargebacks.

Are there open-source crypto payment plugins for other e-commerce platforms?

Yes. Payzum publishes 29 official integrations at github.com/payzum-dev. They cover carts such as WooCommerce, Magento 2, PrestaShop, Shopware 6 and Shopify, the four headless frameworks, and billing, donation and membership platforms. Licenses are MIT, GPL or OSL 3.0, and every integration is non-custodial.

Book 20 minutes and we'll get USDC live in your headless checkout

Every headless store is wired differently: the framework and version, a custom storefront, regions or channels, the way orders reach the warehouse. Book 20 minutes with our team and we'll map how you'd accept USDC and USDT in yours. We'll cover which integration to use, accepted tokens and networks, the redirect and the webhook route, and a staging payment before you go live. Non-custodial, to a wallet you control. Running a classic cart instead? See the WooCommerce setup guide and the Magento 2 guide.

If the calendar does not load, book directly here · [email protected]

This article is general information, not legal, tax, security or financial advice. The integrations are provided under the MIT license in their repositories; test them on staging before using them in production. Framework behaviour described here comes from Medusa, Saleor, Vendure and Sylius documentation and release notes as of 4 October 2026 and may change with new releases. Rules on stablecoins, refunds, accounting, tax and sanctions screening vary by jurisdiction; confirm them with your own advisers.