Skip to content

feat: add com.razorpay.upi.circle UPI Circle payment handler#321

Open
paraskathuria-dev wants to merge 10 commits intoUniversal-Commerce-Protocol:mainfrom
paraskathuria-dev:feat/razorpay-upi-circle-payment-handler
Open

feat: add com.razorpay.upi.circle UPI Circle payment handler#321
paraskathuria-dev wants to merge 10 commits intoUniversal-Commerce-Protocol:mainfrom
paraskathuria-dev:feat/razorpay-upi-circle-payment-handler

Conversation

@paraskathuria-dev
Copy link
Copy Markdown

@paraskathuria-dev paraskathuria-dev commented Mar 31, 2026

Summary

Adds the com.razorpay.upi.circle payment handler for delegated UPI payments (UPI Circle / NPCI delegation framework).

UPI Circle lets a buyer authorize a platform to make UPI payments on their behalf within pre-configured mandate limits — no per-transaction MPIN, no buyer interaction at payment time.

Architecture

Follows the credential-before-Complete-Checkout pattern (same as com.google.pay and dev.shopify.shop_pay). Razorpay serves dual roles: Credential Provider (issues cryptograms) and PSP (processes the delegated debit).

Platform             Razorpay (Credential Provider)
   │                              │
   │── fetch cryptogram ─────────>│   (one-time cryptogram for delegate_id)
   │<─ { cryptogram, expires_at } │
   │
   │              Business (UCP)
   │── Complete Checkout ────────>│   (upi_circle instrument + upi_circle_cryptogram credential)
   │<─ completed ─────────────────│   (straight to completed — no escalation)

Participants (UCP terminology)

Participant Role
Business Advertises handler config; processes cryptogram via Razorpay; responds completed
Platform Discovers handler; fetches cryptogram from Razorpay; submits Complete Checkout
Razorpay (PSP) Processes delegated debit via NPCI; fires webhook to business
Razorpay (Credential Provider) Issues one-time cryptograms for established delegation mandates

Design Decisions

Decision Choice Rationale
Credential type upi_circle_cryptogram Cryptogram is single-use and time-limited — distinct from VPA-input credentials
Instrument field delegate_id Persistent mandate reference — like a card vault token; actual VPA resolved by PSP
business_config fields business_id + environment only Mandate limits are enforced by NPCI/bank at delegation layer, not UCP config
response_config fields environment only Per-txn/monthly limits are mandate-level, not UCP config parameters
Delegation setup Out-of-band, not part of UCP One-time bilateral integration between Platform and Razorpay — analogous to saving a card on ChatGPT

Files Changed

New schemas (shopping layer):

  • source/schemas/shopping/types/upi_circle_instrument.jsonupi_circle instrument with delegate_id, display.delegator_name, display.masked_vpa
  • source/schemas/shopping/types/upi_circle_credential.jsonupi_circle_cryptogram credential with cryptogram, delegate_id, expires_at

New handler:

  • source/handlers/razorpay-upi-circle/schema.json — top-level handler schema for com.razorpay.upi.circle
  • source/handlers/razorpay-upi-circle/types/business_config.jsonbusiness_id + environment
  • source/handlers/razorpay-upi-circle/types/platform_config.jsonenvironment
  • source/handlers/razorpay-upi-circle/types/response_config.jsonenvironment
  • source/handlers/razorpay-upi-circle/types/upi_circle_instrument.json — handler-level available instrument wrapper

New specification doc:

  • docs/specification/razorpay-upi-circle-payment-handler.md — full handler spec: delegation setup (out-of-band), payment flow, business/platform/PSP integration guides, error handling table, security considerations

Test plan

  • Schema validation: upi_circle_instrument.json extends payment_instrument.json via allOf, no additionalProperties: false, no redeclared base fields
  • Schema validation: upi_circle_credential.json extends payment_credential.json via allOf, type discriminator is upi_circle_cryptogram
  • Handler schema: com.razorpay.upi.circle declared correctly in schema.json
  • business_config validates: accepts { "business_id": "...", "environment": "test" } and rejects missing required fields
  • platform_config validates: accepts { "environment": "production" } and rejects unknown enum values
  • response_config validates: accepts { "environment": "test" } — no limit fields present
  • Spec doc: delegation setup section is clearly marked as out-of-band / outside UCP
  • Spec doc: payment flow diagram shows credential fetch BEFORE Complete Checkout (no escalation step)
  • Spec doc: error handling table covers mandate-expired, cryptogram-replayed, limit-exceeded cases
  • mkdocs build completes without errors

