Verified, not assumed
Server-side amount checks, idempotent webhooks, replay protection and a manual UTR path for direct-to-VPA credits. A “success” redirect never marks an order paid.
A complete UPI-only payment engine you can lift into any project. Razorpay-style checkout, instant QR, webhook verification, UTR reconciliation and a hosted payment page — in one small, typed package.
Try it now — the sandbox QR settles automatically in a few seconds. No credentials, no database.
₹1,499.00
Monthly rent · Flat B-402
256-bit encrypted · No card details ever collected
Built to reuse
The core is framework-agnostic. The Next.js layer is a thin reference adapter you can copy into the next project.
Server-side amount checks, idempotent webhooks, replay protection and a manual UTR path for direct-to-VPA credits. A “success” redirect never marks an order paid.
Swap between mock, direct VPA (0% MDR) and PhonePe Standard Checkout with one environment variable. Add a new PSP by implementing a small interface.
Every order is an auditable event stream: created, webhook received, UTR claimed, verified, expired. The admin view lets ops settle a payment in seconds.
Integration
Create an order on the server
Amounts are integer paise. The engine builds the UPI intent, stores the order and returns a reference.
Render the drop-in checkout
Pass a reference or use the button component. QR, countdown, UPI app deep link, UTR claim and success state are included.
Listen for settlement
Webhooks mark orders paid. Polling is the fallback. A paid order is terminal, idempotent and safe to retry.
// server — create an order (paise or rupees)
import { createOrder } from '@/server/upi';
const { order } = await createOrder({
amountInRupees: 1499,
note: 'June rent · Flat B-402',
metadata: { tenantId: 't_204' },
});
// client — the whole checkout in one line
import { UpiCheckoutButton } from '@/components/upi-checkout';
<UpiCheckoutButton amountInRupees={1499} note="June rent" />