/

to search

Introducing Setu Changelog Check it out ↗

#API Integration

Below is a quick summary of the APIs you need to start integrating with for bank verification using Reverse Penny Drop (RPD).

Here are the things you will need for this integration—

  • Sandbox — https://dg-sandbox.setu.co
  • Production — https://dg.setu.co
  • Headers — x-client-id, x-client-secret and x-product-instance-id
  • Webhook endpoint: You need to create a webhook url on your server. Once configured, Setu will send notifications to that URL.

To get started quickly, you can setup a mock API endpoint using Beeceptor. This will help you understand the notification flow before you start to implement it on your server.


#Create reverse penny drop request

Send a POST request to the /api/verify/ban/reverse endpoint to create a reverse penny drop request.

#Request Body

You can include the following parameters in the request body:

Optional Parameters
  • redirectionConfig: Configuration for redirect behavior after transaction completion

    • redirectUrl: The URL where the user will be redirected after the transaction (e.g., "https://example.com")
    • timeout: Duration in seconds to wait before redirection occurs (e.g., 30)
  • additionalData: Additional information to be included with the request. additionalData should be simple key-value pairs (string value only).

    You can expect this additionalData as part of a JSON body when we notify you with bank account verification details over webhook, or when you use our GET details API.

Request Headers

Content-Type: application/json (optional, required when sending request body)

Example Request
"additionalData": {
"customField": "value"
},
"redirectionConfig": {
"redirectUrl": "https://example.com",
"timeout": 30
}

If successful, you will get a JSON response. Two of the fields in the response would be

  • upiLink, a UPI intent link starting with upi://
  • shortUrl, a link starting with https:// and an image with a QR code
We recommend showing the QR code on desktop devices so that a user can use their phone to scan QR and pay. For mobile phones, it's recommended to use the UPI intent link to pay on the same device.
  • If you want PSP specific link. Read the FAQ.

Notify your user, that they should pay from the account they want to use on your platform (if their primary account has to be verified for such usage).


Once payment is done, the payment link expires, and cannot be reused again. The link can also expire if your customer hasn't paid in 24hrs—in this case you will be notified of the status of the request, which will be BAV_REVERSE_PENNY_DROP_EXPIRED.


Types of statuses
  • BAV_REVERSE_PENNY_DROP_CREATED, if request was created successfully.
  • BAV_REVERSE_PENNY_DROP_FAILED, something went wrong. A payment should not be attempted with this request id.
  • BAV_REVERSE_PENNY_DROP_EXPIRED, upon expiry of payment link for customer. No payments can be done with expired links. The expiry is triggered as per the specified validUpto field or within 24 hours, whichever comes first.
  • BAV_REVERSE_PENNY_DROP_PAYMENT_SUCCESSFUL, when your user has successfully paid, and Setu’s banking partner has sent a credit alert with bank account details.
  • BAV_REVERSE_PENNY_DROP_PAYMENT_FAILED, when an issue occurs during payment by your user or at Setu’s banking partner’s end. The payment, if made, will be auto-refunded.

In some cases when our banking partner doesn't send us credit alerts, the status may still show as BAV_REVERSE_PENNY_DROP_CREATED.



RPD request created.


Request
POST /api/verify/ban/reverse
{
"additionalData": { // optional
"key1": "value1",
"key2": "value2"
}
}

Response
{
"id": "1b740e7a-5a81-4b88-ad43-110a08935286",
"shortUrl": "https://sandbox.bills.pe/wh9kk4mwuktg",
"status": "BAV_REVERSE_PENNY_DROP_CREATED",
"traceId": "1-640f227f-784ece1c005e4f9e653947ca",
"upiBillId": "1114053970646533628",
"upiLink": "upi://pay?pa=bauvatest@kaypay&pn=BauvaTest&am=1.00&tr=1114053970646533628&tn=Account%20Verification&cu=INR&mode=04",
"validUpto": "2023-03-13T13:20:52.277688"
}

Note: This 'id' is your 'requestId'. Please use this 'requestId' for rest the API reference.


#Mock payment

This API lets you test the end to end flow without an actual payment. This will send a webhook to the callback URL you have configured with us.

