Drupal is a registered trademark of Dries Buytaert
Protected Pages 3.0.0 Major update available for module protected_pages (3.0.0). Commerce Core 3.3.8 Minor update available for module commerce (3.3.8). Layout Builder Reorder 2.0.1 Minor update available for module layout_builder_reorder (2.0.1). Ban 1.1.0 Minor update available for module ban (1.1.0). Field Formatter Range 2.0.0 Major update available for module field_formatter_range (2.0.0). Field Formatter Range 8.x-1.8 Minor update available for module field_formatter_range (8.x-1.8). UI Patterns (SDC in Drupal UI) 2.0.18 Minor update available for module ui_patterns (2.0.18). Varbase FAQs 9.2.1 Minor update available for module varbase_faqs (9.2.1). Search API Solr 4.3.11 Module search_api_solr updated after 14 months of inactivity (4.3.11). Provus Mega Menu Module provus_mega_menu crossed 1,000 active installs.

Khalti

No security coverage
View on drupal.org

This module integrates Drupal Commerce with the Khalti ePay API to allow customers to pay online using Nepalese Rupees. It redirects customers to Khalti's secure payment page and verifies transactions server-side before updating the order status.

Integrates the Khalti ePay v2 API (KPG-2) with Drupal Commerce, enabling merchants to accept online payments in Nepalese Rupees (NPR) on Drupal 10 and 11 sites via an offsite redirect checkout flow.

Khalti is Nepal's leading digital wallet, payment gateway, and banking API provider. This Drupal module uses the Khalti ePay v2 Web Checkout (KPG-2) to redirect customers to a Khalti-hosted payment page, then verifies the payment server-side via the Khalti Lookup API before updating the order status.

Key design principles:

  • Server-side payment initiation — the secret key never leaves your server.
  • Lookup API verification on return — callback query parameters are never trusted alone.
  • All seven Khalti payment statuses are handled explicitly.
  • Orders are always unlocked after the redirect, regardless of outcome.

Supported Payment Methods

Method Notes Khalti wallet Available to all Khalti users eBanking Khalti-partnered banks only Mobile banking Khalti-partnered banks only SCT / VISA cards Requires separate approval from Khalti ConnectIPS Available to all ConnectIPS users

Requirements

Dependency Version Link Drupal core 10.x or 11.x drupal.org/project/drupal PHP 8.1 or higher php.net Drupal Commerce 3.x drupal.org/project/commerce Khalti merchant account — admin.khalti.com (live) / test-admin.khalti.com (sandbox)

Currency: Your Commerce store must use NPR (Nepalese Rupee). Khalti only accepts NPR and requires amounts expressed in paisa (1 NPR = 100 paisa; minimum Rs. 10 = 1000 paisa).

  • Commerce Cart and Commerce Checkout — included with Drupal Commerce; required for the standard checkout flow.
  • Commerce Log — logs order state transitions for audit purposes.

Installation

Option A — Composer (recommended)

	
composer require drupal/khalti
drush en khalti
drush cr

Option B — Manual

  1. Download the module archive from drupal.org/project/khalti.
  2. Extract it to modules/contrib/khalti (or modules/custom/khalti for a custom copy).
  3. Go to Administration › Extend ( /admin/modules).
  4. Find Khalti, tick the checkbox, and click Install.
  5. Run drush cr or clear caches at Administration › Performance.

Configuration

Step 1 — Enable NPR currency

  1. Go to Administration › Commerce › Configuration › Currencies ( /admin/commerce/config/currencies).
  2. If NPR is not listed, click Add currency, search for Nepalese Rupee (NPR), and save.

Step 2 — Set store currency to NPR

  1. Go to Administration › Commerce › Configuration › Stores ( /admin/commerce/config/stores).
  2. Edit your store and set the Default currency to NPR.
  3. Save.

Step 3 — Add a Khalti payment gateway

  1. Go to Administration › Commerce › Configuration › Payment Gateways ( /admin/commerce/config/payment-gateways).
  2. Click Add payment gateway.
  3. Fill in the form:
    Field Value Name Khalti (or any label) Plugin Khalti Payment Mode Test for sandbox · Live for production Test Secret Key Your sandbox live_secret_key from test-admin.khalti.com Live Secret Key Your production live_secret_key from admin.khalti.com
  4. Save.

