Beta / sandbox — no real money moves.
Trile

KHALTI · खल्ती

Can Khalti do recurring payments?

के खल्तीले पुनरावर्ती भुक्तानी गर्न सक्छ?

Khalti cannot charge a customer on a schedule, and Trile does not need it to. Khalti's developer documentation, checked on 27 August 2026, has two payment endpoints, /epayment/initiate/ and /epayment/lookup/, and neither charges a stored customer. Trile is subscription-billing infrastructure for Nepal. Because no card-on-file rail exists here, the customer pre-funds a wallet and Trile deducts each cycle from that balance. Khalti funds the wallet.

खल्तीले आफैं हरेक महिना पैसा काट्न सक्दैन। तर खल्तीबाट वालेटमा पैसा हाल्न मिल्छ, र त्यही ब्यालेन्सबाट हरेक चक्रमा कटौती हुन्छ।

Written by Pukar Khanal , Founder and engineer Published Last reviewed

Can Khalti charge a customer every month without them tapping anything?

No. Khalti has no recurring endpoint, no mandate call, and no way to store a customer for a later charge. Its documentation site publishes eight content pages. Searched on 27 August 2026, across the rendered pages and the Markdown sources in Khalti's own public repository, they contain zero occurrences of recurring, subscription, mandate, standing instruction, auto-debit, scheduled, or card on file. The word token appears twice, both times inside the "Invalid token." authentication error.

What Khalti does publish is a single-payment flow. Your server calls initiate, Khalti returns a payment_url, and the customer is redirected to a Khalti-hosted page to enter their mPIN. That redirect is the constraint. It needs a person, in a browser, on every charge. Trile works around it by moving the person to the front of the relationship instead of the front of every month.

One thing to know before you read the rest. Trile is in beta and runs in sandbox mode platform-wide. You can integrate and test end to end today. No real money moves until Trile completes Nepal Rastra Bank verification. Everything below describes the mechanism you build against with a nep_test_ key.

What does the Khalti ePayment API actually do?

It initiates one payment and lets you look up its status. Khalti calls the current version KPG-2, or Web Checkout. The base URL is https://dev.khalti.com/api/v2/ for sandbox and https://khalti.com/api/v2/ for production, and authorisation is a header in the form Authorization: Key <live_secret_key>. Amounts go in paisa as an integer. Below 1000 paisa the API rejects the request with "Amount should be greater than Rs. 10, that is 1000 paisa."

POST https://khalti.com/api/v2/epayment/initiate/
Authorization: Key <live_secret_key>
Content-Type: application/json

{
  "return_url": "https://example.com/payment/",
  "website_url": "https://example.com/",
  "amount": 49900,
  "purchase_order_id": "topup-2026-08-0417",
  "purchase_order_name": "Wallet top-up"
}

Khalti's own sample success response:

{
  "pidx": "bZQLD9wRVWo4CdESSfuSsB",
  "payment_url": "https://test-pay.khalti.com/?pidx=bZQLD9wRVWo4CdESSfuSsB",
  "expires_at": "2023-05-25T16:26:16.471649+05:45",
  "expires_in": 1800
}

What comes back after the customer pays?

You redirect the customer to payment_url. Khalti's sample shows expires_in of 1800 seconds, and the documentation separately states that in production the payment link expires in 60 minutes by default. When the customer finishes, Khalti sends a GET to your return_url carrying pidx, status, transaction_id, tidx, amount, mobile, purchase_order_id, purchase_order_name and total_amount. Khalti tells you to confirm with /epayment/lookup/ anyway, and warns that only Completed counts as success. The other documented statuses are Pending, Initiated, Refunded, Partially Refunded, Expired and User canceled.

Required fields on Khalti's POST /epayment/initiate/, quoted from Khalti's Web Checkout documentation
FieldRequiredWhat Khalti's documentation says
return_urlYes"Landing page after the transaction. Field must contain a URL."
website_urlYes"The URL of the website. Field must contain a URL."
amountYes"Total payable amount excluding the service charge. Amount must be passed in Paisa"
purchase_order_idYes"Unique identifier for the transaction generated by merchant"
purchase_order_nameYes"This is the name of the product."

