Beta / sandbox — no real money moves.
Trile

BILLING API · बिलिङ एपीआई

Is there a subscription billing API for Nepal?

के नेपालका लागि सब्स्क्रिप्शन बिलिङ API छ?

Yes. 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. The API is REST at https://api.trile.app/v1, every amount is integer paisa as a string, so NPR 499.00 is 49900, and every write is rejected without an Idempotency-Key header.

छ। रकम पूर्णांक पैसामा स्ट्रिङका रूपमा जान्छ, र हरेक राइटमा idempotency key अनिवार्य छ।

Written by Pukar Khanal , Founder and engineer Published Last reviewed

Is there a subscription billing API for Nepal?

Yes, and there is more than one. Trile exposes a REST API at https://api.trile.app/v1 that models products, prices, customers, subscriptions and invoices, and bills each cycle by debiting a Trile wallet the customer funded in advance. SUQO publishes a subscription billing API whose create call returns a checkout_url and a pending_checkout status, because its collection model asks the customer to pay through a link each cycle. APINepal describes itself as "one payment API for eSewa, Khalti and Fonepay", with hosted checkout, payment links and signed webhooks. That is collection. It does not schedule the next charge. The difference that reaches your code is not the endpoint list. It is whether a renewal needs a person to act.

मुख्य फरक: नवीकरणका बेला मान्छेले केही गर्नुपर्छ कि पर्दैन।

That question has its own page, because the real answer is narrower than the one currently indexed: is auto-debit possible in Nepal?

What does the Trile API object model look like?

Six objects, and the shape is familiar if you have used Stripe. A product is the thing you sell. A price pins an amount and an interval onto that product, so amountPaisa: "49900" with interval: "month" is NPR 499.00 a month. A customer is who you bill, and every customer owns one Trile wallet, a balance held by Trile that the customer pre-funded through eSewa, Khalti, IME Pay or bank transfer. Trile debits that balance. It cannot reach into the customer's own eSewa or Khalti account. A subscription binds a customer to a price. An invoice is one cycle's statement, generated by the billing engine and paid by debiting that Trile wallet. Subscriptions reference a price, never a product, which is what lets one product carry a monthly and an annual price at once. Every object carries a prefixed ULID such as sub_01ARZ3NDEKTSV4RRFFQ69G5FAZ, so a log line tells you the type without a lookup, and IDs sort lexicographically by creation time.

Productprod_Priceprice_Subscriptionsub_Invoiceinv_Customercus_Walletwal_has manyused bygeneratesownsdebited each cycle to pay the invoiceWHAT YOU SELLWHO PAYS, AND FROM WHAT BALANCE
The Trile API object model. A subscription references a price and generates an invoice each cycle; the invoice is paid by debiting the customer's prepaid Trile wallet rather than by charging a card.

How does the Trile API represent money?

As integer paisa, serialized as a string. NPR 499.00 goes over the wire as "49900", never as 499, never as 499.00, and never as a JSON number. There are two reasons. A string cannot be quietly coerced into a float by a JSON parser, and it survives values past Number.MAX_SAFE_INTEGER, which a rupee-denominated ledger reaches sooner than most people expect. The currency field is always present and is NPR in v1. Convert at the display edge with BigInt and integer division, and never inside billing code. One parseFloat in the wrong place is how billing systems lose money, and it is the most common defect in a hand-rolled implementation.

Are idempotency keys required on the Trile API?

Yes, on every write. A POST, PATCH or DELETE to /v1 without an Idempotency-Key header returns 400 idempotency_required. Keys are client-generated, up to 255 characters, scoped per business, and stored for 24 hours. A UUID is the normal choice. On a repeat, Trile returns the stored response without re-executing, including when the original was a 5xx. That is the property that makes a timeout safe: retry with the same key and either the work happens once, or you get back the answer it already gave. Reuse a key with a different body and you get 422 idempotency_error, because the body is fingerprinted. Send it again while the first is still running and you get 409 request_in_progress.

curl -s "https://api.trile.app/v1/subscriptions" \
  -H "x-api-key: nep_test_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "customerId": "cus_01ARZ3...", "priceId": "price_01ARZ3..." }'

Three headers on every authenticated write, documented in full under idempotency and authentication.

