# Setu UPI addressing API - v0.1.2 - draft
Using this Setu API set, you can
1. Create a VPA
2. Add Settlement Account as a beneficiary
3. Set Settlement Rule
4. Update Settlement Rule
5. Credit Notification
6. Settlement Notification
7. Check Transaction Status
8. Fetch Report
8. Create Refund
9. Check Refund Status
10. Pause Address
11. Delete Address
12. Send collect Request
13. Query collect request Status
14. Create deep link/short link
15. Get deeplink engagment status
# Use cases
Some use cases
## QR codes
Anyone can now issue UPI QR codes like BharatPe, PhonePe. For example Khatabook
## Loan collection
- Unnati Small Finance bank (name changed for privacy) gives 3 wheeler loans.
- They can issue a UPI QR code to the auto
- They can take a cut of the transactions and do EDI (dialy EMIs)
## SMB bill collection
- Cinnamon ventures (name changed) is a agriculture business that distributes spices
- They supply to multiple small vendors around Bangalore
- They can associate a VPA with their invoice. They will print the QR code.
## Digitize door to door collections
- Paisa-collect has a fleet of foot on street delivery boys doing collections for bounced loans.
- The foot on street agent's mobile app can display a dynamic QR code.
- When payment is received, they will immediately know.
## Alternative to payment gateways
- UPI is preferred payment mode for many consumers.
- UPI pricing is costly on some payment gateways as the pricing is blended.
- With collect-request feature, merchants can easily send collect requests and reconsile.
# Addresses
## Create address
**End Point**: `/routes/addresses/`
**Request method**: `POST`
### Request Body
```javascript=
{
"type": "VPA",
"settlementDirective": {
"settlementType": "PERCENTAGE"
"rules":[
{
"beneficiaryID": "23723523502323",
"default": true // default account into which the money should be settled
},
{
"beneficiaryID": "12432992359235",
"value": 25,
"charge": true //charge for BPC
},
{
"beneficiaryID": "12432992359235",
"value": 15
}
]
}
}
```
### Response Body
```javascript=
{
"data": {
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak",
"settlementDirective": {
"settlementType": "PERCENTAGE"
"rules":[
{
"beneficiaryID": "23723523502323",
"default": true
},
{
"beneficiaryID": "12432992359235",
"value": 25,
"charge": true //charge for BPC
},
{
"beneficiaryID": "12432992359235",
"value": 15
}
]
},
"status": "ACTIVE"
}
},
"status": 200,
"success": true
}
```
## List addresses
**End Point**: `/routes/addresses/`
**Request method**: `GET`
### Response Body
```javascript=
{
"data": {
"addresses": [
{
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak",
"settlementDirective": {
"settlementType": "PERCENTAGE"
"rules":[
{
"beneficiaryID": "23723523502323",
"default": true
},
{
"beneficiaryID": "12432992359235",
"value": 25,
"charge": true //charge for BPC
},
{
"beneficiaryID": "12432992359235",
"value": 15
}
]
},
"status": "ACTIVE"
}
]
},
"status": 200,
"success": true
}
```
## Get address by ID
**End Point**: `/routes/addresses/<address-id>`
**Request method**: `GET`
### Response Body
```javascript=
{
"data": {
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak",
"settlementDirective": {
"settlementType": "PERCENTAGE"
"rules":[
{
"beneficiaryID": "23723523502323",
"default": true
},
{
"beneficiaryID": "12432992359235",
"value": 25,
"charge": true //charge for BPC
},
{
"beneficiaryID": "12432992359235",
"value": 15
}
]
},
"status": "ACTIVE"
}
},
"status": 200,
"success": true
}
```
## Edit address
**End Point**: `/routes/addresses/<address-id>`
**Request method**: `POST`
This can be used to
1. Update settlement rule
2. Pause address or reactivate a paused address
### Request Body
The request body would contain what needs to be edited.
```javascript=
{
"id": "92422992359235"
"settlementDirective": {
"settlementType": "PERCENTAGE"
"rules":[
{
"beneficiaryID": "12432992359235",
"value": 100,
"default": true
}
]
}
}
```
### Response Body
```javascript=
{
"data": {
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak",
"settlementDirective": {
"settlementType": "PERCENTAGE"
"rules":[
{
"beneficiaryID": "12432992359235",
"value": 100,
"default": true
}
]
},
"status": "ACTIVE"
}
},
"status": 200,
"success": true
}
```
## Delete address
**End Point**: `/routes/addresses/<address-id>`
**Request method**: `DELETE`
This API call will delete the address
### Response Body
```javascript=
{
"status": 200,
"success": true
}
```
# Notifications
## Transaction Notification
This is sent when a credit is received against an address.
**End Point**: `notificationUrl` as specified in the in the partner configuration.
**Request method**: `POST`
### Request Body
```javascript=
{
"eventType": "CREDIT"
"eventData": {
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak"
}
"paymentDetails": {
"additionalInfo": {},
"amountPaid": {
"value": 11200
}
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string"
}
}
}
```
### Response Body
Contains the payment acknowledgment ID.
```javascript=
{
"data": {
"acknowledgment": {
"type": "CREDIT",
"date": "2019-10-24T19:29:11Z",
"id": "string"
}
},
"status": 200,
"success": true
}
```
## Settlement Notification
Called when the T+1 settlement happens.
The data would be huge, so it should be processed in asynchronous manner on the client side
**End Point**: `notificationUrl` as specified in the in the partner configuration.
**Request method**: `POST`
### Request Body
```javascript=
{
"eventType": "SETTLEMENT"
"eventData": {
"id": "875712299009", // ID of the settlement event
"summary": {
"totalTransactions": 120,
"transactionDateTimeRange": {
"start": "datetime",
"end": "datetime"
},
"totalSettled": {
"value": 1002100
},
"totalProcessingCharge": {
"value": 1002100
}
},
"transactions": [ // individual transactions that have been settled
{
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak"
}
"paymentDetails": {
"additionalInfo": {},
"amountPaid": {
"value": 11200
}
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string"
}
}
],
"payouts": [ // information about the batch settlement transactions
{
"beneficiaryID": "string",
"amount": {
"value": 1000
},
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string" // UTR for the batch settlements
},
{
"beneficiaryID": "string",
"amount": {
"value": 2000
},
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string" // UTR for the batch settlements
}
]
}
}
```
### Response Body
Contains the payment acknowledgment ID.
```javascript=
{
"data": {
"acknowledgment": {
"type": "SETTLEMENT",
"date": "2019-10-24T19:29:11Z",
"id": "string"
}
},
"status": 200,
"success": true
}
```
# Beneficiaries
These APIs allow you to add beneficiaries needed to be used in the settlement rules.
## Add beneficiary
**End Point**: `/routes/beneficiaries`
**Request method**: `POST`
Setu will do penny drop and verify the beneficiary details.
### Request Body
```javascript=
{
"demographics": {
"type": "SOLE_PROPRIETORSHIP",
"address": "1, Merchant street, Bangalore 560001"
},
"account": {
"name": "Anand Agarwal",
"number": "12109991212",
"ifsc": "SBI00003312"
},
"kycDocs": [
{"type": "GSTN", "data": "<base64 encoded scanned copy>"},
{"type": "TAN", "data": "<base64 encoded scanned copy>"}
]
}
```
### Response Body
```javascript=
{
"data": {
"beneficiary": {
"id": "67182191188"
"demographics": {
"type": "SOLE_PROPRIETORSHIP",
"address": "1, Merchant street, Bangalore 560001"
},
"account": {
"name": "Anand Agarwal",
"number": "12109991212",
"ifsc": "SBI00003312"
},
"status": "PENDING"
}
},
"status": 200,
"success": true
}
```
## List beneficiaries
**End Point**: `/routes/beneficiaries`
**Request method**: `GET`
### Response Body
```javascript=
{
"data": {
"beneficiaries": [
{
"demographics": {
"type": "SOLE_PROPRIETORSHIP",
"address": "1, Merchant street, Bangalore 560001"
},
"account": {
"name": "Anand Agarwal",
"number": "12109991212",
"ifsc": "SBI00003312"
},
"id": "67182191188",
"status": "ACTIVE/PENDING/PROCESSING/INACTIVE/REJECTED"
}
]
},
"status": 200,
"success": true
}
```
## Get beneficiary by ID
**End Point**: `/routes/beneficiaries/<beneficiary-id>`
**Request method**: `GET`
### Response Body
```javascript=
{
"data": {
"beneficiary": {
"id": "67182191188"
"demographics": {
"type": "SOLE_PROPRIETORSHIP",
"address": "1, Merchant street, Bangalore 560001"
},
"account": {
"name": "Anand Agarwal",
"number": "12109991212",
"ifsc": "SBI00003312"
},
"status": "ACTIVE"
}
},
"status": 200,
"success": true
}
```
## Update beneficiary
**End Point**: `/routes/beneficiaries/<beneficiary-id>`
**Request method**: `POST`
You can edit a beneficiary's status between `ACTIVE` and `INACTIVE`.
### Request Body
```javascript=
{
"status": "INACTIVE"
}
```
This will throw an error if there are active addresses that are using this in their settlement rules and you try to deactivate.
### Response Body
```javascript=
{
"data": {
"beneficiary": {
"id": "67182191188"
"demographics": {
"type": "SOLE_PROPRIETORSHIP",
"address": "1, Merchant street, Bangalore 560001"
},
"account": {
"name": "Anand Agarwal",
"number": "12109991212",
"ifsc": "SBI00003312"
},
"status": "INACTIVE"
}
},
"status": 200,
"success": true
}
```
## Delete beneficiary
**End Point**: `/routes/beneficiaries`
**Request method**: `DELETE`
This will throw an error if there are active addresses that are using this in their settlement rules.
### Response Body
```javascript=
{
"status": 200,
"success": true
}
```
# Collect requests
## Create a collect request
**End Point**: `/routes/addresses/<address-id>/collect-requests`
**Request method**: `POST`
### Request body
```javascript=
{
"payerDetails": {
"type": "VPA",
"address": "mobileNumber@ybl"
}
"amount": {
"value": 123000
},
"notes": "string"
}
```
### Response body
```javascript=
{
"data": {
"collectRequest": {
"id": "765512127712",
"status" "PENDING/SUCCESS/REJECTED/INVALID_TARGET",
"payerDetails": {
"type": "VPA",
"address": "mobileNumber@ybl"
},
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak"
},
"amount": {
"value": 123000
},
"notes": "string",
"platformTransactionRefID": "string"
}
},
"status": 200,
"success": true
}
```
## GET collect request
**End Point**: `/routes/addresses/<address-id>/collect-requests/<collect-request-id>`
**Request method**: `GET`
### Response body
```javascript=
{
"data": {
"collectRequest": {
"id": "765512127712",
"status" "PENDING/SUCCESS/REJECTED/INVALID_TARGET",
"payerDetails": {
"type": "VPA",
"address": "mobileNumber@ybl"
},
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak"
},
"amount": {
"value": 123000
},
"notes": "string",
"platformTransactionRefID": "string"
}
},
"status": 200,
"success": true
}
```
## List collect requests
**End Point**: `/routes/addresses/<address-id>/collect-requests`
**Request method**: `GET`
### Response body
```javascript=
{
"data": {
"collectRequests": [
{
"id": "765512127712",
"status" "PENDING/SUCCESS/REJECTED/INVALID_TARGET",
"payerDetails": {
"type": "VPA",
"address": "mobileNumber@ybl"
},
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak"
},
"amount": {
"value": 123000
},
"notes": "string",
"platformTransactionRefID": "string"
}
]
},
"status": 200,
"success": true
}
```
# Transactions
Get the transaction statement against an address. Should be possible to query with filters such as date.
## List transactions
**End Point**: `/routes/addresses/<address-id>/transactions?startDate=<start-date>&endDate=<end-date>`
**Request method**: `GET`
### Response Body
```javascript=
{
"data": {
"transactions": [
{
"additionalInfo": {},
"amountPaid": {
"value": 11200
}
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string",
"timestamp": "datetime"
}
]
},
"status": 200,
"success": true
}
```
## Get transaction by ID
**End Point**: `/routes/addresses/<address-id>/transactions/<platformTransactionRefID>`
**Request method**: `GET`
### Response Body
```javascript=
{
"data": {
"transaction": {
"additionalInfo": {},
"amountPaid": {
"value": 11200
}
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string",
"timestamp": "datetime"
}
},
"status": 200,
"success": true
}
```
# Refunds
## Create a refund request
**End Point**: `/routes/refunds`
**Request method**: `POST`
### Request body
```javascript=
{
"platformTransactionRefID": "string"
}
```
### Response body
```javascript=
{
"data": {
"refund": {
"platformTransactionRefID": "string",
"status": "PENDING",
"id": "12139112121212",
"rejectReason": {}
}
},
"status": 200,
"success": true
}
```
## Get a refund status by ID
**End Point**: `/routes/refunds/<refund-id>`
**Request method**: `GET`
### Response body
```javascript=
{
"data": {
"refund": {
"platformTransactionRefID": "string",
"status": "PENDING/SUCCESS/REJECTED",
"id": "12139112121212",
"rejectReason":{
"code": "string",
"description": "string"
}
}
},
"status": 200,
"success": true
}
```
## List ongoing and recent refunds
**End Point**: `/routes/refunds`
**Request method**: `GET`
### Response body
```javascript=
{
"data": {
"refunds": [
{
"platformTransactionRefID": "string",
"status": "PENDING/SUCCESS/REJECTED",
"id": "12139112121212",
"rejectReason":{
"code": "string",
"description": "string"
}
}
]
},
"status": 200,
"success": true
}
```
# Settlements
Get the settlements statement against an address. Should be possible to query with filters such as date.
## List transactions
**End Point**: `/routes/addresses/<address-id>/settlements?startDate=<start-date>&endDate=<end-date>`
**Request method**: `GET`
### Response Body
```javascript=
{
"data": {
"settlements": [
{
"id": "875712299009",
"summary": {
"totalTransactions": 120,
"transactionDateTimeRange": {
"start": "datetime",
"end": "datetime"
},
"totalSettled": {
"value": 1002100
},
"totalProcessingCharge": {
"value": 1002100
}
},
"transactions": [
{
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak"
}
"paymentDetails": {
"additionalInfo": {},
"amountPaid": {
"value": 11200
}
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string"
}
}
],
"payouts": [
{
"beneficiaryID": "string",
"amount": {
"value": 1000
},
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string" // UTR for the batch settlements
},
{
"beneficiaryID": "string",
"amount": {
"value": 2000
},
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string" // UTR for the batch settlements
}
]
}
]
},
"status": 200,
"success": true
}
```
## Get settlement by ID
**End Point**: `/routes/addresses/<address-id>/settlements/<settlementID>`
**Request method**: `GET`
### Response Body
```javascript=
{
"data": {
"settlement": {
"id": "875712299009",
"summary": {
"totalTransactions": 120,
"transactionDateTimeRange": {
"start": "datetime",
"end": "datetime"
},
"totalSettled": {
"value": 1002100
},
"totalProcessingCharge": {
"value": 1002100
}
},
"transactions": [
{
"address": {
"id": "92422992359235",
"type": "VPA",
"identifier": "partner-prefix-218792433930995022@kotak"
}
"paymentDetails": {
"additionalInfo": {},
"amountPaid": {
"value": 11200
}
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string"
}
}
],
"payouts": [
{
"beneficiaryID": "string",
"amount": {
"value": 1000
},
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string" // UTR for the batch settlements
},
{
"beneficiaryID": "string",
"amount": {
"value": 2000
},
"platformTransactionRefID": "string",
"uniquePaymentRefID": "string" // UTR for the batch settlements
}
]
}
},
"status": 200,
"success": true
}
```
# Settlement directive examples
### How rules are applied
1. The rules are applied in series. First rule will have precedence in case of conflicts.
2. In case of no account being marked as `default`, first account in the `rules` list will be the default account.
3. Money leftover after applying different rules will go into default account
4. If no account is specified as the `charge` account, the `default` account shall be considered as the `charge` account. This account will be charged the BPC.
5. If the sum of percentages exceeds 100, it will be an error.
6. In case of `flat` splits, the rules that come first in the list with `value` will have higher priority. If there is no money leftover after settling to first `k` values, the rest of the accounts will get `0`.
### Settle 100% to the default account:
```javascript=
{
"rules":[
{
"beneficiaryID": 23723523502323,
"default": true
}
]
}
```
### Split settlement by percentage
```javascript=
{
"settlementType": "PERCENTAGE"
"rules":[
{
"beneficiaryID": 23723523502323,
"default": true
},
{
"beneficiaryID": 12432992359235,
"value": 25,
"charge": true //charge for BPC
},
{
"beneficiaryID": 12432992359235,
"value": 15,
"max": 200000 // max flat charge to be credited in a transaction. Rest will spill over to the
}
]
}
```
### Flat rate split settlement
```javascript=
{
"settlementType": "FLAT"
"rules":[
{
"beneficiaryID": 12432992359235,
"value": 1000 // split 10 rupees max
},
{
"beneficiaryID": 12432992359235,
"value": 2000,
"charge": true //charge for BPC
},
{
"beneficiaryID": 23723523502323,
"default": true
}
]
}
```
# Error codes
1. `invalid_address_id`
2. `invalid_benficiary_id`
3. `invalid_settlement_directive`
4. `beneficiary_in_use`
5. `invalid_transaction_id`
6. `invalid_refund_id`