• Модуль интеграций
  • Сообщество
  • Блог
Документация
Плагины и интеграцииВсе расширения для Medusa от сообществаСтартерыЗапускайте проекты быстрее с готовыми решениями
ЭкспертыПодберите специалиста для разработки и развития вашего проекта на MedusaКейсыПосмотрите примеры Medusa в продакшене и успешные внедрения
Меч Moscow
Комплексная e-commerce платформа на Medusa для московского fashion-бренда

Меч Moscow · Fashion

Gorgo снижает затраты на адаптацию Medusa к локальным рынкам.

Мы разрабатываем плагины интеграции, осуществляем поддержку и развиваем сообщество разработчиков на Medusa в Telegram.

  • Ресурсы Medusa
  • Плагины и интеграции
  • Стартеры
  • Эксперты
  • Кейсы
  • Medusa Чат в Telegram
  • Medusa Новости в Telegram
  • Документация Gorgo
  • Связаться с нами
  • TelegramGitHub
Плагины
C

Cutluy

Medusa Payment Module Provider for CutLuy — Bakong KHQR scan-to-pay (asynchronous payment method).

npm install medusa-payment-cutluy
Категория
Платежи
Создано
Gavined1
Версия
0.2.4
Последнее обновление
2 дня назад
Ежемесячные загрузки
Загрузка данных
Звезды на Github
0
npmNPMGitHubGithub

medusa-payment-cutluy

A Medusa Payment Module Provider for CutLuy — Bakong KHQR scan-to-pay payments.

CutLuy is an asynchronous payment method: the customer scans a KHQR code (or opens a hosted checkout page) and pays from their banking app. The plugin is a standalone Medusa payment provider (like ) and installable in any Medusa v2 application.


Features

  • ✅ Create a CutLuy KHQR payment per payment session
  • ✅ Exposes and to the storefront through the payment session
  • ✅ Asynchronous authorization () → order created as "awaiting"
  • ✅ Webhook handling via Medusa's built-in listener with HMAC-SHA256 signature verification (over the raw body) and session/amount verification
  • ✅ Scheduled sweep job that detects CutLuy payments expired/failed while their order is still (dropped webhook events) and flags them for operators
  • ✅ webhook marks the session captured and completes the cart/order
  • ✅ Poll-based status () and retrieval ()
  • ✅ USD-only enforcement (CutLuy only charges USD)
  • ❌ Capture / cancel / delete / update / refund are not part of CutLuy's public v1 API — implemented as safe no-ops or explicit errors

How it works

1sequenceDiagram
2 participant S as Storefront
3 participant M as Medusa Backend
4 participant C as CutLuy
5
6 S->>M: initiate payment session (provider_id = cutluy)
7 M->>C: POST /v1/payments (amount in USD, metadata.session_id)
8 C-->>M: payment { id, qr_string, checkout_url }
9 M-->>S: payment session data (qr_string / checkout_url)
10 S->>S: render QR or redirect to checkout_url
11 S->>M: place order → authorizePayment → pending_authorization
12 C->>M: webhook payment.completed → /hooks/payment/cutluy_cutluy
13 M->>M: verify X-CutLuy-Signature → mark captured → complete cart/order

Because returns , the order is created with an awaiting payment status. When CutLuy fires , Medusa's re-invokes — the provider re-checks the CutLuy payment status and returns once it's paid — which creates the Payment record, captures it, and flips the order to paid/captured. If the QR expires or the payment fails, / are mapped to a action — which Medusa 2.18's webhook processor ignores, so the order remains awaiting and no capture occurs. The storefront must surface CutLuy's own payment status (poll ), and operators see a warning log per event.

Async flow requirement: polls on every call and only returns while the payment is still pending. This is what lets the webhook-driven autocapture flow create and capture the Payment.


Requirements

  • Medusa v2.17.0 or later (uses the async payment methods support)
  • Node.js 20+
  • A CutLuy account with an API key and a configured webhook endpoint

Testing

A complete end-to-end test harness lives in the directory (sibling of this repo — not part of the package):

  • — Postgres + Redis for the Medusa app
  • — a backend with the plugin registered
  • — a mock of the CutLuy API (), so no real credentials are needed
  • — drives the full flow via the API: cart → payment session () → verify / → complete cart (order "awaiting") → simulate customer paying at the mock → deliver a signed webhook → assert the order becomes

When you later point the provider at the real CutLuy API ( + real key), the same script works unchanged.

Dependency & security posture: the published package ships zero runtime dependencies — it only declares the peer (>=2.17.0) that any Medusa app already provides. Scanner findings (CVEs, telemetry, minified files) that appear for this package come from Medusa core's own dependency tree (e.g. , which is opt-out via ), and are identical for every Medusa plugin — they resolve upstream when Medusa updates its dependencies.


1. Install

Install locally for development (yalc)

From this plugin's directory (pnpm is the package manager for this repo):

1pnpm install
2pnpm medusa plugin:publish # pushes to the LOCAL yalc registry (dev only — this is not npm)

Then, in your Medusa application:

npx medusa plugin:add medusa-payment-cutluy

While developing, run in this plugin's directory to watch changes and auto-update the app.

Install from npm

npm install medusa-payment-cutluy

2. Configure

In of your Medusa application, register the provider in the Payment Module's array:

medusa-config.ts
1import { defineConfig } from "@medusajs/framework/utils"
2
3module.exports = defineConfig({
4 // ...other config
5 modules: [
6 {
7 resolve: "@medusajs/medusa/payment",
8 options: {
9 providers: [
10 {
11 // provider installed from the local registry or npm
12 resolve: "medusa-payment-cutluy/providers/cutluy",
13 id: "cutluy",
14 options: {
15 apiKey: process.env.CUTLUY_API_KEY,
16 webhookSecret: process.env.CUTLUY_WEBHOOK_SECRET,
17 // apiUrl: "https://cutluy.com/v1", // optional override
18 // timeoutMs: 15000, // optional
19 },
20 },
21 ],
22 },
23 },
24 ],
25})

Add the environment variables to your application's :

1# apps/backend/.env
2CUTLUY_API_KEY=ck_live_...
3CUTLUY_WEBHOOK_SECRET=whsec_...

The provider's identifier is . Enable it in a region from the Medusa Admin (Settings → Regions → Payment Providers).

Options

OptionRequiredDescription
✅CutLuy secret API key ( / )
⚠️Signing secret used to verify . Without it webhooks are rejected.
Override the API base URL (default )
HTTP request timeout (default )

3. Configure the webhook in CutLuy

  1. Make sure your CutLuy store has a payment link configured (payment creation returns otherwise).

  2. In the CutLuy dashboard, go to Webhooks.

  3. Add an endpoint pointing at Medusa's built-in payment webhook listener:

    https://<your-medusa-backend>/hooks/payment/cutluy_cutluy

    ( is the provider's , repeated for the provider .)

  4. Copy the endpoint's signing secret into .

The provider verifies the header (HMAC-SHA256 of ) before trusting any event. Medusa's built-in listener acks the request with 200 immediately and processes the event asynchronously (~5s delay, up to 3 internal attempts). Invalid or missing signatures are logged and dropped — the request is still acked, so CutLuy does not retry after a 2xx (non-2xx or timeout responses are retried with exponential backoff, up to 8 times); monitor your backend logs for signature failures. Use the dashboard's Send test or resend a delivery to exercise your endpoint.

Before completing, the provider also verifies the webhook's payment against its payment session: the session must exist, the payment must be USD, and the webhook amount must match the session amount cent-exact. On a mismatch or unknown session the event is logged and ignored (the order stays ). The payload is HMAC-authenticated, so this guards against CutLuy-side drift, not forgery.

Payment sweep job

Because Medusa 2.18's webhook processor ignores / events, an order whose QR expired or whose payment failed would stay forever with no signal. The plugin ships a scheduled job, , that closes the loop:

  • Runs every 15 minutes (node-schedule cron ).
  • Lists the provider's payment sessions older than 15 minutes that are still / , polls CutLuy for each, and for payments that are or at CutLuy:
    • logs a warning with the session id, CutLuy payment id, amount, and currency, and
    • marks the session (best-effort) so it stops being silently pending.
  • Sessions are only touched once (they leave the pending set), so re-runs are idempotent.

To load the job, the plugin must be listed in the app's array (the provider itself is registered under ):

medusa-config.ts
plugins: ["medusa-payment-cutluy"],

The staleness window is tunable via (default ).


4. Storefront integration

The payment session contains everything the storefront needs:

1{
2 "id": "PUETcMUOKStjZsCb6zAl8kg9fMRGM85x",
3 "status": "pending",
4 "amount": "1.50",
5 "currency": "USD",
6 "qr_string": "00020101021229...", // render as a QR code
7 "checkout_url": "https://cutluy.com/pay/PUETcMUOKStjZsCb6zAl8kg9fMRGM85x",
8 "expires_at": "2026-07-09T12:05:00.000Z"
9}

Choose one of:

  • Redirect the customer to (hosted, branded page with countdown and live status), or
  • Render as a QR code in your own UI (e.g. with a library) and poll the cart/order status.

After the customer pays, the webhook completes the order automatically — no storefront polling required.

CutLuy's hosted checkout redirects back to your configured success/failure URLs after a terminal payment, appending . Since Medusa drops / webhooks, the redirect (or polling ) is how the storefront learns the order failed — the order itself stays until the sweep job or an operator acts.


5. Development

1pnpm install # install dependencies
2pnpm test # run unit tests (vitest)
3pnpm build # medusa plugin:build → outputs to .medusa/server
4pnpm dev # watch + push to the local yalc registry for the test app

6. Testing in a full Medusa app (Docker)

This repo ships only the plugin. To test it end-to-end, run a Medusa app in Docker and install the plugin into it. Follow the official guide — Install Medusa with Docker — then:

  1. Clone the DTC Starter repo and set up , , as described in the guide.
  2. Install the plugin locally via yalc ( here, then in the app), or mount this plugin's folder and install it with .
  3. Register the provider in (see Configure) and add the env vars to .
  4. , create an admin user, and enable the CutLuy payment provider in a region.
  5. Expose the backend to the internet (e.g. with a tunnel) and set the webhook URL in the CutLuy dashboard.

API mapping

Medusa provider methodCutLuy API call
webhook events (signature verified)
/ / / no-op (not in CutLuy v1 API)
throws — not supported by CutLuy yet

Status mapping: / → pending · → captured · / → error/failed.


License

MIT

Еще в этой категории

Посмотреть все
Платежи
Braintree logo

Braintree

От Lambda Curry

Поддержка платежей и 3D Secure через Braintree

Загрузка данных
GitHubnpm
Платежи
Pay. logo

Pay.

От Webbers

Принимайте кредитные карты, цифровые платежи и купи сейчас — плати потом

Загрузка данных
GitHubnpm
Платежи
Mollie logo

Mollie

От Variable Vic

Легко принимайте мультивалютные платежи через Mollie

Загрузка данных
GitHubnpm