Note: Khalti's Authorization header uses the format Key <secret_key> — not Bearer. The module handles this automatically.

Step 4 — Verify the checkout flow

  1. Go to Administration › Commerce › Configuration › Checkout Flows ( /admin/commerce/config/checkout-flows).
  2. Edit your checkout flow and confirm the Payment and Payment Process panes are present and in the correct order.

Sandbox Testing

The Khalti sandbox environment is completely isolated from production. No real money moves.

1. Get sandbox credentials

Sign up at test-admin.khalti.com/#/join/merchant or log in if you already have an account. Copy the live_secret_key from the sandbox merchant dashboard.

2. Configure the gateway in Test mode

Follow Step 3 of Configuration, set Mode → Test, and paste the sandbox key into Test Secret Key.

3. Place a test order

Add any product to the cart, proceed to checkout, and select Khalti as the payment method.

4. Sandbox payment credentials

Field Value(s) Khalti IDs 9800000000, 9800000001, 9800000002, 9800000003, 9800000004 MPIN 1111 Transaction OTP 987654 Login OTP 987654

5. View transactions

Go to Administration › Commerce › Khalti ( /admin/commerce/khalti) to see all recorded transactions. You can view details, edit, or delete records from here.

Note: The Khalti payment link expires in 60 minutes in production (sandbox links may differ).

Going Live

  1. Create a production merchant account at admin.khalti.com.
  2. Complete the merchant agreement and KYC verification with the Khalti business team.
  3. The Khalti team will generate and share your production live_secret_key.
  4. In Drupal, edit your payment gateway, switch Mode → Live, and enter the production key in Live Secret Key.
  5. Place a real low-value test transaction (e.g. Rs. 10) end-to-end.
  6. Contact the Khalti business team to raise transaction limits and agree on fee slabs.

How It Works

Payment flow

  1. Customer adds a product to cart and proceeds to checkout.
  2. Customer selects Khalti as the payment method and clicks Pay.
  3. Module calls POST /api/v2/epayment/initiate/ server-side → receives payment_url and pidx.
  4. Customer is redirected to pay.khalti.com (or dev.khalti.com in sandbox).
  5. Customer completes or cancels payment on the Khalti-hosted page.
  6. Khalti redirects back to /khalti/success/{token}?pidx=…&status=…
  7. Module calls POST /api/v2/epayment/lookup/ with the pidx to verify the payment status server-side.
  8. Order and payment status are updated; customer is forwarded to the result page.

API endpoints

Endpoint Method Purpose /api/v2/epayment/initiate/ POST Create a payment request; returns payment_url and pidx /api/v2/epayment/lookup/ POST Verify payment status by pidx — always call before granting service
  • Sandbox base URL:
    https://dev.khalti.com
  • Production base URL:
    https://khalti.com

Amount conversion

Commerce stores prices in NPR. Khalti requires amounts as integer paisa:

	amount_paisa = (int) round(order_total_NPR × 100)

Minimum accepted value: Rs. 10 → 1000 paisa.

Security

Measure Description CSRF token A random session token is generated at checkout initiation and verified when Khalti redirects back. Mismatched tokens return HTTP 403. Lookup API verification The module always calls the Lookup API server-side. The status query parameter in the callback URL is never trusted alone. Order unlock Orders are unlocked after every redirect return (success, cancel, or error), preventing permanently locked orders.

Payment Statuses

All seven statuses returned by the Khalti Lookup API are handled:

Khalti Status Order State Meaning Completed Completed Payment confirmed ✓ — safe to grant service Pending Pending Not yet settled — do not grant service; contact Khalti support Initiated Cancelled Customer never reached the Khalti payment page User canceled Cancelled Customer pressed cancel on the Khalti page Expired Cancelled Payment link timed out (60 min in production) Refunded Cancelled Payment fully reversed by Khalti Partially Refunded Cancelled Partial refund issued — do not grant full service

Rule: Only Completed should trigger order fulfilment.

Hooks for Developers

See khalti.api.php for full documentation of all available hooks.

hook_khalti_customer_info_alter(array &$customer_info)

Alter the customer information sent to Khalti during payment initiation. Blank values are stripped automatically before the API call.

	
<?php
/**
 * Implements hook_khalti_customer_info_alter().
 */