What does a Trile API response look like?

Every /v1 response is wrapped in the same envelope. Success carries success: true, the object in data, and a meta.requestId. Failure carries success: false and an error object with a stable code, a human message, and sometimes details. Branch on error.code, never on message, which is free to change. List endpoints use cursor paging: an items array plus a nextCursor that is null on the last page, with limit defaulting to 20 and capped at 100. Treat the cursor as opaque.

{
  "success": true,
  "data": { "id": "sub_01ARZ3NDEKTSV4RRFFQ69G5FAZ", "status": "active" },
  "meta": { "requestId": "req_aBcDeFgHiJkL" }
}
What a write to the Trile API can return, and what your handler should do
error.codeHTTPWhen it happensWhat your code does
idempotency_required400You sent a write with no Idempotency-KeyFix the client. This is never a runtime condition
idempotency_error422Same key, different request bodyYou reused a key across two operations. Generate one key per operation
request_in_progress409The first attempt with that key is still runningBack off and retry with the same key
insufficient_funds400The wallet cannot cover the first cyclePrompt a top-up. No subscription was created
wallet_cap_exceeded400The top-up would breach the customer's KYC-tier capShow cap_paisa and offer the KYC upgrade path
subscription_already_exists409That customer already holds that priceTreat as success if you were retrying, otherwise show the existing subscription
internal_error500Server errorSafe to retry with the same idempotency key

Error codes and status mapping as published in the Trile API documentation, read 27 August 2026.

How does my server find out that a renewal happened?

Two channels, and a correct integration uses both. Trile signs every webhook delivery with a Trile-Signature header of the form t=<unix-seconds>,v1=<hex>, where the hex is HMAC-SHA256(secret, "<t>.<raw body>"). Verify against the raw bytes, before any parse and re-stringify, compare in constant time, and reject anything older than five minutes. Deliveries are at-least-once, so dedupe on the event id. The second channel is the pull side: /v1/events is an append-only log, filterable by type, resource and date range, that never expires. Webhooks give you latency. The event log gives you a way to prove what happened and to backfill whatever a delivery missed. Sweep it on a schedule.

Should you build recurring billing yourself or adopt an API?

Build it if billing is your product. Adopt it if it is not. The honest version of the trade is that the first month of a hand-rolled billing engine is easy and the eighteenth is not, because the hard parts do not appear until you have volume, retries, and a customer arguing about a charge. 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, which replaces a card decline path with a balance check. The split below is what you own either way against what arrives already built.

बिलिङ नै तपाईंको उत्पादन हो भने आफैं बनाउनुहोस्। होइन भने नबनाउनुहोस्।

What you build yourself versus what the Trile API gives you आफैं बनाउने काम बनाम API ले दिने काम।
ConcernIf you build it yourselfWhat the Trile API gives you
Retry safety on writesA key store, body fingerprinting, and a decision about what a replay returnsIdempotency-Key mandatory on every write, stored response replayed for 24 hours, 422 on a reused key with a different body
Money representationPick a type, then enforce it in the database, the API layer, and every clientInteger paisa as strings end to end, "49900" is NPR 499.00, currency always present
Cycle schedulingThe cron, the row lock, the transaction boundary, and the resume-after-crash pathA daily billing tick that generates the invoice and debits the wallet, run by a worker, not by your request
A renewal that failsInvent the state machine, the retry schedule, and the recovery triggerpast_due with an invoice.payment_failed event, recovering on the next top-up
Ledger correctnessAn append-only ledger, plus a job that proves the balance still equals the sum of itAppend-only wallet ledger, balance reconciled against the ledger sum daily
Event deliveryA queue, retry with backoff, HMAC signing, secret rotation, and a replay pathSigned Trile-Signature deliveries with retries, plus a pullable /v1/events log
Top-up railsIntegrate eSewa, Khalti, IME Pay and bank transfer, and verify each settlement server-sideHosted checkout doing phone OTP, top-up, KYC and subscribe in one flow
KYC caps under NRB rulesTrack tiers yourself and enforce a per-customer ceiling on balance and top-upcap_paisa per KYC tier, with wallet_cap_exceeded on breach
Proration on a plan changeDesign itNot exposed in the public API today. Prices are immutable in amount and archived rather than edited
Bikram Sambat dates in your UIBuild itNothing. Billing intervals are Gregorian; BS rendering stays on your side

Right-hand column verified against docs.trile.app on 27 August 2026. The last two rows are work Trile does not do for you.

What is actually hard about building recurring billing?

Five things, and none of them is the cron job. They are listed in the order they tend to bite.

How do you make a write safe to retry?

Not by storing the key and returning 200. The key, the request fingerprint, and the response body have to be written in the same transaction as the effect they describe. Otherwise a crash between the charge committing and the key being recorded leaves you with a customer who has been debited and a system that believes nothing happened, and the client is about to retry. Two cases most implementations forget: what to return when the same key arrives with a different body, and what to return while the first attempt is still in flight. Trile answers 422 idempotency_error and 409 request_in_progress. Build it yourself and you write both branches, plus the SHA-256 fingerprinting over method, path and canonical body that makes the first one possible.

What happens when a billing run dies halfway through?

A sweep walks every subscription due today. The process is killed on number 4,000 of 9,000. On restart, a flag written after the loop protects nothing, because it was never written. The guard has to live inside the unit of work: lock the subscription row, check whether its period has already advanced, and move the period in the same transaction that debits the wallet. A second pass then reads a period that has already moved and skips. Trile exposes currentPeriodStart and currentPeriodEnd on every subscription, and they advance with the debit. Building this means getting a row lock, a transaction boundary and a resume path right before production tells you which one was wrong.

How do you know the wallet balance is still correct?

You do not, unless something checks. A wallet holds two representations of one number: the balance, and the sum of the append-only ledger. They agree until a write lands in one and not the other, and then they disagree quietly for weeks. The fix is a job that walks every wallet, sums the signed ledger entries, compares against the stored balance, records each mismatch, and alarms on it. Trile runs that reconciliation daily. If you build the ledger you also build the job that proves it, and you build it before you need it, because after a drift the history you need in order to reconstruct the truth is exactly the history you did not record.

What do you do when a customer changes plan mid-cycle?

Proration, and it is harder in a prepaid model than in a card one. The customer has already paid for a cycle they are abandoning, and there is no card to refund, so the credit has to go somewhere: back into the wallet as a ledger entry, or forward onto the next invoice. Pick one and you own that product decision permanently. Worth stating plainly: Trile does not expose a proration parameter in the public API today. Prices are immutable in the amount that matters, so you create a new price and archive the old one, and the documented PATCH on a subscription takes cancelAtPeriodEnd and metadata. Plan changes are yours to model on either path.

Can you replay an append-only event log safely?

Only if every consumer of it is idempotent. An append-only log earns its keep because you can read it again after an outage, a bad deploy, or a webhook endpoint that was down for six hours. That value disappears the moment replaying invoice.paid grants a second month of access or sends a second receipt. Dedupe on the event id and make each handler's effect a set operation rather than an increment. Trile's log is queryable through /v1/events with evt_ prefixed ids for exactly this purpose. The log is the easy half. Replay safety is won or lost in the consumers.

How do Bikram Sambat dates and Nepal's clock affect billing cycles?

They affect the boundaries, not the arithmetic, and keeping those apart is the thing to get right. Trile computes intervals in the Gregorian calendar: an interval of day, week, month or year with an intervalCount multiplier, so quarterly is month with intervalCount: 3. Month arithmetic still overflows, because a cycle that starts on the 31st has no 31st in most following months, and you decide what that means before a customer notices you did not. Bikram Sambat makes the display side harder rather than the billing side. BS month lengths run from 29 to 32 days and follow the sun's transit through the zodiac instead of a rule, so every converter is a lookup table with a bounded year range, not a formula.

Then there is the clock. Nepal Standard Time is UTC+05:45, so "today in Nepal" is not a UTC timestamp truncated to a date. A daily billing tick that assumes it is will be on the wrong Nepali day for the first five hours and forty-five minutes of every one of them, which shows up as invoices dated a day early for a slice of your customers, and as a reconciliation report that never quite matches.

What else can a Nepali developer use for recurring billing?

