feat: add com.razorpay.upi UPI Intent payment handler#315
feat: add com.razorpay.upi UPI Intent payment handler#315paraskathuria-dev wants to merge 5 commits intoUniversal-Commerce-Protocol:mainfrom
Conversation
Introduces a complete UCP payment handler specification for UPI Intent payments via Razorpay, enabling Indian UPI support in the UCP ecosystem. Handler ID: com.razorpay.upi Flow: UPI Intent only (buyer deep-links to their UPI app to authorize) New files: - docs/specification/razorpay-upi-payment-handler.md — full handler spec covering participants, prerequisites, business/platform integration, payment protocol, security considerations, and end-to-end test guide - source/handlers/razorpay-upi/schema.json — root handler schema - source/handlers/razorpay-upi/types/business_config.json — key_id, env - source/handlers/razorpay-upi/types/platform_config.json — upi_apps - source/handlers/razorpay-upi/types/response_config.json — runtime config including razorpay_order_id (serves as checkout binding) - source/handlers/razorpay-upi/types/upi_intent_instrument.json — instrument type with available_upi_intent_instrument declaration - source/handlers/razorpay-upi/types/razorpay_payment_credential.json — HMAC-SHA256 payment proof credential (payment_id + order_id + signature) Design decisions: - No tokenization endpoint required: the Razorpay payment proof is a cryptographic tuple verified locally by the business using their key_secret - razorpay_order_id acts as the UCP binding, preventing replay attacks by tying each payment proof to a specific checkout session - Business creates Razorpay Order before responding to checkout and includes the order_id in response_config for the platform to initialize the SDK - Capture is manual (payment_capture: 0) so the business verifies the HMAC signature before committing funds Updated: - mkdocs.yml — adds handler to nav and llmstxt plugin sections
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
Inverts credential flow architecture: business now generates intent_uri server-side after Complete Checkout and returns it in escalation response. Platform executes the deep link natively (no Razorpay SDK on platform). Schema changes: - Move UPI schemas to base type space (source/schemas/shopping/types/) - Remove razorpay_payment_credential (platform no longer submits HMAC proof) - Update response_config (remove razorpay_order_id, key_id no longer required) Protocol amendment: - Add requires_buyer_authentication error code (severity: requires_buyer_review) - Amend requires_escalation Platform guideline for conditional native execution Specification: - Complete rewrite of razorpay-upi-payment-handler.md with inverted flow - 14-step ASCII diagram matching product doc v5 - Business integration: Razorpay order/payment creation, webhook handling - Platform integration: escalation handling, polling, deep link execution Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
| "pattern": "^upi://pay\\?.*pa=[^&]+.*$", | ||
| "minLength": 20, | ||
| "maxLength": 2048, | ||
| "description": "NPCI-compliant UPI Intent URI. Must contain the 'pa' (payee VPA) parameter per NPCI UPI Linking Specification. Example: upi://pay?pa=merchant@rzp&pn=MerchantName&tr=TXN123&am=500.00&cu=INR" |
There was a problem hiding this comment.
Given this only includes merchant VPA and amount, how could user confirm that they are indeed paying for the right items?
| "const": "upi_intent", | ||
| "description": "Discriminator for UPI Intent credential." | ||
| }, | ||
| "intent_uri": { |
There was a problem hiding this comment.
Since the intent_uri is passed through the Agent/Platform, what prevents a malicious app or a compromised Agent from tampering with the Payee VPA (pa) or Merchant Code (mc) before the user reaches the bank app? Does the protocol provide a way for the Merchant to cryptographically sign the URI itself?
| "required": ["type", "intent_uri", "transaction_reference"], | ||
| "properties": { | ||
| "type": { | ||
| "const": "upi_intent", |
There was a problem hiding this comment.
Does the handler mandate a system chooser for the upi:// intent? If a malicious app registers itself as the default handler for UPI intents, it could 'mimic' a bank app UI to steal the user's PIN. How does the protocol ensure the user has landed on a genuine, trusted Bank/TPAP surface?
Summary
Introduces a complete UCP payment handler specification for UPI Intent payments via Razorpay (
com.razorpay.upi), bringing Indian UPI support into the UCP ecosystem.UPI (Unified Payments Interface) is India's real-time bank-to-bank payment system managed by NPCI. This handler uses the UPI Intent flow — the platform deep-links the buyer into their preferred UPI app (Google Pay, PhonePe, Paytm, BHIM, etc.) which authorizes the payment. The resulting cryptographic proof from the Razorpay SDK is submitted at checkout.
What's included
Handler spec (
docs/specification/razorpay-upi-payment-handler.md):JSON Schemas (
source/handlers/razorpay-upi/):schema.json— root handler schema forcom.razorpay.upitypes/business_config.json—key_id,environment,merchant_nametypes/platform_config.json—upi_apps(optional app constraint)types/response_config.json— runtime config includingrazorpay_order_idtypes/upi_intent_instrument.json—upi_intentinstrument withavailable_upi_intent_instrumentdeclarationtypes/razorpay_payment_credential.json—razorpay_payment_proofcredential (payment_id + order_id + HMAC signature)Navigation (
mkdocs.yml): handler added to nav and llmstxt plugin.Key design decisions
key_secret— no token storage or detokenize API needed.razorpay_order_idas bindingorder_idinresponse_config. The credential must reference this exact ID, tying the payment proof to the checkout and preventing replay attacks.payment_capture: 0)How it differs from the processor-tokenizer pattern
The
com.razorpay.upihandler is structurally closer to Shop Pay (dev.shopify.shop_pay) than to the processor-tokenizer example — it uses a single fixed instrument type (upi_intent) with no card-brand-style constraints, and the credential is a payment proof rather than a stored token. The key addition israzorpay_order_idinresponse_config, which serves as the UCP checkout binding and is created by the business backend before returning the checkout response.Test plan
/.well-known/ucpbusiness profile declaration parses correctlyrzp_test_*keys) and confirmorder_idformat matches schema pattern^order_[A-Za-z0-9]+$key_id+razorpay_order_idfromresponse_config; confirm intent flow opens{razorpay_payment_id, razorpay_order_id, razorpay_signature}razorpay_order_idupi_intentinstrument schemamkdocs build)🤖 Generated with Claude Code