Documentation
Get started with upiagent
Accept UPI payments directly into your bank account. No payment gateway, no fees, no merchant onboarding. Install the package, add your API key, done.
Install
npm install upiagentZero native dependencies. Works in Node.js 18+, Next.js, Express, or any server-side JS.
Quick start
Sign up at beta-dashboard.upiagent.live, connect your Gmail and UPI ID, grab your API key. Then it's 5 lines:
import { UpiAgent } from "upiagent/client";
const upi = new UpiAgent({ apiKey: process.env.UPIAGENT_API_KEY });
// 1. Create payment — returns a QR code
const payment = await upi.createPayment({
amount: 499,
note: "Order #123",
addPaisa: true, // ₹499 → ₹499.37 (unique amount for matching)
});
// 2. Show QR to customer
// payment.qrDataUrl → base64 PNG for <img src={...} />
// payment.intentUrl → upi://pay?... for mobile deep link
// 3. Verify — checks your Gmail for bank alert automatically
const result = await upi.verify(payment.id);
if (result.verified) {
console.log("Paid!", result.payment.senderName, result.payment.upiReferenceId);
}Create & wait (one call)
For the simplest integration, use createAndWaitForPayment() — it creates the payment, polls for verification, and returns when done.
import { UpiAgent } from "upiagent/client";
const upi = new UpiAgent({ apiKey: process.env.UPIAGENT_API_KEY });
const payment = await upi.createAndWaitForPayment(
{ amount: 499, note: "Order #123", addPaisa: true },
{
onPaymentCreated: (p) => {
// Show QR to customer
console.log("Scan to pay:", p.qrDataUrl);
},
onStatusUpdate: (p) => {
console.log("Status:", p.status);
},
pollInterval: 5000, // check every 5s
timeout: 180_000, // give up after 3 min
}
);
if (payment.status === "verified") {
console.log("Payment confirmed!", payment.senderName);
}Next.js integration
API route
// app/api/pay/route.ts
import { UpiAgent } from "upiagent/client";
const upi = new UpiAgent({ apiKey: process.env.UPIAGENT_API_KEY! });
export async function POST(req: Request) {
const { amount, orderId } = await req.json();
const payment = await upi.createPayment({
amount,
note: `Order ${orderId}`,
addPaisa: true,
});
return Response.json({
id: payment.id,
qrDataUrl: payment.qrDataUrl,
intentUrl: payment.intentUrl,
amount: payment.amount,
});
}
// app/api/pay/[id]/route.ts
export async function GET(
_req: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const status = await upi.getStatus(id);
return Response.json(status);
}React component
"use client";
import { useState, useEffect } from "react";
export function Checkout({ amount }: { amount: number }) {
const [payment, setPayment] = useState<any>(null);
const [status, setStatus] = useState("idle");
async function createPayment() {
const res = await fetch("/api/pay", {
method: "POST",
body: JSON.stringify({ amount, orderId: "ORD_123" }),
});
const data = await res.json();
setPayment(data);
setStatus("pending");
}
// Poll for verification
useEffect(() => {
if (status !== "pending" || !payment) return;
const interval = setInterval(async () => {
const res = await fetch(`/api/pay/${payment.id}`);
const data = await res.json();
if (data.status === "verified") {
setStatus("verified");
clearInterval(interval);
}
if (data.status === "expired") {
setStatus("expired");
clearInterval(interval);
}
}, 5000);
return () => clearInterval(interval);
}, [status, payment]);
if (status === "idle") {
return <button onClick={createPayment}>Pay \u20b9{amount}</button>;
}
if (status === "pending") {
return (
<div>
<img src={payment.qrDataUrl} alt="Scan to pay" width={200} />
<a href={payment.intentUrl}>Open UPI App</a>
<p>Waiting for payment...</p>
</div>
);
}
if (status === "verified") return <p>Payment confirmed!</p>;
return <p>Payment expired. Try again.</p>;
}Express integration
import express from "express";
import { UpiAgent } from "upiagent/client";
const app = express();
app.use(express.json());
const upi = new UpiAgent({ apiKey: process.env.UPIAGENT_API_KEY! });
app.post("/pay", async (req, res) => {
const payment = await upi.createPayment({
amount: req.body.amount,
note: req.body.note,
addPaisa: true,
});
res.json(payment);
});
app.get("/pay/:id", async (req, res) => {
const status = await upi.getStatus(req.params.id);
res.json(status);
});
app.post("/pay/:id/verify", async (req, res) => {
const result = await upi.verify(req.params.id);
res.json(result);
});
app.listen(3000);SDK reference
UpiAgent(config)
Create a client instance. All you need is your API key.
| Param | Type | Description |
|---|---|---|
| apiKey | string | Your API key from the dashboard |
| baseUrl? | string | Override API URL (default: https://beta.upiagent.live) |
upi.createPayment(params)
Create a payment and get a QR code. Customers scan with any UPI app — GPay, PhonePe, Paytm, CRED.
| Param | Type | Description |
|---|---|---|
| amount | number | Amount in INR |
| note? | string | Note shown in UPI app |
| addPaisa? | boolean | Add random paisa for unique matching (recommended) |
Returns a Payment with qrDataUrl (base64 PNG), intentUrl (UPI deep link), id, amount, and status.
upi.verify(paymentId)
Trigger verification — scans Gmail for a matching bank alert. Call after the customer has paid.
const result = await upi.verify(payment.id);
// result.verified → true if payment matched
// result.payment → { amount, upiReferenceId, senderName, bankName, confidence }
// result.status → "verified" | "pending" | "expired"
// result.message → failure reason if not verifiedupi.getStatus(paymentId)
Read-only status check — no verification triggered.
upi.createAndWaitForPayment(params, options)
Create + poll in one call. Returns when verified, expired, or timeout.
| Option | Type | Description |
|---|---|---|
| onPaymentCreated? | fn | Called with payment after creation (show QR here) |
| onStatusUpdate? | fn | Called on each poll |
| pollInterval? | number | Ms between polls (default: 5000) |
| timeout? | number | Ms before giving up (default: 180000) |
Webhooks
Set your webhook URL in the dashboard settings. We POST to it when payments are verified. HMAC-signed for security.
Webhook payload
{
"event": "payment.verified",
"data": {
"paymentId": "uuid",
"amount": 499.37,
"currency": "INR",
"status": "verified",
"upiReferenceId": "003538060093",
"senderName": "JOHN DOE",
"confidence": 0.95,
"verifiedAt": "2026-05-03T10:30:00Z"
}
}Verify signature
import { verifyWebhookSignature } from "upiagent";
export async function POST(req: Request) {
const body = await req.text();
const signature = req.headers.get("x-upiagent-signature")!;
if (!verifyWebhookSignature(body, signature, process.env.WEBHOOK_SECRET!)) {
return new Response("Invalid signature", { status: 401 });
}
const payload = JSON.parse(body);
if (payload.event === "payment.verified") {
// Credit the customer, fulfill the order
}
return new Response("ok");
}Headers
| Header | Value |
|---|---|
| X-UpiAgent-Signature | sha256=HMAC hex digest |
| X-UpiAgent-Event | payment.verified |
| X-UpiAgent-Delivery-Id | Unique ID for idempotency |
Security layers
Every payment goes through 5 validation layers. If any layer fails, verification stops immediately.
Email source
Is the email from a known bank? Checked against a registry of bank sender patterns (ICICI, HDFC, Axis, SBI, etc.).
Amount match
Does the parsed amount match exactly? Zero tolerance by default.
Time window
Was the payment within the lookback window? Blocks stale/replayed emails.
LLM confidence
AI confidence in parsing the email. Low confidence = verification fails.
Deduplication
Has this UPI reference been used before? Prevents double-crediting.
Error handling
import { UpiAgent, UpiAgentApiError } from "upiagent/client";
const upi = new UpiAgent({ apiKey: process.env.UPIAGENT_API_KEY! });
try {
const payment = await upi.createPayment({ amount: 499, addPaisa: true });
} catch (err) {
if (err instanceof UpiAgentApiError) {
console.error(err.status, err.message);
// 401 → invalid API key
// 429 → rate limit or daily token cap
// 404 → payment not found
}
}{ verified: false, message: "..." }. Only infrastructure failures (auth, rate limits) throw.How it works
When you sign up, you connect your Gmail (the one that receives bank alerts like "You have received Rs.499 from...") and your UPI ID. upiagent handles the rest:
Ready to start?
npm install upiagentThen grab your API key from the dashboard