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

@promactinfo/medusa-payment-phonepe

v2.5.0

Published

PhonePe payment provider for Medusa Commerce

Readme

MEDUSA-PAYMENT-PHONEPE

PhonePe Payment provider for MedusaJS v2.x

PHONEPE is an immensely popular payment gateway with a host of features. This plugin enables the PhonePe payment interface on MedusaJS v2.x commerce stack.

Version

v2.0.0 - This version is compatible with:

  • MedusaJS v2.x
  • PhonePe Payment Gateway API v2 (with OAuth authentication)

Installation

Install the plugin using your package manager:

yarn add medusa-payment-phonepe
# or
npm install medusa-payment-phonepe
# or
pnpm add medusa-payment-phonepe

Prerequisites

  • MedusaJS v2.x installed and running
  • PhonePe merchant account with:
    • Merchant ID
    • Salt key (for webhook verification)
    • OAuth Client ID
    • OAuth Client Secret

Configuration

Environment Variables

Add the following to your .env file:

PHONEPE_SALT=<your-supplied-salt>
PHONEPE_MODE=production|uat|test
PHONEPE_MERCHANT_ID=<your-merchant-id>
PHONEPE_CLIENT_ID=<your-oauth-client-id>
PHONEPE_CLIENT_SECRET=<your-oauth-client-secret>
PHONEPE_REDIRECT_URL=<your-redirect-url>
PHONEPE_CALLBACK_URL=<your-callback-url>
PHONEPE_MERCHANT_USERNAME=<your-merchant-username>  # Required for webhook validation
PHONEPE_MERCHANT_PASSWORD=<your-merchant-password>  # Required for webhook validation

MedusaJS Configuration

Add the plugin to your medusa-config.ts (or medusa-config.js):

import { defineConfig } from "@medusajs/framework/utils";

export default defineConfig({
  // ... other config
  plugins: [
    // ... other plugins
    {
      resolve: "medusa-payment-phonepe",
      options: {
        redirectUrl:
          process.env.PHONEPE_REDIRECT_URL ||
          "http://localhost:8000/api/payment-confirmed",
        callbackUrl:
          process.env.PHONEPE_CALLBACK_URL ||
          "http://localhost:9000/phonepe/hooks",
        salt: process.env.PHONEPE_SALT,
        merchantId: process.env.PHONEPE_MERCHANT_ID,
        clientId: process.env.PHONEPE_CLIENT_ID,
        clientSecret: process.env.PHONEPE_CLIENT_SECRET,
        clientVersion: 1, // PhonePe client version (typically 1)
        mode:
          (process.env.PHONEPE_MODE as "production" | "uat" | "test") || "test",
        merchantUsername: process.env.PHONEPE_MERCHANT_USERNAME, // Required for webhook validation
        merchantPassword: process.env.PHONEPE_MERCHANT_PASSWORD, // Required for webhook validation
        tokenCacheEnabled: true, // Optional: Enable OAuth token caching (default: true)
        enabledDebugLogging: false, // Optional: Enable debug logging
      },
    },
  ],
});

Configuration Options

| Option | Type | Required | Description | | --------------------- | ------- | ----------- | --------------------------------------------------------------------- | | redirectUrl | string | Yes | URL to redirect customers after payment | | callbackUrl | string | Yes | Server-to-server webhook callback URL | | salt | string | Yes | PhonePe provided salt key (legacy, kept for backward compatibility) | | merchantId | string | Yes | Your PhonePe merchant ID | | clientId | string | Yes | OAuth client ID for PhonePe API v2 | | clientSecret | string | Yes | OAuth client secret for PhonePe API v2 | | clientVersion | number | Yes | PhonePe client version (typically 1) | | mode | string | Yes | production, uat, or test | | merchantUsername | string | Recommended | Merchant username for webhook validation (recommended for production) | | merchantPassword | string | Recommended | Merchant password for webhook validation (recommended for production) | | tokenCacheEnabled | boolean | No | Enable OAuth token caching (default: true) | | enabledDebugLogging | boolean | No | Enable debug logging (default: false) |

API Endpoints

The plugin uses PhonePe Payment Gateway API v2 with the following endpoints:

  • Payment Creation: /checkout/v2/pay
  • Order Status: /checkout/v2/order/{merchantOrderId}/status
  • Refund: /checkout/v2/refund
  • OAuth Token: /v1/oauth/token

Webhook Events

The plugin supports the following PhonePe webhook events:

  • checkout.order.completed (PG_ORDER_COMPLETED) - Payment succeeded
  • checkout.order.failed (PG_ORDER_FAILED) - Payment failed
  • pg.refund.completed (PG_REFUND_COMPLETED) - Refund completed
  • pg.refund.failed (PG_REFUND_FAILED) - Refund failed

Webhook Validation

The plugin uses PhonePe's official SDK (pg-sdk-node) for webhook validation. The SDK's validateCallback method is used to verify the authenticity of webhook callbacks from PhonePe.

Recommended Configuration:

  • Set merchantUsername and merchantPassword in your configuration to enable SDK-based webhook validation
  • The plugin will automatically use the SDK's validation method when these credentials are provided
  • If credentials are not provided, the plugin falls back to legacy signature-based validation

Webhook Endpoint:

  • Default endpoint: /phonepe/hooks
  • Configure this URL in your PhonePe merchant dashboard as the callback URL

Migration from v1.x to v2.x

Breaking Changes

  1. MedusaJS Version: Requires MedusaJS v2.x (no backward compatibility with v1.x)
  2. OAuth Authentication: PhonePe API v2 requires OAuth authentication (clientId and clientSecret)
  3. API Endpoints: Updated to PhonePe API v2 endpoints
  4. Configuration: New required fields (clientId, clientSecret)

Migration Steps

  1. Upgrade MedusaJS: Ensure your MedusaJS installation is upgraded to v2.x

  2. Update Plugin Version: Install the latest version of the plugin:

    yarn add medusa-payment-phonepe@^2.0.0
  3. Obtain OAuth Credentials: Get your OAuth Client ID and Client Secret from PhonePe dashboard

  4. Update Configuration: Add OAuth credentials to your plugin configuration:

    {
      resolve: "medusa-payment-phonepe",
      options: {
        // ... existing options
        clientId: process.env.PHONEPE_CLIENT_ID, // NEW
        clientSecret: process.env.PHONEPE_CLIENT_SECRET, // NEW
      },
    }
  5. Update Environment Variables: Add OAuth credentials to your .env file

  6. Test Integration: Test the payment flow in UAT mode before going to production

Client-Side Integration

Next.js Example

For Next.js applications, create a payment confirmation route:

// app/api/payment-confirmed/route.ts
import { NextRequest, NextResponse } from "next/server";
import { medusaClient } from "@lib/config";

export async function POST(request: NextRequest) {
  const data = await request.formData();
  const merchantOrderId = data.get("merchantOrderId") as string;
  const code = data.get("code") as string;

  if (!merchantOrderId || code !== "SUCCESS") {
    return NextResponse.redirect(new URL("/cart", request.url));
  }

  // Extract cart ID from merchantOrderId (format: cartId_sequence)
  const cartIdParts = merchantOrderId.split("_");
  const cartId = `${cartIdParts[0]}_${cartIdParts[1]}`;

  try {
    // Wait for order to be created by webhook
    let orderId;
    let attempts = 0;
    while (!orderId && attempts < 10) {
      await new Promise((resolve) => setTimeout(resolve, 1000));
      try {
        const order = await medusaClient.orders.retrieveByCartId(cartId);
        orderId = order.order.id;
      } catch (e) {
        attempts++;
      }
    }

    if (orderId) {
      return NextResponse.redirect(
        new URL(`/order/confirmed/${orderId}`, request.url)
      );
    }
  } catch (error) {
    console.error("Payment confirmation error:", error);
  }

  return NextResponse.redirect(new URL("/cart", request.url));
}

Features

  • ✅ OAuth authentication for PhonePe API v2
  • ✅ Automatic token caching and refresh
  • ✅ Payment initiation and status checking
  • ✅ Webhook handling for payment events
  • ✅ Refund support
  • ✅ Multiple payment modes (UPI, Cards, Net Banking)
  • ✅ UAT and Production mode support

Testing

UAT Mode

Set mode: "uat" in your configuration to test against PhonePe's UAT environment:

{
  mode: "uat",
  // ... other options
}

Test Mode

Set mode: "test" for local testing (mocked responses).

Troubleshooting

OAuth Token Issues

If you encounter OAuth authentication errors:

  1. Verify your clientId and clientSecret are correct
  2. Check that your PhonePe account has API access enabled
  3. Ensure your environment variables are properly loaded

Webhook Issues

If webhooks are not being received:

  1. Verify your callbackUrl is publicly accessible
  2. Check webhook signature verification
  3. Ensure your salt key matches PhonePe dashboard

Payment Status Issues

If payment status checks fail:

  1. Verify the merchantOrderId format
  2. Check that the order exists in PhonePe system
  3. Review debug logs (enable enabledDebugLogging: true)

Contributing

Pull requests are welcome! For major changes, please open an issue first to discuss what you would like to change.

Please make sure to:

  • Update tests as appropriate
  • Follow the existing code style
  • Update documentation for any API changes

License

MIT

Support

For issues and questions:

Disclaimer

The code was tested on a limited number of usage scenarios. There may be unforeseen bugs. Please raise issues as they come, or create pull requests if you'd like to submit fixes.