UPI Collect Guard

Shows a UPI collect request as the payment it really is and asks whether the user expects money, since a UPI PIN only ever sends money.

StopsEntered UPI PIN to receive money

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/upi-collect-guard.json

The files land in your project. They're yours to edit.

Usage

upi-collect-guard-usage.tsx
import { UpiCollectGuard } from "@/components/ui/upi-collect-guard"

<UpiCollectGuard
  request={{
    name: "Rahul Sharma",
    vpa: "9876543210@ybl",
    amount: 4999,
    note: "OLX advance for sofa. Enter PIN to receive money",
  }}
  contacts={["mom@okaxis", "bescom.bill@icici"]}
  onPay={async () => {
    await new Promise((resolve) => setTimeout(resolve, 500))
    setResult("Opening UPI PIN…")
  }}
  onDecline={async () => {
    await new Promise((resolve) => setTimeout(resolve, 400))
    setResult("Declined. Nothing was sent.")
  }}
/>

What it catches

  • "Enter PIN to receive money" confusion, by asking what the user expects
  • Refund, prize, buyer and KYC scam wording
  • Person-to-person collect requests (no longer permitted on UPI)
  • Requesters not in contacts or not matching the expected name
  • Small test amounts used to build trust

Props

UpiCollectGuard props
PropTypeDefault
request* (required)

The incoming request.

CollectRequest—
contacts

UPI IDs the user has paid before; anything else is "unknown".

string[]—
expectedName

Who the user believes is asking, to compare with the bank's name.

string—
locale

Locale for money.

string"en-IN"
onPay

Continue to the PIN screen. Only reachable after the user says they are paying. May return a Promise.

(request: CollectRequest) => void | Promise<void>—
onDecline

Decline the request. May return a Promise.

(request: CollectRequest) => void | Promise<void>—
messages

Any visible string.

Partial<Omit<UpiCollectMessages, "risks">> & { risks?: Partial<UpiCollectMessages["risks"]> }—

* required. Also accepts the native props of <div> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Intent question is a roving-tabindex radiogroup with arrow keys
  • Risks linked via aria-describedby; status is role=status
  • Choosing "I expect money" moves focus to Decline
  • Pay uses aria-disabled while pending

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: PSPs and banks must enforce collect rules and fraud checks; treat this as user education before the PIN.

  • Heuristic wording and name checks; scams can avoid them
  • Does not block the UPI app's own PIN screen; it advises before it
  • Requester names come from what your PSP returns

Rules

Rules last verified:

Confirmed: PSPs and UPI apps must ensure collect on person-to-person transactions is not permitted (consolidating OC-220 of 29 Jul 2025, effective 1 Oct 2025). Informational; check NPCI's current circulars. Copied components don't update themselves, so re-check after rule changes (see updating a component).

What it stops

Entered UPI PIN to receive money

Also known as

upi collect · request money · upi pin · olx scam · phonepe · google pay · paytm · kyc fraud

Field type

Dependencies

Pairs well with