Optional fields documented alongside these: customer_info, amount_breakdown, product_details, and any attribute prefixed merchant_. Source: docs.khalti.com/khalti-epayment/, read 27 August 2026.

Read that field list as a design statement. There is no customer identifier that persists, no plan, no interval, no next-charge date. Every call is a fresh order. Khalti also documents a refund call at /api/merchant-transaction/{transaction_id}/refund/, which takes a transaction that already happened. Nothing in the set points forward in time.

Why is there no recurring endpoint in Khalti's API?

Because Khalti has no self-serve mandate to call. A recurring charge on a card works by re-presenting a stored credential against a mandate the customer granted once. Stripe Billing and Chargebee are built on that assumption from the first line of their data model. Khalti exposes nothing equivalent to a merchant, so a Khalti recurring endpoint would have to fall back to messaging the customer and waiting, which is a product decision rather than an API. Khalti is not behind here. It built the flow the country's payment rails allow.

Does that mean no mandate exists anywhere in Nepal?

No, and the blanket version of that claim is wrong. Mandates do exist in Nepal. NCHL documents that NEPALPAY Request "also supports recurring e-Mandate payments for a specified frequency and time period, whereby on due date the standing instruction amount will be debited from the payer and credited to payee", and that "E-Mandates can be used for recurring service payments as an option for AutoPay or AutoDebit". eSewa separately runs a customer-controlled scheduled payment for its own biller catalogue. What is missing is a self-serve merchant API. Access runs through member banks and payment service providers, and Khalti publishes no merchant-facing mandate call at all.

The rail-by-rail answer belongs on its own page. Read is auto-debit available in Nepal for how bank standing instructions, ConnectIPS and Fonepay compare, and the eSewa page for what eSewa's Scheduled Payment does and does not do. Neither of those is a call a subscription business can make from its own backend.

Does the Khalti and Stripe partnership solve recurring billing?

No, and it is aimed at a different problem entirely. On 20 April 2026 Khalti published "Bridging the Global Gap: Receive International Payments Directly in Your Khalti Wallet via Stripe". The flow runs one way: a Nepali user generates a payment link, sends it to a client abroad, and that client pays with Google Pay, Apple Pay, Visa, Mastercard, or an international bank account. The money converts and lands in the recipient's Khalti wallet in NPR. Khalti's post lists the requirements as a PAN number and occupation for the receiver, and a one-time liveness and document check for the sender.

That fixes something genuinely broken. Freelancers and small exporters in Nepal spent years routing payments through SWIFT intermediaries and waiting days for settlement, and it explains why the partnership dominates search results for Nepali payment queries.

It is still the wrong tool for a subscription business in Kathmandu billing Nepali customers in NPR. That business needs to charge the same local customer on the same date every month without asking. The Stripe integration needs a payer outside Nepal to act on each payment. Two different problems, and the search results for "Stripe Nepal" mix them constantly. The Stripe alternative for Nepal page separates them properly.

Which Khalti product fits which job?

Khalti ships four distinct things that people conflate, and only one of them touches money on a schedule, which is Trile's rather than Khalti's. Khalti and IME Pay merged, and khalti.com now describes itself as "Nepal's first unified payment platform bringing together Khalti and IME Pay", so IME Pay balances and Khalti balances sit behind the same brand.

The consumer-app row is worth pausing on, because eSewa and Khalti differ here. eSewa publishes a Scheduled Payment feature that genuinely deducts from the customer's own eSewa balance on a date they set, for a closed list of billers eSewa controls. Khalti's consumer service pages and support pages, read on 27 August 2026, publish no equivalent. Neither one is reachable from a merchant backend, so neither one is a way to bill a subscription, but do not flatten the two wallets into the same answer.

Khalti products against the job each one does, August 2026 खल्तीका उत्पादन र तिनले गर्ने काम
ProductWhat it is forWho acts to move moneyCharges on a schedule
Khalti wallet, consumer appPaying bills and merchants from a balanceThe wallet holder, per paymentNo
Khalti ePayment API, KPG-2One-time online collection on a merchant siteThe customer, per payment, by redirect and mPINNo
Khalti Refund APIReturning a transaction that already completedThe merchantNot applicable
Khalti payment link via StripeReceiving money from a payer outside NepalThe foreign payer, per paymentNot documented
Trile wallet deductionBilling an NPR subscription each cycleNobody, once the wallet is fundedYes

