Pro UPI QR LogoPro UPI QR

Developer Toolkit

Integrate Free UPI Payments On Your Website

Generate interactive client-side UPI QR widgets, payment buttons, and deep links instantly. For a real checkout flow, your app sends customers to a checkout screen or QR, then your backend records the verified payment result after the gateway confirms it.

Widget Configurator

Customize your payment widget parameters and get instant embed code below.

Overlay Logo Badge
Theme Accent Color
#287a57
<iframe 
  src="https://www.proupiqr.in/embed/?pa=merchant%40upi&pn=Merchant+Store&am=500&tn=Invoice+%231024&theme=287a57" 
  width="340" 
  height="480" 
  style="border:none; background:transparent; overflow:hidden;" 
  title="UPI Payment QR Widget"
></iframe>

Live Sandbox Preview

Scanning this QR code from any standard UPI app (GPay, PhonePe, Paytm, BHIM) will request ₹500 to Merchant Store.

Merchant API key required

Hosted Checkout Sessions

Create a 24-hour checkout with an exact INR amount and public HTTPS return URL. Reusing the same order_id is idempotent. A customer-submitted UTR remains verification_pending until your server checks its bank records and confirms the session.

1. Create

POST /api/v1/checkout-sessions/
Authorization: Bearer puqi_live_...

2. Inspect

GET /api/v1/checkout-sessions/:id/
Authorization: Bearer puqi_live_...

3. Confirm

PATCH /api/v1/checkout-sessions/:id/
{ "status": "paid", "confirmed": true }

Redirection API & Query Parameters

If you want to generate payment QR codes dynamically inside your custom CRM, billing software, or ecommerce site, you can directly invoke our rendering endpoints by passing standard URL query parameters.

ParameterTypeDescriptionExample
paString (Required)Your registered merchant/personal UPI Virtual Payment Address (VPA)payee@bank
pnString (Required)The display name of the payee/businessMerchant Store
amNumber (Optional)Requested transaction amount. (Locks the amount field on scanning apps)250.50
tnString (Optional)Transaction note or reference ID (shows up on the customer's payment statement)Order-8390
themeString (Optional)Custom hex color (without # prefix) to theme the payment widget buttonef4444
logoString (Optional)Brand overlay logo. Options: phonepe, gpay, paytm, bhimphonepe

Backend-only verification

Payment Response API

This API is for your server, not for the customer's browser. The browser can open a checkout screen or UPI link, but only your backend can receive and trust the final payment result from a verified gateway webhook or secure relay.

Simple client flow

  1. 1. Your app creates a payment request or shows a checkout screen.
  2. 2. The customer pays in their UPI app.
  3. 3. Your backend stores the verified result and your UI polls for status.

1. Receive the verified gateway result

Configure your gateway webhook to reach your server first. Your backend verifies the provider signature, uses a globally unique order ID, normalizes the result, and then calls this endpoint server-to-server.

POST /api/payment-response/
Content-Type: application/json
x-pro-upi-timestamp: 1787832000000
x-pro-upi-signature: sha256=...

{ "orderId": "order_8390", "status": "SUCCESS", "transactionId": "UTR…", "amountPaise": 25000, "provider": "your-gateway" }

2. Read the saved response

Your frontend can show a payment pending screen while your backend polls this endpoint or updates your order database. The result is retained for 90 days in Vercel KV.

GET /api/payment-response/?orderId=order_8390
x-pro-upi-timestamp: 1787832000000
x-pro-upi-signature: sha256=...

{ "payment": { "status": "SUCCESS", "transactionId": "UTR…", "receivedAt": "…" } }
Backend requirement: set PAYMENT_WEBHOOK_SECRET, KV_REST_API_URL, and KV_REST_API_TOKEN in Vercel. Sign POST as POST.timestamp.rawBody and GET as GET.timestamp.sortedQuery. The secret is only for server-to-server calls. Keep it out of browser JavaScript and embedded widgets. This response store is separate from hosted checkout sessions and does not change their status automatically.

Native UPI Intent Link

Open the standard UPI URI directly from your mobile checkout. Pro UPI QR does not provide an unrestricted redirect endpoint for arbitrary destinations.

upi://pay?pa=merchant@upi&pn=Pro%20UPI%20QR&am=250.00&cu=INR

Encode parameter values and verify the payee and amount in the UPI app before authorizing payment.

Zero commission explained

Unlike payment gateways that charge 2% to 3% transaction fees, our widget uses native UPI link protocols. Payments flow directly from the customer's bank app to your bank account over the NPCI network, entirely bypassing any third-party gateway processor.

✓ No API Keys Required✓ No SDKs to Install

Open-source utility

UPI URI Parser & Builder

A single 4 kB TypeScript module that both constructs valid upi://pay?... links from typed fields and parses them back into structured data. Copy it into any JavaScript, React, Next.js, or Node project. Zero dependencies. Based on NPCI UPI Linking Specification v1.6.

Build a UPI URI

import { buildUpiUri } from './lib/upi-uri';

const uri = buildUpiUri({
pa: 'shop@upi',
pn: 'My Shop',
am: '250.50'
});
// "upi://pay?pa=shop%40upi&pn=My%20Shop&am=250.50&cu=INR"

Parse a UPI URI

import { parseUpiUri } from './lib/upi-uri';

const r = parseUpiUri('upi://pay?...');
r.pa // "shop@upi"
r.pn // "My Shop"
r.amountPaise // 25050
r.valid // true

buildUpiUri(fields)

Accepts { pa, pn, am?, tn?, cu?, mc?, tr?, ref? }. Returns an encoded UPI URI string. Omits optional fields when empty.

parseUpiUri(uri)

Returns { pa, pn, am, tn, cu, amountPaise, amountNumeric, valid }. amountPaise is integer paise or null.

isValidUpiUri(uri)

Returns boolean. Validates VPA format (regex), payee name presence, amount decimal places, and char safety.

Source: Copy /src/lib/upi-uri.ts from the site source. No npm package yet. The parser uses URLSearchParams, which is available in browsers, Node 18+, React Native, and Android/iOS webviews. Full source is ~120 lines, MIT-licensed.

Platform Integration Examples

Copy-paste ready code for four platforms. All examples use the free UPI intent — no API key, no SDK, no server.

React 18+TypeScript

React Component

import React from 'react'; function UpiPayButton({ vpa, name, amount }: { vpa: string; name: string; amount?: number }) { const pay = () => { const params = new URLSearchParams({ pa: vpa, pn: name, cu: "INR" }); if (amount) params.set("am", amount.toFixed(2)); window.location.href = `upi://pay?${params}`; }; return ( <button onClick={pay} className="rounded-full bg-emerald-800 px-6 py-3 text-white font-bold hover:bg-emerald-700"> Pay ₹{amount ? amount.toFixed(2) : "..."} </button> ); } export default UpiPayButton;
Next.js 14+App Router

Next.js Server + Client

// app/api/upi-link/route.ts — Server Component import { NextResponse } from 'next/server'; export async function GET(req: Request) { const { searchParams } = new URL(req.url); const vpa = searchParams.get('vpa') || 'shop@upi'; const name = searchParams.get('name') || 'My Shop'; const amt = searchParams.get('amount'); const params = new URLSearchParams({ pa: vpa, pn: name, cu: 'INR' }); if (amt) params.set('am', amt); return NextResponse.redirect(`upi://pay?${params}`); } // Usage: /api/upi-link?vpa=shop@upi&name=Store&amount=250
AndroidKotlin

Android (Kotlin)

// Open a UPI payment intent in any installed UPI app fun payViaUpi(context: Context, vpa: String, name: String, amount: String?) { val uri = Uri.Builder() .scheme("upi") .authority("pay") .appendQueryParameter("pa", vpa) .appendQueryParameter("pn", name) .appendQueryParameter("cu", "INR") .apply { amount?.let { appendQueryParameter("am", it) } } .build() val intent = Intent(Intent.ACTION_VIEW, uri).apply { setPackage("com.google.android.apps.nbu.paisa.user") // GPay fallback } try { context.startActivity(intent) } catch (e: ActivityNotFoundException) { // No UPI app installed — show install prompt } }
iOSSwift

iOS (Swift)

// Open UPI payment via URL scheme (Swift) func payViaUpi(vpa: String, name: String, amount: String?) { var components = URLComponents() components.scheme = "upi" components.host = "pay" components.queryItems = [ URLQueryItem(name: "pa", value: vpa), URLQueryItem(name: "pn", value: name), URLQueryItem(name: "cu", value: "INR") ] if let amt = amount { components.queryItems?.append(URLQueryItem(name: "am", value: amt)) } guard let url = components.url else { return } if UIApplication.shared.canOpenURL(url) { UIApplication.shared.open(url) } else { // Fallback: open App Store UPI app } }

Attribution: Embedding the Pro UPI QR widget is free for any commercial or non-commercial use. Widget attribution ("Powered by Pro UPI QR") may be disabled by setting ?attribution=none on the embed URL. We ask that you do not use the widget in link schemes, keyword-stuffed footer links, or hidden embeds — this violates Google's link-spam policy and can hurt your site's search rankings.