🤖 Generated with Claude Code

Introduces the com.razorpay.upi.circle handler for UPI Circle
(delegated) payments, where a secondary user pays from a primary
account holder's bank account within NPCI limits (₹5,000/txn,
₹15,000/month).

Key differences from com.razorpay.upi (Intent):
- Credential flows platform → business (delegate VPA), not business → platform
- No deep link; buyer authenticates via biometrics/PIN in PSP app
- Supports partial delegation (primary user also approves)
- Poll timeout extended to 5 min to cover approval latency

New files:
- source/schemas/shopping/types/upi_circle_instrument.json
- source/schemas/shopping/types/upi_circle_credential.json
- source/handlers/razorpay-upi-circle/schema.json
- source/handlers/razorpay-upi-circle/types/business_config.json
- source/handlers/razorpay-upi-circle/types/platform_config.json
- source/handlers/razorpay-upi-circle/types/response_config.json
- source/handlers/razorpay-upi-circle/types/upi_circle_instrument.json
- docs/specification/razorpay-upi-circle-payment-handler.md
paraskathuria-dev and others added 9 commits March 31, 2026 11:22
Complete rewrite to match the credential-before-Complete-Checkout pattern:

- Handler follows com.google.pay / dev.shopify.shop_pay architecture:
  platform fetches cryptogram from Razorpay AI Commerce TSP before
  submitting checkout; business responds straight to completed

- upi_circle_instrument: use delegate_id (persistent mandate ref) not
  delegate_vpa; add display.delegator_name and display.masked_vpa

- upi_circle_credential: type discriminator is upi_circle_cryptogram;
  fields are cryptogram + optional delegate_id + expires_at

- business_config: simplified to business_id + environment only;
  removed key_id, merchant_name, max_amount, additionalProperties:false

- platform_config: environment only; removed vpa_input, poll_* fields

- response_config: environment only; removed per_txn_limit_paise /
  monthly_limit_paise (mandate limits are NPCI/bank-enforced, not UCP config)

- spec doc: rewritten with delegation setup (out-of-band), TSP integration,
  PSP section, error handling table, and correct architecture comparison
  table vs UPI Intent
Replace invented "Razorpay AI Commerce TSP" naming with official UCP terms:

- Participants table: "Razorpay AI Commerce TSP" row renamed to
  "Razorpay (Credential Provider)" — the official UCP term for an entity
  that issues payment credentials (analogous to Google Pay token API)

- "AI Platform" → "Platform" throughout (official UCP participant name)

- Removed invented "ai-tpap" from API paths in delegation setup; replaced
  with descriptive operation names and a note to refer to Razorpay docs

- Removed invented razorpay.com/ucp/upi_circle/2026-03-26/ schema URLs
  from References and handler declaration example

- Schema descriptions: "PSP's AI Commerce TSP" → "Razorpay"