Compiled from docs.khalti.com, blog.khalti.com and khalti.com, read 27 August 2026. Trile row from docs.trile.app.

Aggregators sit in the same row as Khalti's own API rather than above it. APINepal, for instance, describes itself as "one payment API for eSewa, Khalti & Fonepay". Putting three one-time collection rails behind one integration saves work, and it still leaves you with three one-time collection rails. Scheduling is not a feature you get by combining gateways that do not have it.

How does Khalti work as a top-up source for Trile?

Khalti moves the money in once, and Trile moves it out on a cycle. Trile is subscription-billing infrastructure for Nepal. Because no card-on-file rail exists here, the customer pre-funds a wallet and Trile deducts each cycle from that balance. Khalti is one of four ways a customer funds that wallet, alongside eSewa, IME Pay, and bank transfer.

Read the direction carefully, because this is where comparisons go wrong. Trile does not pull from a Khalti balance. It has no way to and no permission to. The balance Trile deducts from is a Trile wallet, held by Trile, that the customer funded by making one ordinary Khalti payment. Anyone describing that as auto-debiting a Khalti wallet has described a different mechanism, and a developer will notice within one integration.

The Khalti call is the same initiate-and-lookup flow every merchant uses. The difference is what the payment is for. It is not a month of service. It is a balance. A customer on a NPR 499.00 monthly plan who tops up NPR 3,000.00 has bought six renewals with one mPIN entry. Each of those six renewals is a ledger movement inside Trile against money that is already there, so nothing is re-authorised and nothing can decline.

Collect through Khalti each cycleredirect + mPINredirect + mPINredirect + mPINmonth 1month 2month 3Customer acts three times. Three chances to stop.Top up once through Khalti, deduct each cycleredirect + mPINledger deductionledger deductionledger deductiontop-upmonth 1month 2month 3
Khalti as a top-up source for a Trile wallet. The Khalti redirect happens at funding time, not at renewal time, so the number of customer actions stops scaling with the number of billing cycles.

What does the integration look like for a developer?

You integrate Khalti once, on the top-up path, and you never call it from your billing code. On the Khalti side you do exactly what the Web Checkout page describes: initiate server-side, redirect, handle the callback, confirm with lookup, and treat only Completed as paid. On the Trile side you create a Product, a Price, a Customer and a Subscription, and each write carries an Idempotency-Key header so a retry cannot double-charge a wallet.

One unit detail catches people. Khalti wants amount as an integer in paisa. Trile stores money as integer paisa in a string, so NPR 499.00 is "49900", which keeps the value exact through JSON and through any language that would otherwise hand you a float. Same unit, different carrier type. Convert deliberately at the boundary rather than letting a JSON parser decide. The Trile API reference and the how Trile works page cover the object model, and the subscription billing API page covers idempotency, signed webhooks and reconciliation in depth.

What does the customer actually do each cycle?

Nothing, until the balance runs low. On the renewal date Trile draws the invoice against the wallet and the subscription stays active. If the balance is short, the invoice stays open, the subscription moves to past_due, and a webhook fires. The customer tops up again through Khalti, eSewa, IME Pay, or a bank transfer, and the subscription recovers. past_due is a normal recoverable state, not an incident.

That is a different collection model from the reminder-and-link approach SUQO describes on its own site, where an SMS goes out, the customer taps a link, and pays through a wallet each cycle. Both models are honest about Nepal's rails. They differ in when the customer acts: at every renewal, or once at funding time. The recurring payments in Nepal page compares the two properly, and the eSewa page runs the same analysis on the other big wallet.

What could not be verified from Khalti's own documentation?

