npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

medusa-payment-cpay

v1.0.2

Published

cPay payment provider for MedusaJS v2 — card payments via cpay.com.mk

Downloads

26

Readme

medusa-payment-cpay

cPay payment provider for MedusaJS v2. Integrates the cPay card payment gateway used in North Macedonia.

Built according to cPay Merchant Integration Specification v2.6.8.

Supported cards: MasterCard, Maestro, Visa, Diners Club, Domestic cards.

How It Works

cPay is a redirect-based payment gateway. Card details are never entered on your site:

  Customer         Storefront         Medusa Backend           cPay
     |                 |                    |                     |
     |-- select cPay ->|                    |                     |
     |                 |-- initiatePayment->|                     |
     |                 |<-- form params ----|                     |
     |<-- redirect ----|----------- POST hidden form ----------->|
     |                 |                    |                     |
     |                 |          (customer enters card on cPay)  |
     |                 |                    |                     |
     |                 |                    |<--- PUSH (T1) ------|
     |                 |                    |---- 200 OK -------->|
     |<--------------------------- browser redirect --------------|
     |                 |                    |                     |
     |--- callback --->|--- placeOrder ---->|                     |
     |                 |<-- order created --|                     |
     |<-- confirmation-|                    |                     |

Installation

Option A: Install via npm / yarn

# npm
npm install medusa-payment-cpay

# yarn
yarn add medusa-payment-cpay

Then register the provider in medusa-config.ts:

module.exports = defineConfig({
  // ...
  modules: [
    {
      resolve: "@medusajs/medusa/payment",
      options: {
        providers: [
          {
            resolve: "medusa-payment-cpay",
            id: "cpay",
            options: {
              merchantId: process.env.CPAY_MERCHANT_ID,
              merchantName: process.env.CPAY_MERCHANT_NAME,
              checksumKey: process.env.CPAY_CHECKSUM_KEY,
              paymentUrl: process.env.CPAY_PAYMENT_URL,
              callbackBaseUrl: process.env.CPAY_CALLBACK_BASE_URL,
              storefrontUrl: process.env.CPAY_STOREFRONT_URL,
            },
          },
        ],
      },
    },
  ],
})

You still need to add the webhook route manually (Medusa API routes must live in your project). Copy the webhook file into your project:

mkdir -p src/api/webhooks/cpay
cp node_modules/medusa-payment-cpay/dist/webhook.js src/api/webhooks/cpay/route.ts

Or create src/api/webhooks/cpay/route.ts yourself using the reference in this package (see src/webhook.ts).

Option B: Copy files directly (no npm)

Copy the src/ files into your Medusa project:

your-medusa-project/src/
  modules/cpay/
    index.ts      <- src/provider.ts (rename to index.ts)
    service.ts    <- src/service.ts
    checksum.ts   <- src/checksum.ts
    types.ts      <- src/types.ts
  api/webhooks/cpay/
    route.ts      <- src/webhook.ts (rename to route.ts)

Then register with a local path:

{
  resolve: "./src/modules/cpay",
  id: "cpay",
  options: { ... }
}

Add body parser middleware

cPay sends POST data as application/x-www-form-urlencoded. Add to your src/api/middlewares.ts:

import { defineMiddlewares } from "@medusajs/framework/http"
import { urlencoded } from "express"

export default defineMiddlewares({
  routes: [
    // ... your existing routes
    {
      matcher: "/webhooks/cpay",
      method: ["POST"],
      middlewares: [urlencoded({ extended: true })],
    },
  ],
})

Environment variables

# Required
CPAY_MERCHANT_ID=123456                    # PayToMerchant value (from bank)
CPAY_MERCHANT_NAME=YourStoreName           # MerchantName (from bank)
CPAY_CHECKSUM_KEY=TEST_PASS                # TEST_PASS for testing, production key from bank
CPAY_CALLBACK_BASE_URL=https://api.example.com  # Your Medusa backend URL
CPAY_STOREFRONT_URL=https://example.com          # Your storefront URL

# Optional (defaults shown)
CPAY_PAYMENT_URL=https://www.cpay.com.mk/client/Page/default.aspx?xml_id=/mk-MK/.loginToPay/.simple/

Enable in Medusa Admin

Go to Settings > Regions > [Your Region] > Payment Providers and enable cpay.

Storefront Integration

See the storefront/ directory for reference implementations:

  • cpay-payment-button.tsx -- Hidden form + redirect button
  • cpay-callback-page.tsx -- Callback handler after cPay redirect

Payment Button

When cPay is selected, the payment button must create a hidden HTML form and submit it via POST. The form parameters come from session.data.cpay_form_params:

const activeSession = cart.payment_collection?.payment_sessions?.find(
  (s) => s.status === "pending"
)

if (isCPay(activeSession?.provider_id)) {
  const { cpay_form_params, cpay_payment_url } = activeSession.data

  return (
    <form ref={formRef} action={cpay_payment_url} method="POST">
      {Object.entries(cpay_form_params).map(([name, value]) => (
        <input key={name} type="hidden" name={name} value={value} />
      ))}
      <button type="submit">Pay with card</button>
    </form>
  )
}

Callback Page

Create a route at /payment/cpay/callback. The webhook redirects the browser here with query params:

| Param | Value | |-------|-------| | cpay_status | "success" or "fail" | | ref | Details2 reference | | error | Error message (on failure) |

On success, call your cart completion function (e.g., placeOrder()). On failure, show error with retry option.

Payment Info Map

export const paymentInfoMap = {
  pp_cpay_cpay: {
    title: "Pay with card",
    icon: <CreditCard />,
    description: "Pay online with debit or credit card via cPay.",
  },
}

export const isCPay = (providerId?: string) => providerId?.startsWith("pp_cpay")

Advanced: Using exports

The package exports utilities for custom integrations:

// Default: ModuleProvider (for medusa-config.ts)
import cpayProvider from "medusa-payment-cpay"

// Checksum utilities (for custom webhook handlers)
import { generateChecksum, validateReturnChecksum } from "medusa-payment-cpay/checksum"

// Types
import type { CPayOptions, CPaySessionData } from "medusa-payment-cpay"

Checksum Algorithm

Implements the MD5 checksum from cPay spec Appendix A:

Header      = NN + ParamName1,ParamName2,..., + LLL1LLL2...LLLN
InputString = Header + Value1 + Value2 + ... + ValueN + ChecksumAuthKey
CheckSum    = MD5(UTF-8(InputString))   // 32-char uppercase hex
  • Request checksum: merchant sends with payment request
  • Return checksum: cPay sends back (first two params swapped + cPayPaymentRef added)
  • Validation is mandatory -- without it, attackers could fake payments

Unit tests verify against both official examples from the specification.

Testing

# Run checksum tests
npm test
  1. Set CPAY_CHECKSUM_KEY=TEST_PASS for the testing period
  2. cPay provides a 1-month testing window from merchant definition
  3. Test transactions can be submitted from any domain during this period
  4. After going live, switch to the production key from the bank
  5. After going live, payments only work from your registered domain

Important Notes (from cPay spec)

| Rule | Detail | |------|--------| | No iframes/popups | cPay form must open as full page redirect | | Currency | Only MKD (Macedonian Denar) | | Amount format | Multiplied by 100, last two digits always 00 | | Details2 | Unique per payment, max 10 chars alphanumeric | | PUSH notifications | Only on ports 80/443, valid SSL, static IP | | Domain restriction | After test period, only registered domain works | | HTTP Referer | Must be present (form POST handles this) | | Forbidden chars | ' and @@ trigger IP block by cPay | | ReturnCheckSum | Must validate -- prevents fake success callbacks |

File Structure

medusa-payment-cpay/
  package.json
  tsconfig.json
  jest.config.js
  src/
    index.ts              # Main entry point + re-exports
    provider.ts           # ModuleProvider registration
    service.ts            # AbstractPaymentProvider implementation
    checksum.ts           # MD5 checksum generation & validation
    types.ts              # TypeScript types
    webhook.ts            # Webhook route (copy to src/api/webhooks/cpay/route.ts)
    __tests__/
      checksum.test.ts    # 13 tests against spec examples
  storefront/
    cpay-payment-button.tsx  # Reference: redirect button
    cpay-callback-page.tsx   # Reference: callback page

License

MIT