All naming now matches ucp.dev/latest/specification/* terminology.
…olling

- Add platform handler integration JSON sample matching UCP profile format
- Expand Step 5 response handling to cover all four shapes: completed,
  complete_in_progress, canceled, and requires_escalation
- Replace naive polling loop with exponential backoff (2s→10s, ×1.5, 2min cap)
  including network error resilience and terminal status switch
- Add error handling table mapping message types to platform actions
- Fix AI Commerce TSP anchor link in integration guide table (line 52)
…ent-handler

docs: enhance UPI Circle handler spec with platform integration and p…
…:paraskathuria-dev/ucp into feat/razorpay-upi-circle-payment-handler
@shiv9091
Copy link
Copy Markdown

Can you please add more details on -

  1. How are you solving for Agent hallucination for the commerce items, given it is not shown on the trusted surface?
  2. How are you capturing user consent for order confirmation and payment?
  3. How would PSP verify that the user has indeed confirmed for the purchase for specific set of items and for a specific merchant and amount?
  4. What is preventing Agent to pay to anyone in this mechanism?
  5. Will the TPAP/PSP app be forced to open for every transaction to show a system-level confirmation UI, or is this intended to be a fully backgrounded flow?
  6. How does the protocol distinguish between a human click and an Agent-simulated click to ensure "User Presence" during a delegated payment trigger?

@paraskathuria-dev
Copy link
Copy Markdown
Author

Thanks for the comments @shiv9091

Q1. How are you solving for Agent hallucination for the commerce items, given it is not shown on the trusted surface?
A1. The business owns the checkout state. The agent can only complete a checkout the business created — it can't inject items into a cart. If the agent hallucinates, the business's checkout won't match, and the user catches the mismatch at the review step. This happens before Razorpay is even in the picture, razorpay only get involved after the user has confirmed the order on a trusted.

Q2. How are you capturing user consent for order confirmation and payment?
A2. Razorpay captures consent at the delegation layer; UCP handles it at the transaction layer. Delegation setup (one-time): The user opens their UPI app, enters MPIN, and sets mandate limits themselves. Razorpay acts as the TPAP facilitating this — but we never see the user's MPIN or bank credentials. That interaction is entirely between the user and their bank. Once complete, the delegate_id represents standing consent. The user can revoke it from their UPI app. Consent is by mandate, the user pre-authorizes a spending, and each payment within it is legitimate under that standing authorization.

Q3. How would PSP verify that the user has indeed confirmed for the purchase for specific set of items and for a specific merchant and amount?
A3. Razorpay verifies at three checkpoints in our role as PSP:

  • At cryptogram issuance — We only issue a cryptogram for an active delegate_id with a valid mandate. No active mandate means no cryptogram, which means no payment can proceed. This is our first gate.
  • At debit processing via NPCI — When we submit the debit request, NPCI validates the amount against the mandate's per-transaction and monthly limits. Over the limit, the transaction is rejected at the banking layer.
  • Via UCP checkout binding — The credential is bound to a specific checkout_id, so it can't be replayed at a different merchant or for a different order. If AP2 mandates are active, there's also cryptographic proof that the user approved that exact checkout.

Q4. What is preventing Agent to pay to anyone in this mechanism?
A4. The agent doesn't pick the payee. The business creates the checkout with a specific merchant and amount. The agent can only complete that checkout, it can't redirect payment to a different destination through UCP. Razorpay only processes the debit for the payee the business specified. Razorpay acts as a payment provider for UPI Circle as a payment method. Guidelines are provided by NPCI.

Q5. Will the TPAP/PSP app be forced to open for every transaction to show a system-level confirmation UI, or is this intended to be a fully backgrounded flow?
A5. User needs to As the TPAP, Razorpay's role in the transaction is entirely server-side:

  • Platform calls our API → gets a cryptogram (no user interaction).
  • Business calls us to process → we debit via NPCI (server-to-server)
  • Transaction completes — no app switch, no MPIN, no QR code
    User interaction would be during creating the mandate token for consecutive debits. This is where the intent is provided and user can be involved.

Q6. How does the protocol distinguish between a human click and an Agent-simulated click to ensure "User Presence" during a delegated payment trigger?
A6. The key idea is that the user’s intent at the time of creating a UPI mandate is what authorizes all future payments, not individual transaction clicks. The mandate is set up directly by the user through secure authentication like MPIN or biometrics, making it a deliberate, human-approved action. Once created, it becomes a cryptographic authorization that defines what payments are allowed, while strict limits ensure safety at the banking layer. Instead of verifying every transaction, the system relies on the fact that the user explicitly consented upfront to a controlled payment pattern and can modify or revoke it anytime.

If you want to know more about UPI Circle, here are some reference

  1. https://razorpay.com/blog/what-is-upi-circle/
  2. www.npci.org.in/product/upi-circle.
  3. www.bhimupi.org.in/upi-circle

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants