to search

Introducing Setu API playground Check it out ↗

#UPI Quickstart

As the first step, sign up on The Bridge, if you haven’t already. This is where you can create product configurations and add configuration details. Read more on this here and watch this quick video on how to create a test merchant configuration.

Also, listed below are some other details you need to get started. If you do face any issues, raise a support ticket and our team will reach out.

  • Sandbox
  • Production

Please note that if you are using **OAuth** as your preferred authentication method, the API URL will need to be updated. The sandbox URL would become and production URL would be


These will be applicable to all APIs you call, unless specified otherwise—

  • X-Setu-Product-Instance-ID—this is a unique identifier for your merchant configuration set up on the Bridge. Look for the “Merchant ID” on the top left, inside your merchant configuration.
  • authorization—Bearer <insert_token_here>. Generate this token using OAuth or JWT.
  • Content-Type—will be application/json. This will not be present in the header for Check link status API.

List of APIs
  • Create UPI payment link
  • Add credit (mock a payment in Sandbox)
  • Get notified via webhook (by exposing an endpoint)
  • Check link status (optional)
  • Expire Bill (optional)
API NamePathHTTP MethodAuthenticationAPI documentation
Create payment link/payment-linksPOSTOAuth or JWTRead
Add credit/triggers/funds/addCreditPOSTOAuth or JWTRead
Get notified via webhook<merchants-callback-URL>/notificationsPOSTAs set by merchantRead
Check link status/payment-links/<platformBillId>GETOAuth or JWTRead
Expire bill/utilities/bills/<platformBillId>/expirePOSTOAuth or JWTRead
Create refund/refund/batchPOSTOAuth or JWTRead
Check batch or individual refund status/refund/:batchID or /refund/:refundIDGETOAuth or JWTBatch refund,

Individual refund

#Start integration

Step 1 — Create a merchant configuration

See this quick video on how to create a merchant configuration on The Bridge Sandbox.

Step 2 — Add configuration details

Under the “Configuration” tab—

Add URL endpoint

The callbackURL—for Setu to send notifications for payment and settlment success. If you want to implement this, read more about notifications.

Please note, Setu will add /notifications at the end of this URL.

Set up authentication details as per your preference to expose callbackURL. Add details on The Bridge and contact Setu's team, if needed. Note that you can also add multiple callback URLs, as per your requirements.

Add settlement account(s)

A settlement account has to be added to allow mock settlements while making test transactions. Any dummy value could be added here.

Please note, any changes made to the Production configuration, will require approval from a Setu admin. Until approved, the changes will not be made live. This maker-checker process exists to ensure that there are no accidental updates to the configurations of live products.

#Guide to using all APIs

Create a UPI payment link

Authorization: Bearer <insert_token_here>. Generate this token using OAuth or JWT.

Content-Type—will be application/json
Sample request

Let’s create a payment link for INR 100. This is what the request and response would look like.

"billerBillID" : "EB-1123-345324",
"amount": {
"value" : 10000,
"currencyCode" : "INR"
"amountExactness" : "EXACT", //ENUM values—EXACT | EXACT_DOWN | ANY
"name" : "Merchant name", //specify this optionallly
"transactionNote": "Payment for ABC bill", //optional
"additionalInfo" : {
"UUID": "b6b6f173-8649-4b2e-9c22-f78e9195a23e",
"tags": "electricity"

In the above request:

  • billerBillID is an identifier for this link in merchant’s system which they will later look up or reconcile against.
  • amount.value is the value in paise of the amount needed to be collected from the user, expressed as data type integer
  • amount.currencyCode would always be INR.
  • amountExactness allows flexibility in the amount being paid by the customer, as per merchant specification.
    • Specifying EXACT will allow your customer to pay only the exact amount specified by you in the create link API.
    • Specifying ANY will simply allow your customer to pay any amount above INR 1.
    • Specifying EXACT_DOWN will only allow the paid amount to be more than INR 1 and less than the amount specified in the Create bill API.

Note that UPI does not recognise a “maximum allowed amount” and any payment value above INR 1 will be successful with EXACT_DOWN.

However, paying more than the amount specified in the Create bill API will fail Setu’s validation, and will be refunded to your customer. See Validations below.

amountExactness is not honoured consistently across UPI apps. As explained above, failure against the amountExactness logic on Setu may cause a successful payment to trigger a refund for the customer. Hence, we recommend setting EXACT for amountExactness, for higher predictability.

  • name is an optional parameter using which you may specify the payee’s name when payment is being done. By default this is the name of the merchant as set up on the Bridge.
  • transactionNote is an optional parameter through which you can set the message for when a customer is making a UPI payment. By default the transaction note is “Payment for {your billerBillID}”.
  • additionalInfo is an optional object where you can pass any key, value—Setu will send it back in the payment successful notification. You can use this to define any details that you do not otherwise receive as part of the notification.

This request to generate a link is flexible and allows for many use cases. To know more about all the API params, please refer to the API documentation here.


You may additionally set up checks for transaction to be considered successful.

Currently we have two types of supported validations, that you as a merchant can specify—

  • Amount based check—This is used to specify an acceptable range of payment amounts to consider a payment successful and can be set via the AMOUNT_EXACTNESS condition that is explained above.
  • Source account check—This is a flag you can set while integrating with us, and use it to specify a bank account that you expect the customer to pay from. If you opt for this, you can mention the expected bank account from which the customer can pay in the sourceAccounts object as part of the Create payment link API.

Read more on how refunds will be handled in case these validations are not met.

Sample response
"status": 200,
"success": true,
"data": {
"name": "Test Link generator",
"paymentLink": {
"shortURL": "",
"upiID": "test464618891939677612@kaypay",
"upiLink": "upi://pay?pa=test464618891939677612@kaypay&pn=Test+Link+generator&am=100.00&tr=EB-1123-345324&tn=Payment+for+EB-1123-345324&cu=INR"
"platformBillID": "464618891939677612"

In the above response:

  • shortURLcan be shared directly with customers via a communication channel.
  • upiLink can be used as an Android button target (what is typically known as an intent trigger) or to generate a QR code that can be scanned with any UPI enabled app.
  • upiID would typically not be needed but a merchant may want to share this ID directly with the customer as a last resort in case none of the above 2 methods work - remember that the UX of this would not be good at all.
  • platformBillID is a unique ID that is associated with this link and can be used to track it later.

Add credit (mock a payment in Sandbox)

A mock payment against a link can be triggered to recreate a successful payment by a customer.

Setu recommends using this via Postman and to not waste resources on integrating this in code, unless there is a specific requirement to do so (such as automations and tests at your end).


Authorization: Bearer <insert_token_here>. Generate this token using OAuth or JWT.

Content-Type—will be application/json
Sample request
"amount": 100,
"type": "UPI",
"destinationAccount": {
"accountID": "test464618891939677612@kaypay"
"sourceAccount": {
"accountID": "dummy_customer@vpa"
"transactionReference": "464618891939677612"

In the above request:

  • amount is the value in rupees of the amount the link was generated for, expressed as data type float or double
  • destinationAccount.accountID is the upiID generated above.
  • sourceAccount.accountID is the VPA from which the payment is made - any dummy value can be used here, which is in a valid VPA format.
  • transactionReference is the platformBillID from the Create Link response.

The response would simply be 200 OK without any body.

Get notified via webhook

As soon as a customer makes a successful payment (or mocks a payment), Setu triggers a near realtime notification via webhook mechanism (also called callback).

For this to work, Setu expects the merchant to expose an API endpoint URL ending in /notifications. Once this URL is configured on Setu, the merchant starts receiving notifications.

Sample notification
"partnerDetails": {
"appID": "string", // your unique app ID in Setu system, this is constant
"productInstanceID": "string" // your unique product instance ID in Setu system, this is constant
"events": [
"data": {
"amountPaid": { // amount paid by the user in paisa
"currencyCode" : "INR",
"value" : 10000
"billerBillID" : "EB-1123-345324", // same as the billerBillID set by you when creating the link
"platformBillID": "string", // same as the platformBillID received by you when creating the link
"amountExactness" : "EXACT",
"additionalInfo" : { // same as values defined when creating the link
"UUID": "b6b6f173-8649-4b2e-9c22-f78e9195a23e",
"tags": "electricity"
"payerVpa": "string",
"transactionId": "string",
"timeStamp": 1595325201265,
"id": "fc4d3128-b6f4-46a5-8275-f5c05e0025b4"

In the above request:

  • partnerDetails are unique IDs corresponding to the merchant.
  • events is an array of events, which will usually contain only a single event.
  • events.type is the event type - where the relevant type would be BILL_FULFILMENT_STATUS.
  • events.timestamp is the epoch timestamp of the event.
  • is unique callback ID for every event, used for logging, debugging and tracking.

The response should simply be 200 OK without any body.

Check link status (optional)

This API does a status check on payment done against a link. It should not be used for polling but only for specific use cases.

For example, if someone waiting for a customer to pay within 5 minutes (300 seconds) doesn’t receive a callback within that time—they can use this API to check payment status and mark link as “invalid”, so that it is not used again.


The request should simply be the API URL with platformBillID appended to the path appropriately <base_url>/payment-links/<platformBillId>. Read more.

Authorization: Bearer <insert_token_here>. Generate this token using OAuth or JWT.
Sample response
"status": 200,
"success": true,
"data": {
"amountPaid": {
"currencyCode": "INR",
"value": 100
"createdAt": "2020-09-17T11:21:25.000Z",
"expiresAt": "2020-10-17T11:21:25.000Z",
"name": "test-bill",
"payerVpa": "ramesh@okaxis",
"paymentLink": {
"upiID": "test456457682191123757@kaypay",
"upiLink": "upi://pay?pa=test456457682191123757@kaypay&pn=test-bill&am=1.00&tr=test-bill-1&tn=Payment+for+test-bill-1&cu=INR"
"platformBillID": "string",
"billerBillID": "string",
"receipt": {
"date": "2020-09-17T05:52:04.587Z",
"id": "04abb833-2e83-4960-bd69-4000a0ea48eb"
"additionalInfo": {
"UUID": "a48f0c3f-1b50-40a9-9506-d775b9f9f5d9"

In the above response:

  • amountPaid.value is the amount paid by the customer in paise.

  • createdAt and expiresAt represent the link creation and validity timestamps, respectively. The validity is set to 45 days 0 hours (meaning the time will be same as for link creation) by default, but can be customised.

  • paymentLink contains the same info as in Create UPI payment link API’s response.

  • status represents the status of the link.

    BILL_CREATEDThe UPI link is created.
    PAYMENT_SUCCESSFULUser has made a successful payment.
    PAYMENT_FAILEDUser has made a payment but it failed due to some validation reasons or bank side issue (rare scenario).
    CREDIT_RECEIVEDThe money is received by Setu.
    SETTLEMENT_SUCCESSFULThe money is settled to merchant account.
    SETTLEMENT_FAILEDThe attempt to settle money to merchant account has failed - generally we would either resolve this internally with next batch of settlement or reach out to you in case there is some additional info required.
    BILL_EXPIREDThe UPI link has expired either by the default timeline or the timeline set by customer.
  • A UPI link can take multiple paths depending on the success and failure at different steps. Accordingly, the status journeys of a UPI link can be mapped as follows.

    • An ideal status flow (where user pays successfully and money is settled to merchant account) for a UPI payment link is: BILL_CREATED > PAYMENT_SUCCESSFUL > CREDIT_RECEIVED > SETTLEMENT_SUCCESSFUL

    • In case a user doesn't pay or the payment is unsuccessful due to any reason between user's UPI app and user's bank: BILL_CREATED > BILL_EXPIRED

    • In case payment fails due to an error on Setu (such as amount validation): BILL_CREATED > PAYMENT_FAILED


Expire Bill (optional)

Use the expire bill API to assign the BILL_EXPIRED status to the bill associated with your link. An expiry here refers to 2 things:

  • Setting the bill state to BILL_EXPIRED in Setu's system
  • Expiring the shortlink associated with the bill

platformBillID is a unique identifier for a bill on Setu's system and has to be provided to expire the bill. This is made available in the Create Payment Link API's response.


Authorization: Bearer <insert_token_here>. Generate this token using OAuth or JWT.

Content-Type—will be application/json
"status": 200,
"success": true

In case the platformBillID provided is incorrect, Setu will respond with 404 resource not found error—

status: 404,
success: false,
error: {
code: "bill-not-found",
title: "Bill not found",
detail: "Provided billId not found. Please re-check the billId.",
docUrl: "",
traceId: "XXXX"

If a bill has been expired, ideally, a payment by a customer would not be allowed, if verify VPA call returns an error on a payment app.

But if the verify VPA call was not made and the customer makes a payment, payment will go through but will be refunded in the settlement flow.

Create refund and check refund status (optional)

See Refunds page for more information about how to initiate refunds yourself or set validations to automate them.

Was this page helpful?