Stripe SDK compatibility
Rupay supports the Stripe Node SDK for fixed-period hosted purchases. This is a supported subset, not full Stripe Billing or automatic-renewal parity. The initial client/API contract is Stripe Node 20.4.1, API version 2026-02-25.clover. Configure that version explicitly.
Available methods
| SDK method | Supported behavior |
|---|---|
customers.create | Optional name/email/phone/metadata; idempotent creation |
customers.retrieve | Merchant-scoped Customer object and metadata |
products.list, products.retrieve | Read the existing Rupay catalog; cursor pagination on lists |
prices.list, prices.retrieve | Immutable catalog Price snapshots; product/active filtering; cursor pagination |
checkout.sessions.create | mode: "payment"; one line_items[].price item; existing customer or customer email; order reference; registered return URLs; promotion-code flag |
checkout.sessions.retrieve | SDK-shaped session status, customer ID, payment status and verified access-period metadata |
checkout.sessions.expire | Expire an unpaid session |
webhookEndpoints.create | Register checkout.session.completed; endpoint-specific secret and pinned payload format |
webhooks.constructEventAsync | Verify the raw body with the returned secret and Stripe-Signature header |
refunds.list, refunds.retrieve | Support-managed refund records in Stripe Refund format; read-only |
disputes.list, disputes.retrieve | Existing provider cases in Stripe Dispute format; read-only |
Product and Price writes remain managed through Rupay's catalog admin. Catalog
creation/editing generates Price snapshots transactionally; amount/duration
changes archive the old offer and produce a new ID. Existing sessions keep their
original amount and duration. Migration 0032 also creates Prices for existing
simple products and variants. Because the legacy catalog rebuilds variants on
edit, editing a variable product can replace its variant and Price IDs; refresh
the configured plan mapping after such an edit. Product/Price list and retrieval
currently require checkout_sessions:read; checkout creation/expiry require
checkout_sessions:write.
A fixed-period catalog subscription is exposed as a one-time Price with
metadata.rupay_period_interval. It does not claim Stripe recurring collection.
A paid checkout exposes authoritative Unix-second values as strings in
metadata.rupay_period_start and metadata.rupay_period_end, with
metadata.rupay_renewal_mode: "manual". Its subscription field is null.
Version and backward compatibility
The Stripe SDK sends Stripe-Version; Rupay selects the supported SDK contract
when it equals 2026-02-25.clover. Other nonempty versions are rejected. Requests
without this header retain the native response format. This prevents an SDK
integration from changing existing native merchant responses.
SDK-created webhook endpoints store that API version. Their completed-checkout
payloads use the SDK format and include Stripe-Signature; native endpoints keep
their existing format. Secret generation is per SDK endpoint. Verification must
use the raw body; use the async verifier in Cloudflare/Bun.
Idempotency keys are optional in SDK mode, but callers should always supply a stable key for customer creation, checkout creation, and webhook registration. Keys are merchant-scoped. Replays preserve the original response; differing request bodies cannot reuse the same key. Resource IDs and credentials must belong to Rupay, not Stripe.
Explicit boundaries
mode: "subscription", recurring collection, saved payment methods, subscription CRUD, trials, proration, and cancellation of future charges are not implemented. Unsupported payment-affecting request fields are rejected.- Early manual purchases start at their own payment time; periods do not stack.
- The Price checkout supports one item. Fixed-period access requires quantity 1.
- Customer update/list/delete, Product/Price write APIs, Checkout list/line-item APIs and expansions are not part of this supported subset.
- SDK webhook registration currently accepts only
checkout.session.completed. Enforce expiry locally on entitlement reads; do not wait for an expiry event. - Card/eSewa/Khalti selection stays inside Rupay hosted checkout. Local rail names
in
payment_method_typesare Rupay extensions, not Stripe payment method enums. This does not redirect Stripe.js/Elements to Rupay. - Provider invoice/payment-intent IDs are private. Corresponding SDK checkout fields remain null; a public Stripe Invoice/PaymentIntent API is not supplied.
- Full Stripe field/default/error parity is not claimed. Native checkout lifetime and return-origin restrictions still apply. Hosted success/cancel URLs must be supplied for this subset.
Nepse Edge usage and validation
See Nepse Edge SDK integration for setup, plan mapping, checkout, and verified Premium synchronization.
apps/web/scripts/test-stripe-sdk-integration.ts runs the actual Stripe SDK
through the actual API handlers against a dedicated local PostgreSQL database,
with provider credentials disabled. It verifies migration/backfill, replay,
merchant isolation, pagination, catalog price changes, checkout payment/expiry,
webhook registration, signature validation, and outbox deduplication. It does not
make live charges or deliver webhooks to external servers.
Remaining full compatibility work
The broader five-domain roadmap still requires Product/Price write endpoints,
Customer CRUD, complete Checkout shapes/options, expansions and errors,
independent Subscription/SubscriptionItem storage, invoice and payment-attempt
lifecycles, confirmed recurring-provider support, retry/recovery and cancellation,
and resource-correct invoice.* / customer.subscription.* events. These must
be implemented and tested before advertising full Stripe API parity.
References: Stripe SDK configuration, Checkout, subscription lifecycle, webhook verification.
Refund and chargeback inquiries are made by email or phone to Rupay support. Refund creation/update/cancellation and dispute evidence/closure methods are unavailable through the API. See Refunds and disputes for supported read filters and the support workflow.