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

Меч Moscow · Fashion

Нужна помощь в разработке плагина интеграции для Medusa?

Написать намНайти плагины

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

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

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

Cybersource

CyberSource payment provider for Medusa.js v2 with Flex Microform (PCI DSS SAQ-A)

Нужна доработка этого плагина?

Связаться с нами
npm install medusa-payment-cybersource
Категория
Платежи
Создано
Geovannygil
Версия
1.1.1
Последнее обновление
3 месяца назад
Ежемесячные загрузки
Загрузка данных
Звезды на Github
4
npmNPMGitHubGithub

Medusa Payment Cybersource for Medusa

CyberSource payment plugin for Medusa.js v2, built on Flex Microform v2 (PCI DSS SAQ-A compliant).

Features

  • Flex Microform v2 — card data is tokenized directly at CyberSource; it never touches your server
  • Device Fingerprint (ThreatMetrix) — fraud scoring via device profiling before payment
  • Authorization + manual capture from the Medusa admin dashboard
  • Auto-capture (sale mode) for instant settlement
  • Partial and full refunds
  • Zero-amount orders — 100% discounts and free orders are handled automatically (no gateway call)
  • Admin widget — CyberSource transaction details panel injected into order detail view

Requirements

Medusa.jsv2 ()
Node.js18+
CyberSourceBusiness Center account

Installation

npm install medusa-payment-cybersource

Environment Variables

Add these to your :

1CYBERSOURCE_MERCHANT_ID=your_merchant_id
2CYBERSOURCE_KEY_ID=your_shared_key_id
3CYBERSOURCE_SECRET_KEY=your_shared_secret_key
4CYBERSOURCE_ENV=sandbox # or "production"
5CYBERSOURCE_AUTO_CAPTURE=false # set to "true" for sale/auto-capture mode

Where to find these values: CyberSource Business Center → Account Management → Transaction Security Keys → Security Keys for the HTTP Signature Security Policy

Configuration

In , add the plugin to both (for the API route) and (for the payment provider):

1import { loadEnv, defineConfig } from "@medusajs/framework/utils"
2
3loadEnv(process.env.NODE_ENV || "development", process.cwd())
4
5module.exports = defineConfig({
6 plugins: [
7 // Required: registers the built-in /store/cybersource/authorize route
8 { resolve: "medusa-payment-cybersource" },
9 ],
10 projectConfig: {
11 // ... your existing config
12 },
13 modules: [
14 {
15 resolve: "@medusajs/medusa/payment",
16 options: {
17 providers: [
18 {
19 resolve: "medusa-payment-cybersource",
20 id: "cybersource",
21 options: {
22 merchantID: process.env.CYBERSOURCE_MERCHANT_ID,
23 merchantKeyId: process.env.CYBERSOURCE_KEY_ID,
24 merchantsecretKey: process.env.CYBERSOURCE_SECRET_KEY,
25 environment:
26 process.env.CYBERSOURCE_ENV === "production"
27 ? "production"
28 : "sandbox",
29 capture: process.env.CYBERSOURCE_AUTO_CAPTURE === "true",
30 },
31 },
32 ],
33 },
34 },
35 ],
36})

Plugin Options

OptionTypeDescription
Required. Your CyberSource Merchant ID
Required. Shared key ID (HTTP Signature)
Required. Shared secret key (HTTP Signature)
or . Default:
Auto-capture on authorization (sale mode). Default:
Card networks for Flex. Default:

Payment Flow

Frontend Integration

1. Load Flex Microform

<script src="https://flex.cybersource.com/microform/bundle/v2/flex-microform.min.js"></script>

2. Load Device Fingerprint Script

When the user selects CyberSource as payment method, generate a unique session ID and load the ThreatMetrix script. The same ID must be sent in the authorize request.

1const fingerprintSessionId = crypto.randomUUID()
2
3const script = document.createElement("script")
4script.src = `https://h.online-metrix.net/fp/tags.js?org_id=${ORG_ID}&session_id=${fingerprintSessionId}`
5script.async = true
6document.head.appendChild(script)
7
8// org_id values:
9// Sandbox: 1snn5n9w
10// Production: k8vif92e (confirm in Business Center → Decision Manager)

3. Initialize Flex

1// captureContext comes from payment_session.data.captureContext
2const flex = new Flex(captureContext)
3const microform = flex.microform()
4
5const cardNumber = microform.createField("number", { placeholder: "Card number" })
6const cvn = microform.createField("securityCode", { placeholder: "CVV" })
7
8cardNumber.load("#card-number-container")
9cvn.load("#cvn-container")

4. Tokenize and Pre-authorize

Call this before :

1async function authorizePayment(paymentSessionId, fingerprintSessionId) {
2 // 1. Get transient token from Flex Microform
3 const transientToken = await new Promise((resolve, reject) => {
4 microform.createToken({ expirationMonth: "12", expirationYear: "2030" }, (err, token) => {
5 if (err) reject(err)
6 else resolve(token)
7 })
8 })
9
10 // 2. Pre-authorize at CyberSource via the built-in plugin route
11 const response = await fetch("/store/cybersource/authorize", {
12 method: "POST",
13 headers: {
14 "Content-Type": "application/json",
15 "x-publishable-api-key": YOUR_PUBLISHABLE_API_KEY,
16 },
17 body: JSON.stringify({
18 payment_session_id: paymentSessionId,
19 transient_token: transientToken,
20 fingerprint_session_id: fingerprintSessionId, // same UUID used in the script URL
21 bill_to: { // optional but recommended
22 firstName: "John",
23 lastName: "Doe",
24 email: "john@example.com",
25 address1: "123 Main St",
26 locality: "Guatemala City",
27 administrativeArea: "Guatemala",
28 postalCode: "01001",
29 country: "GT",
30 },
31 }),
32 })
33
34 const result = await response.json()
35
36 if (!response.ok) {
37 throw new Error(result.message || "Payment declined")
38 }
39
40 return result // { success: true, cs_payment_id, cs_status }
41}
42
43// Usage
44await authorizePayment(
45 cart.payment_collection.payment_sessions[0].id,
46 fingerprintSessionId,
47)
48await placeOrder() // Medusa completes the order using the stored cs_payment_id