Four realistic paths, and only one of them is Trile. SUQO's API creates a subscription and hands back a checkout_url, which fits a business whose customers already expect to pay on a link and whose churn tolerates an ignored message. Stripe Billing and Chargebee are the mature products, and both assume a card on file that can be charged while the customer is absent. Nepal has no self-serve merchant API for unattended recurring collection; the e-Mandate path does exist, and it runs through member BFIs and licensed PSPs rather than a key you sign up for, which the auto-debit page covers. The Stripe alternative for Nepal page separates receiving international money from billing domestic customers. APINepal offers what it calls one payment API for eSewa, Khalti and Fonepay, settling into your own merchant accounts, which solves taking a payment rather than owning a cycle. Integrating eSewa, Khalti, IME Pay, ConnectIPS or Fonepay directly gives you a payment call and leaves the scheduler, the ledger and the invoice object to you.

Rail by rail, the detail lives on its own page: can eSewa do recurring payments, and how a recurring charge works end to end in Nepal.

How do I get a Trile API key and test the integration?

Sign up, then work with a nep_test_ key. Trile splits test and live entirely at the key: nep_test_ moves no money, nep_live_ does, and the key carries its environment server-side, so there is no flag to pass and nothing to misconfigure. Test objects and live objects never mix. Authentication has three modes because three actors talk to the system: your server sends an API key in x-api-key, your customer authenticates to wallet and checkout endpoints with a phone number and a 6-digit OTP valid for five minutes, and the merchant dashboard uses email, password and TOTP. 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, and that whole path runs against provider sandboxes before a rupee moves.

One thing to weigh before you plan a launch date: Trile is running in sandbox mode platform-wide while Nepal Rastra Bank licensing is pending. You can integrate and test end to end today, and no real funds move. Start with the quickstart, then the API reference for exact schemas and how Trile works for the lifecycle.

Common questions

Does the Trile API require an idempotency key on every write?

के हरेक राइटमा idempotency key अनिवार्य छ?

Yes. Every POST, PATCH and DELETE to /v1 must carry an Idempotency-Key header, or the request returns 400 idempotency_required. Keys are client-generated, scoped per business, and stored for 24 hours. A repeat with the same key returns the stored response without re-executing, so a timeout is safe to retry. A reused key with a different body returns 422 idempotency_error.

How does the Trile API represent money?

As integer paisa serialized as a string. NPR 499.00 travels as "49900", never as a JSON number and never in rupees. The currency field is always present and is NPR in v1. Strings survive values past Number.MAX_SAFE_INTEGER and cannot be coerced into a float by a JSON parser. Convert to rupees at the display edge with BigInt.

How much does the Trile API cost?

Trile has not published pricing. The docs, the API reference and test keys are open, and the quickstart runs end to end on a nep_test_ key without any money moving. For current commercial terms, email support@trile.app. Any Trile rate quoted somewhere else did not come from Trile.

Does the Trile API bill on Bikram Sambat dates?

के बिलिङ चक्र विक्रम सम्वत् मितिमा चल्छ?

No. Billing intervals are Gregorian: an interval of day, week, month or year with an intervalCount multiplier. Bikram Sambat is a display concern, and a real one, because BS month lengths run from 29 to 32 days and are set by solar transit rather than by a rule, so every converter is a bounded lookup table. Nepal Standard Time is UTC+05:45, which also changes what counts as today.

Can I test the Trile API without moving real money?

Yes. A nep_test_ key runs against isolated sandbox data and provider sandboxes, and moves nothing. The key carries its environment server-side, so there is no flag to pass and test objects never appear to a live key. Going live is a one-line swap from nep_test_ to nep_live_ in your server config, with the same base URL and the same payloads.

Does Trile support proration when a customer changes plan?

Not through a proration parameter in the public API today. Prices are immutable in amount, so you create a new price and archive the old one, and the documented PATCH on a subscription accepts cancelAtPeriodEnd and metadata. In a prepaid model a mid-cycle change means deciding whether the unused value returns to the wallet or offsets the next invoice. That call is yours.

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 the billing engine, the append-only wallet ledger, and the daily reconciliation job described on this page, and integrated eSewa, Khalti, IME Pay and bank transfer as wallet top-up sources. Every API detail below was checked against the published documentation at docs.trile.app on 27 August 2026 rather than written from memory.

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.