Three things, stated plainly so nobody has to guess which claims here are sourced.

  • Fees and merchant discount rates. Khalti's lookup response returns a fee field described as "The fee that has been set for the merchant", and the FAQ page tells testers to set a fee between Rs. 10 and Rs. 200 in sandbox. No public rate card was found, so no fee figure appears on this page.
  • Limits and pricing on the Stripe payment link. Khalti's announcement post publishes no transaction limit, no exchange-rate margin and no fee, and the Nepali trade coverage of the launch adds none. Absence of a published limit is not the same as no limit, so this page states neither.
  • Whether any Khalti biller service, such as the SIP entry in Khalti's separate service API catalogue, involves a scheduled debit behind the scenes. That catalogue lists utility, insurance, EMI and booking services. It exposes no recurring, mandate or scheduling call to merchants, which is the question this page answers.

Has anyone outside Trile reached the same conclusion?

Yes. The Drupal Commerce Khalti module, version 2.0.0, released 24 June 2026, answers the question "Is the module compatible with Commerce Recurring / Subscriptions?" in its own project FAQ:

"Not currently. Khalti ePay v2 does not support automatic recurring charges."

Read that as a description of the rail, not a criticism of Khalti. A maintainer who wires payment gateways into subscription software for a living checked, found no recurring capability, and said so. It is also why Trile is subscription-billing infrastructure for Nepal: because no card-on-file rail exists here, the customer pre-funds a wallet and Trile deducts each cycle from that balance. Khalti gets the money in. The ledger does the rest.

Common questions

Does Khalti support recurring payments or subscriptions?

के खल्तीले सब्स्क्रिप्सन वा पुनरावर्ती भुक्तानी सपोर्ट गर्छ?

No. Khalti publishes no recurring, subscription, mandate, or standing-instruction endpoint. Its documentation covers one-time collection through /epayment/initiate/ and /epayment/lookup/, plus a refund call. The Drupal Commerce Khalti module, version 2.0.0, released 24 June 2026, answers the same question in its own FAQ: "Not currently. Khalti ePay v2 does not support automatic recurring charges."

Does the Khalti and Stripe partnership let me bill Nepali customers monthly?

No, and it does not claim to. Khalti announced the Stripe integration on 20 April 2026 for receiving money from outside Nepal. A payer abroad uses a card, Apple Pay, Google Pay, or an international bank account, and the amount lands in a Khalti wallet in NPR. That is inbound cross-border collection, not domestic scheduled billing.

What is the minimum amount the Khalti ePayment API accepts?

One thousand paisa. Khalti validates the amount field and returns "Amount should be greater than Rs. 10, that is 1000 paisa." with error_key validation_error when the value is lower. The amount must be an integer in paisa, not rupees. A wrong unit here is the most common first-integration bug on this API.

Can I save a Khalti customer and charge them later?

Not through anything Khalti documents publicly. There is no tokenisation, saved-instrument, or card-on-file call in the ePayment documentation. Every collection starts with a server-side initiate, produces a fresh pidx, and sends the customer to a Khalti-hosted payment page where they enter an mPIN. The customer is present for each charge.

How does Trile bill on a schedule if Khalti cannot?

खल्तीले नसक्दा ट्रिलेले कसरी हरेक चक्रमा बिल गर्छ?

Trile does not ask Khalti to charge anything, and it never pulls from a Khalti balance. The customer uses Khalti once to move money into a Trile wallet. After that, each renewal is a deduction inside the Trile ledger against a balance the customer already funded. No payment attempt leaves Trile, so nothing can decline and no mandate rail is involved.

Who wrote this, and how it was checked

Author
Pukar Khanal , Founder and engineer
Last reviewed

Reviewed against the Trile API docs at each release. Corrections go to support@trile.app.

Experience
Trile is in beta and runs in sandbox mode platform-wide. You can integrate and test end to end today. No real money moves until Trile completes Nepal Rastra Bank verification. The Trile team built Khalti's Web Checkout as a wallet top-up path alongside eSewa, IME Pay, and bank transfer, and reconciles every top-up against Khalti's lookup response. Every Khalti claim on this page was checked against docs.khalti.com and its public source repository on 27 August 2026, not against a summary of it.

What to ask next

Start in test mode

Create an account, grab your nep_test_ keys, and run a wallet-funded subscription end to end before a rupee moves.