function mymodule_khalti_customer_info_alter(array &$customer_info): void {
  // Example: pull phone number from a custom customer profile field.
  $account = \Drupal::currentUser();
  $profiles = \Drupal::entityTypeManager()
    ->getStorage('profile')
    ->loadByProperties(['uid' => $account->id(), 'type' => 'customer']);
  if ($profile = reset($profiles)) {
    $customer_info['phone'] = $profile->get('field_phone')->value ?? '';
  }
}
Key Type Required Description name string Yes Customer full name email string No Customer email address phone string No Customer phone number

hook_khalti_success_message(string &$message)

Override the on-screen success message shown after a completed payment.

	
<?php
/**
 * Implements hook_khalti_success_message().
 */
function mymodule_khalti_success_message(string &$message): void {
  $message = 'Thank you! Your Khalti payment was received successfully.';
}

Troubleshooting

Always start by checking Administration › Reports › Recent log messages ( /admin/reports/dblog), filtered by type khalti.

"An error occurred while initiating Khalti payment"

Likely cause Solution Invalid secret key Verify the key in your Khalti dashboard. It must match the selected mode (test vs. live). Amount below minimum Ensure the order total is at least Rs. 10 (1000 paisa). Currency not NPR Set the store default currency to NPR. Server cannot reach Khalti API Check outbound firewall rules — HTTPS must be allowed to dev.khalti.com and khalti.com.

"Your session has expired or is invalid"

The checkout session was lost between redirect and return.

  • Ensure the PHP session lifetime is long enough (at least 10–15 minutes).
  • If you use a CDN or reverse proxy, confirm session cookies are not stripped on the return URL path ( /khalti/success/*).
  • Ensure trusted_host_patterns in settings.php allows the return URL host.

"Payment verification failed" / empty API response

  • The Khalti API returned an empty body — check Drupal logs for the HTTP status code.
  • In sandbox, confirm the pidx belongs to the current session; pidx values cannot be reused.
  • Verify the server clock is accurate — Khalti tokens are time-sensitive.

"This order is locked and cannot be edited"

Unlock from Administration › Commerce › Orders, or via Drush:

	
drush php:eval "
\$order = \Drupal\commerce_order\Entity\Order::load(ORDER_ID);
if (\$order && \$order->isLocked()) {
  \$order->unlock();
  \$order->save();
  echo 'Order ' . ORDER_ID . ' unlocked.';
}
"

Payment shows as Pending indefinitely

Pending means Khalti has received the payment but it is not yet settled with the bank. Do not fulfil the order. Contact Khalti merchant support with the pidx and transaction_id from the Khalti Transactions admin page.

FAQ

Can I use multiple currencies?
No. Khalti only accepts NPR. Multi-currency stores must convert totals to NPR before initiating a Khalti payment.
Is the customer redirected away from my site?
Yes. Khalti ePay v2 is an offsite/hosted checkout. The customer leaves your site, pays on Khalti's page, and is redirected back.
What happens if the customer closes the browser on the Khalti page?
The payment link expires after 60 minutes. The module receives a status of Expired or Initiated and cancels the order, allowing the customer to retry.
Are refunds handled automatically?
The module detects Refunded and Partially Refunded from the Lookup API and cancels the order. Refund initiation must be done from the Khalti merchant dashboard.
Where are Khalti transactions stored?
Each verified payment creates a KhaltiTransaction entity. View them at Administration › Commerce › Khalti ( /admin/commerce/khalti).
Is the module compatible with Commerce Recurring / Subscriptions?
Not currently. Khalti ePay v2 does not support automatic recurring charges.

Contact Khalti

Channel Details Business enquiries [email protected] · +977 9801165557 Merchant technical support [email protected] · 9801301162 · 9801165565
(Viber / WhatsApp) API documentation docs.khalti.com/khalti-epayment/ Sandbox admin test-admin.khalti.com Production admin admin.khalti.com

Activity

Total releases
4
First release
Dec 2024
Latest release
3 weeks ago
Releases (12 mo)
2
Maintenance
Active

Release Timeline

Releases

Version Type Release date
2.0.0 Stable Jun 24, 2026
2.0.x-dev Dev Jun 24, 2026
1.0.2 Stable Dec 4, 2024
1.0.1 Stable Dec 4, 2024