Skip to main content

Introduction

With S2S UPI Collect, the buyer types their UPI ID (VPA) on your page and your backend asks EximPe to send them a payment request. The request appears in the buyer’s UPI app, they approve it with their UPI PIN, and EximPe tells you the outcome.

No redirect, no QR

The buyer stays on your page. There is no intent to invoke and no QR code to show

Works on any device

The request reaches the buyer’s phone wherever they started, including on a desktop

Server-confirmed outcome

Read the final status from the Order Status API or the webhook

Collect or Intent?

Prerequisites

Before you begin, ensure you have:
  • Credentials: Your X-Client-ID and X-Client-Secret, and X-API-Version: 3.0.0 on every call
  • S2S UPI enabled: Server-to-server UPI must be enabled on your account. Without it, Create Order returns 403
  • Webhook URL: A secure endpoint to receive payment status updates
PSP callers also send X-Merchant-ID, naming the sub-merchant the order belongs to.
The flow:
  1. The buyer enters their UPI ID on your page.
  2. Your backend creates the order with upi_flow_type: "collection" and the buyer’s vpa. EximPe sends the payment request.
  3. The buyer approves the request in their UPI app.
  4. Your backend confirms the outcome from the webhook or the Order Status API.

Step 1: Ask for the buyer’s UPI ID

Add a field for the buyer’s UPI ID, such as name@okaxis, and tell them to open their UPI app once they submit. Check the format before you send it. EximPe lowercases the UPI ID, then accepts letters, numbers, dots and underscores before the @, and letters, numbers, dots and hyphens after it:
A UPI ID can pass this check and still not exist. EximPe does not look it up before sending the request. An unknown UPI ID shows up as a failed payment.

Step 2: Send the collect request

Create the order from your backend. The request carries your Client Secret, so never send it from a browser or a mobile app.
Alongside amount, currency, reference_id, buyer, product and invoice, a collect request needs:
  • collection_mode: "s2s"
  • mop_type: "upi". Leaving it out is refused with {"mop_type": "Invalid MOP type"}
  • upi_flow_type: "collection". It is not case-sensitive, and "collect" is refused
  • vpa: the buyer’s UPI ID
  • buyer.ip_address and buyer.user_agent: the buyer’s device IP address and browser or app user agent
A 201 means the request reached the payment network, not that the buyer has paid. The order is now payment_pending. Tell the buyer to open their UPI app and approve the request, and keep your page waiting for the outcome. The response has no intent_uri and no expires_at. There is nothing to invoke on the buyer’s device.

When the request is refused

Field errors come back as 400 with ERR_ORDER_002, keyed by field. No order is created, so you can fix the field and retry with the same reference_id. If the payment network cannot be reached, Create Order returns 502 with ERR_GATEWAY_UNAVAILABLE or ERR_PAYMENT_003. Retry with a new reference_id.

Create Order API

Every parameter, constraint, response field and error for this endpoint.

Step 3: The buyer approves in their UPI app

The buyer sees the request in their UPI app, checks the amount and payee, and approves it with their UPI PIN. Your page has nothing to call in the meantime. Show a “waiting for approval” state and tell the buyer which app to open. The request expires if the buyer does not approve it in time. How long that is depends on how your account collects UPI, so don’t build in a fixed countdown. When the request expires or the buyer declines it, the order fails and you receive PAYMENT_FAILED.
If the buyer typed the wrong UPI ID, the request went to someone else’s app or nowhere at all. Let them correct it and start a new order with a new reference_id.

Step 4: Confirm the outcome

Wait for the webhook, or poll the Order Status API from your backend:
Accept a success after a failure. A late approval can still capture an order already reported as failed. You then receive PAYMENT_SUCCESSFUL after PAYMENT_FAILED for the same order. Treat the success as final.
The Get Payment API shows the payer’s UPI ID masked, for example jo****@okaxis.

Get Order Status API

Full request and response reference.

Payment Successful webhook

Get pushed the outcome instead of polling for it.

Testing in sandbox

Sandbox sends collect requests to the payment network’s test environment, so no real money moves. When your sandbox account is set up to simulate UPI, the Create Order response also carries a test_simulator_url. Open it in a browser to approve or decline the request without a UPI app. It is never returned in production.

Need Help?

API Reference

📚 Create Order, Get Order Status, and the v3 webhook payloads