— Request / Response

Request body:

FieldRequiredDescription
YesMedusa payment session ID
YesJWT from
NoSession ID used in the ThreatMetrix script URL
NoBilling address object for AVS/fraud checks

Success response (200):

{ "success": true, "cs_payment_id": "7278957202756800104005", "cs_status": "AUTHORIZED" }

Declined response (402):

{ "error": "Payment declined", "reason": "INSUFFICIENT_FUND", "cs_status": "DECLINED" }

Device Fingerprint

The plugin sends and to the CyberSource Payments API. The flag is required so that CyberSource looks up ThreatMetrix using the raw session ID (your UUID) instead of the default composite key — which would cause a mismatch with what the frontend script registered.

You can verify fingerprint collection is working by checking a transaction in CyberSource Business Center. A successful integration shows a hash under Device Fingerprint ID instead of "Not Submitted".

Capture Modes

Manual Capture (default)

CyberSource authorizes the card on order placement. You capture the funds from the Medusa Admin → Orders → Payment panel. Authorization expires in 5–7 days if not captured.

Auto-Capture (sale mode)

Set . CyberSource processes authorization and capture together; the payment is marked as captured immediately on order placement.

Admin Widget

The plugin injects a CyberSource panel into the order detail page of the Medusa admin (). It shows:

FieldDescription
Status badgeDerived display status (see table below)
Transaction IDCyberSource authorization ID
Capture IDOnly shown if different from Transaction ID (manual capture)
Reconciliation IDCyberSource reconciliation ID
CardCard brand + last 4 digits
Last Refund IDID of the last refund issued
Last Refund AmountAmount of the last refund

Status badge logic:

ConditionBadge
is set🔵 REFUNDED
+ set (auto-capture)🟢 CAPTURED
(no capture ID)🟠 AUTHORIZED
🟢 CAPTURED
⚫ VOIDED
🔴 DECLINED

Admin Refund Route

Medusa's default refund UI has a validation that can block refunds in some edge cases. Add this route to your Medusa store for a direct refund bypass:

Create in your Medusa project:

1import { MedusaRequest, MedusaResponse } from "@medusajs/framework"
2import { Modules } from "@medusajs/framework/utils"
3
4type RefundRequestBody = {
5 payment_id: string
6 amount?: number
7 note?: string
8}
9
10export const POST = async (
11 req: MedusaRequest<RefundRequestBody>,
12 res: MedusaResponse
13) => {
14 const { payment_id, amount, note } = req.body
15
16 if (!payment_id) {
17 return res.status(400).json({ error: "payment_id is required" })
18 }
19
20 const paymentModule = req.scope.resolve(Modules.PAYMENT)
21
22 const payments = await paymentModule.listPayments(
23 { id: [payment_id] },
24 { relations: ["captures", "refunds"] }
25 )
26 const payment = payments[0]
27
28 if (!payment) {
29 return res.status(404).json({ error: "Payment not found" })
30 }
31
32 const captured = (payment.captures ?? []).reduce(
33 (sum: number, c: any) => sum + Number(c.amount ?? 0),
34 0
35 )
36 const alreadyRefunded = (payment.refunds ?? []).reduce(
37 (sum: number, r: any) => sum + Number(r.amount ?? 0),
38 0
39 )
40 const refundable = captured - alreadyRefunded
41
42 if (refundable <= 0) {
43 return res.status(400).json({ error: "No capturable amount available to refund" })
44 }
45
46 const refundAmount = amount ?? refundable
47
48 if (refundAmount > refundable) {
49 return res.status(400).json({
50 error: `Cannot refund ${refundAmount}. Maximum refundable: ${refundable}`,
51 })
52 }
53
54 const updatedPayment = await paymentModule.refundPayment({
55 payment_id,
56 amount: refundAmount,
57 created_by: (req as any).auth_context?.actor_id,
58 note,
59 })
60
61 return res.json({ payment: updatedPayment })
62}

Call it from your admin UI or custom dashboard:

1curl -X POST http://localhost:9000/admin/cybersource/refund \
2 -H "Authorization: Bearer <admin_token>" \
3 -H "Content-Type: application/json" \
4 -d '{ "payment_id": "pay_01...", "amount": 50.00 }'

Development

1# Clone
2git clone https://github.com/Eleven-Estudio/medusa-payment-cybersource.git
3cd medusa-payment-cybersource
4
5# Install dependencies
6npm install
7
8# Build
9npm run build
10
11# Watch mode (backend only)
12npm run dev

Linking to a local Medusa store with yalc

1# In the plugin directory
2npm run build
3npx yalc push
4
5# In your Medusa store directory
6npx yalc add medusa-payment-cybersource
7npx medusa develop

After any plugin change, re-run in the plugin directory, then fully restart the Medusa server (yalc updates , hot-reload won't pick it up).

CyberSource Resources

  • Business Center — sandbox + production portal
  • Flex Microform v2 docs
  • Payments API reference
  • Sandbox test cards

License

MIT

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

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

Braintree

От Lambda Curry

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

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

Pay.

От Webbers

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

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

Mollie

От Variable Vic

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

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