Use this API only on sandbox/UAT. This endpoint is disabled on production environment.


Successfully Mocked. If you already configured webhook url, you should receive a webhook.


Request
POST /api/verify/ban/reverse/mock_payment/:requestId
{
"paymentStatus": "successful" // or 'expired'. Default = 'successful'
}

Response
{
"success": true,
"traceId": "1-640f2285-2b2b250015fb3d3a6939db8b"
}

#Redirection Behavior

After the transaction is completed, the user will be automatically redirected to the specified redirectUrl based on the transaction status:

  • Successful transaction: Redirection after 5 seconds
  • Failed transaction: Redirection after 5 seconds
  • Timeout: Redirection occurs after the specified timeout period (in seconds)

When using the shortUrl on mobile devices (not recommended), notify your mobile users that they will need to manually return to their browser after completing the payment in their UPI app to be redirected to the specified redirectUrl. The redirection will not happen automatically when the user is in the UPI app.


#Notifications / Webhooks

Below is a summary of the notifications that need to be processed on your server by exposing an endpoint for Setu to send an HTTP POST request with 5 exponential backoff retries.

Please send back HTTP 200 status code if the request sent was processed correctly to avoid receiving multiple notifications for the same payment event. Response body is ignored.


Setu provides webhook authentication. For more details, refer to webhook-authentication


1. RPD_VERIFICATION_UPDATE Webhook

This webhook is sent when the end user makes a payments.

accountType can be BANK_ACCOUNT, PPI or UNKNOWN

  • PPI, if the payment happened from a PPI (Pre Paid Instrument) account and not a valid bank account
  • BANK_ACCOUNT, if the payment happened from a valid bank account and the IFSC is in the RBI database
  • UNKNOWN, if the payment happened from a bank account who's IFSC is not in the RBI database

If the bank account is classified as PPI, then it is for sure a PPI instrument and for majority of the use cases consider it an invalid bank account since money movement doesn't happen when trying to deposit an amount through IMPS/NEFT/RTGS. There can be PPI instruments that come up asUNKNOWN, please notify us at [support@setu.co](support@setu.co)


bankAccountType is an optional data field, you may not receive the value always. (Please contact with Setu team to know more about this feature.) The value can be SAVINGS, CURRENT, NRO, NRE

Examples

Example 1

In case of successful bank verification
{
"event" : "RPD_VERIFICATION_UPDATE",
"timeStamp" : "2021-11-12T00:12:29+05:30",
"data" : {
"rpd" : {
"success" : true,
"id" : "7097e53a-ba29-48a2-983d-878433b4f33e", // the RPD request id
"upiBillId" : "907442106379798024",
"data" : {
"bankAccountName" : "Eve",
"bankAccountIfsc" : "SBIN0000001",
"bankAccountNumber" : "48097036412",
"payerVpa" : "test@upi"
"accountType" : "BANK_ACCOUNT", // or UNKNOWN or PPI
"bankAccountType" : "SAVINGS" // Optional, can be null
"ifscCrossCheck" : true,
"ifscDetails" : {
"address": "EXPRESS TOWERS,GROUND FLOOR,NARIMAN POINT,MUMBAI 400021",
"branch": "Development Bank of Singapore IMPS",
"center": "MUMBAI",
"city": "MUMBAI",
"contact": "+912266388888",
"district": "MUMBAI",
"imps": "true",
"iso3166": "IN-MH",
"micr": "400641002",
"name": "Development Bank of Singapore",
"neft": "true",
"rtgs": "true",
"state": "MAHARASHTRA",
"swift": "",
"upi": "true"
}
}
"additionalData": { // if you have specified while creating RPD request
"key1" : "value1",
"key2" : "value2"
}
}
}
"traceId" : "7097e53a-baq9-4122-9d3d-8s8433b4f33e",
}

Example 2

In case of failed bank verification
{
"event" : "RPD_VERIFICATION_UPDATE",
"traceId" : "7097e53a-baq9-4122-9d3d-8s8433b4f33e",
"timeStamp" : "2021-11-12T00:12:29+05:30",
"data" : {
"rpd" : {
"success" : false,
"id" : "7097e53a-ba29-48a2-983d-878433b4f33e",
"upiBillId" : "907442106379798024",
"data" : null,
"error" : {
"code" : "BAV_REVERSE_PENNY_DROP_EXPIRED", // or BAV_REVERSE_PENNY_DROP_FAILED
"detail" : "Expired or failed"
},
}
}
}
2. RPD_DEBIT_ATTEMPT_FAILED Webhook

This webhook is sent when the end user tries to make a payments but the debit fails due to some reason.

statusCode of this event can be one of the following:
statusCodestatusDescription
R01The customer's debit attempt failed.
R02Payment authorization took too long.
R03The customer's bank is taking too long to respond.
R04The debit process took too long.
R05Connection timed out during the credit request process.
R06The transaction exceeds the risk threshold.
R07The customer's bank is unavailable.
R08This transaction isn't permitted for the beneficiary.
R09Connection timed out during the debit request process.
R12Beneficiary bank response time is too high.
R13The total debit amount exceeded the set limit.
R14Transaction details mismatch.
R16The requested function is not supported for the beneficiary.
R20Receiver/beneficiary is not available, causing a timeout.
R22The debit acknowledgement was not received.
R25Duplicate transaction request.
R100Any other upstream server error.
Examples

Example 1

In case of customer's debit attempt failed
{
"data": {
"rpd": {
"id": "178ce32b-bf43-4797-9423-027d3722df08",
"additionalData": null, // customer's own data if they provided
"statusCode": "R01",
"statusDescription": "The customer's debit attempt failed."
}
},
"event": "RPD_DEBIT_ATTEMPT_FAILED",
"timeStamp": "2023-08-24T12:59:11.427233"
}

#Get Details API

This is an optional API. This API lets you know the bank verification status.

Note: It should not be used for polling but only for specific use cases. For example: if you're not receiving successful webhook for a customer and want to know if the customer has made the INR 1 payment for bank verification or not.


Note: Data will be purged after receiving a 2xx status code from the webhook. In the case of a non-2xx status code, the data will be purged after 24 hours.


Bank verification status and bank details (if available).


Request
GET /api/verify/ban/reverse/:requestId

Response
{
"status": "BAV_REVERSE_PENNY_DROP_PAYMENT_SUCCESSFUL", // or, BAV_REVERSE_PENNY_DROP_CREATED, BAV_REVERSE_PENNY_DROP_EXPIRED, BAV_REVERSE_PENNY_DROP_PAYMENT_FAILED
"data": { // null if status is BAV_REVERSE_PENNY_DROP_PAYMENT_SUCCESSFUL and data is not purged
"accountType": "BANK_ACCOUNT",
"bankAccountType": "SAVINGS" // Optional, can be null
"bankAccountIfsc": "SBIN0000539",
"bankAccountName": "Noresh",
"bankAccountNumber": "9009120939129",
"ifscCrossCheck": true,
"ifscDetails": {
"address": "M V ROAD ANDHERI E MUMBAI MAHARASHTRA",
"branch": "ANDHERI (EAST)",
"center": "GREATER BOMBAY",
"city": "MUMBAI",
"contact": "",
"district": "GREATER BOMBAY",
"imps": "true",
"iso3166": "IN-MH",
"micr": "400002002",
"name": "State Bank of India",
"neft": "true",
"rtgs": "true",
"state": "MAHARASHTRA",
"swift": "",
"upi": "true"
},
"payerVpa": "customer@vpa"
},
"id": "1b740e7a-5a81-4b88-ad43-110a08935286",
"shortUrl": "https://sandbox.bills.pe/wh9kk4mwuktg",
"upiBillId": "1114053970646533628",
"upiLink": "upi://pay?pa=bauvatest@kaypay&pn=BauvaTest&am=1.00&tr=1114053970646533628&tn=Account%20Verification&cu=INR&mode=04",
"validUpto": "2023-03-13T13:20:52.277688"
"traceId": "1-640f228a-4dded97e470971343adae3da",
"additionalData": {
"key1": "value1"
"key2": "value2"
},
}