Skip to content

Commit a6414be

Browse files
author
tanmay
committed
idempotency content update
1 parent 3223754 commit a6414be

File tree

1 file changed

+227
-97
lines changed
  • content/payments/billpay/api-integration

1 file changed

+227
-97
lines changed

content/payments/billpay/api-integration/upms.mdx

+227-97
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,15 @@ When a new bill is available for a registered customer, the flow is:
10331033

10341034
**Example `BILL_FETCH` Callback (for UPMS Presentment):**
10351035
Note the presence of `upmsRegistrationRefId` indicating this is for a registered subscription.
1036-
```json
1036+
1037+
<Card padding="nano" shape="rounded">
1038+
<details>
1039+
<summary>
1040+
<Text as="h6" marginBottom="none" marginTop="none">
1041+
Sample Callback Payload
1042+
</Text>
1043+
</summary>
1044+
<CodeBlockWithCopy language="json">{`
10371045
{
10381046
"event": "BILL_FETCH",
10391047
"timeStamp": "2025-04-17T17:56:55.159+05:30",
@@ -1072,7 +1080,10 @@ Note the presence of `upmsRegistrationRefId` indicating this is for a registered
10721080
"upmsRegistrationRefId": "D00EP9IJSBI05F06U9K0eBQWOq851071727"
10731081
}
10741082
}
1075-
```
1083+
`}</CodeBlockWithCopy>
1084+
</details>
1085+
</Card>
1086+
<br />
10761087

10771088
> **Note**: The same webhook endpoint receives notifications for both automatically presented bills (via UPMS) and bills retrieved through manual fetch requests (using separate Bill Fetch API). You can distinguish between these two scenarios by checking the `upmsRegistrationRefId` field within the callback's data object:
10781089
> - If `upmsRegistrationRefId` is present (not null), this callback represents an automatic bill presentment for a registered customer.
@@ -1102,7 +1113,15 @@ If a bill is paid elsewhere after presentation, you'll receive a `SKIP_PAYMENT`
11021113
- Locate and mark the bill as paid in your system.
11031114

11041115
**Example `SKIP_PAYMENT` Callback:**
1105-
```json
1116+
1117+
<Card padding="nano" shape="rounded">
1118+
<details>
1119+
<summary>
1120+
<Text as="h6" marginBottom="none" marginTop="none">
1121+
Sample Callback Payload
1122+
</Text>
1123+
</summary>
1124+
<CodeBlockWithCopy language="json">{`
11061125
{
11071126
"event": "SKIP_PAYMENT",
11081127
"traceId": "D0508DIBJFBLCSGI36RG",
@@ -1112,7 +1131,10 @@ If a bill is paid elsewhere after presentation, you'll receive a `SKIP_PAYMENT`
11121131
"dateOfPayment": "2025-04-25T18:16:44+05:30"
11131132
}
11141133
}
1115-
```
1134+
`}</CodeBlockWithCopy>
1135+
</details>
1136+
</Card>
1137+
<br />
11161138

11171139
### 6.2 Why Handle SKIP_PAYMENT Callbacks?
11181140

@@ -1172,56 +1194,110 @@ This asynchronous API allows you to manually trigger a `BILL_FETCH` callback for
11721194
Confirms that the request to simulate the callback has been accepted.
11731195

11741196
- **On Acceptance: HTTP 200 OK**
1175-
```json
1176-
{
1177-
"success": true,
1178-
"traceId": "CV4PE82LTNJE9O014OE0"
1179-
}
1180-
```
1197+
<Card padding="nano" shape="rounded">
1198+
<details>
1199+
<summary>
1200+
<Text as="h6" marginBottom="none" marginTop="none">
1201+
Sample Response
1202+
</Text>
1203+
</summary>
1204+
<CodeBlockWithCopy language="json">{`
1205+
{
1206+
"success": true,
1207+
"traceId": "CV4PE82LTNJE9O014OE0"
1208+
}
1209+
`}</CodeBlockWithCopy>
1210+
</details>
1211+
</Card>
1212+
<br />
1213+
11811214
- **On Bad Request: HTTP 400 Bad Request** (e.g., Invalid `upmsRegistrationRefID` format).
1182-
```json
1183-
{
1184-
"success": false,
1185-
"error": {
1186-
"code": "invalid-registration-ref-id",
1187-
"message": "Invalid format for upmsRegistrationRefID"
1188-
},
1189-
"traceId": "CV4PE82LTNJE9O014OE1"
1190-
}
1191-
```
1215+
<Card padding="nano" shape="rounded">
1216+
<details>
1217+
<summary>
1218+
<Text as="h6" marginBottom="none" marginTop="none">
1219+
Sample Response
1220+
</Text>
1221+
</summary>
1222+
<CodeBlockWithCopy language="json">{`
1223+
{
1224+
"success": false,
1225+
"error": {
1226+
"code": "invalid-registration-ref-id",
1227+
"message": "Invalid format for upmsRegistrationRefID"
1228+
},
1229+
"traceId": "CV4PE82LTNJE9O014OE1"
1230+
}
1231+
`}</CodeBlockWithCopy>
1232+
</details>
1233+
</Card>
1234+
<br />
1235+
11921236
- **On Forbidden: HTTP 403 Forbidden** - If attempted in the Production environment.
1193-
```json
1194-
{
1195-
"success": false,
1196-
"error": {
1197-
"code": "forbidden-operation",
1198-
"message": "Simulation API not allowed in this environment"
1199-
},
1200-
"traceId": "CV4PE82LTNJE9O014OE2"
1201-
}
1202-
```
1237+
<Card padding="nano" shape="rounded">
1238+
<details>
1239+
<summary>
1240+
<Text as="h6" marginBottom="none" marginTop="none">
1241+
Sample Response
1242+
</Text>
1243+
</summary>
1244+
<CodeBlockWithCopy language="json">{`
1245+
{
1246+
"success": false,
1247+
"error": {
1248+
"code": "forbidden-operation",
1249+
"message": "Simulation API not allowed in this environment"
1250+
},
1251+
"traceId": "CV4PE82LTNJE9O014OE2"
1252+
}
1253+
`}</CodeBlockWithCopy>
1254+
</details>
1255+
</Card>
1256+
<br />
1257+
12031258
- **On Not Found: HTTP 404 Not Found** - If the specified `upmsRegistrationRefID` does not exist or is not active.
1204-
```json
1205-
{
1206-
"success": false,
1207-
"error": {
1208-
"code": "registration-not-found",
1209-
"message": "UPMS registration with the specified refId not found or inactive"
1210-
},
1211-
"traceId": "CV4PE82LTNJE9O014OE3"
1212-
}
1213-
```
1259+
<Card padding="nano" shape="rounded">
1260+
<details>
1261+
<summary>
1262+
<Text as="h6" marginBottom="none" marginTop="none">
1263+
Sample Response
1264+
</Text>
1265+
</summary>
1266+
<CodeBlockWithCopy language="json">{`
1267+
{
1268+
"success": false,
1269+
"error": {
1270+
"code": "registration-not-found",
1271+
"message": "UPMS registration with the specified refId not found or inactive"
1272+
},
1273+
"traceId": "CV4PE82LTNJE9O014OE3"
1274+
}
1275+
`}</CodeBlockWithCopy>
1276+
</details>
1277+
</Card>
1278+
<br />
1279+
12141280
- **On Server Error: HTTP 500 Internal Server Error**.
1215-
```json
1216-
{
1217-
"success": false,
1218-
"error": {
1219-
"code": "internal-error",
1220-
"message": "Internal Error"
1221-
},
1222-
"traceId": "CV4PE82LTNJE9O014OE2"
1223-
}
1224-
```
1281+
<Card padding="nano" shape="rounded">
1282+
<details>
1283+
<summary>
1284+
<Text as="h6" marginBottom="none" marginTop="none">
1285+
Sample Response
1286+
</Text>
1287+
</summary>
1288+
<CodeBlockWithCopy language="json">{`
1289+
{
1290+
"success": false,
1291+
"error": {
1292+
"code": "internal-error",
1293+
"message": "Internal Error"
1294+
},
1295+
"traceId": "CV4PE82LTNJE9O014OE2"
1296+
}
1297+
`}</CodeBlockWithCopy>
1298+
</details>
1299+
</Card>
1300+
<br />
12251301

12261302
**Handling the Asynchronous Callback Outcome:**
12271303

@@ -1256,56 +1332,110 @@ This asynchronous API allows you to manually trigger a `SKIP_PAYMENT` callback f
12561332
Confirms that the request to simulate the skip payment callback has been accepted.
12571333

12581334
- **On Acceptance: HTTP 200 OK**
1259-
```json
1260-
{
1261-
"success": true,
1262-
"traceId": "CV4PE82LTNJE9O014OE0"
1263-
}
1264-
```
1335+
<Card padding="nano" shape="rounded">
1336+
<details>
1337+
<summary>
1338+
<Text as="h6" marginBottom="none" marginTop="none">
1339+
Sample Response
1340+
</Text>
1341+
</summary>
1342+
<CodeBlockWithCopy language="json">{`
1343+
{
1344+
"success": true,
1345+
"traceId": "CV4PE82LTNJE9O014OE0"
1346+
}
1347+
`}</CodeBlockWithCopy>
1348+
</details>
1349+
</Card>
1350+
<br />
1351+
12651352
- **On Bad Request: HTTP 400 Bad Request** - e.g., Invalid `billRefId` format, or if the bill state is incompatible (e.g., already marked paid). May include specific codes like `invalid-bill`.
1266-
```json
1267-
{
1268-
"success": false,
1269-
"error": {
1270-
"code": "invalid-bill",
1271-
"message": "Bill reference ID not found or inactive"
1272-
},
1273-
"traceId": "SIM4PE82LTNJE9O014OE0"
1274-
}
1275-
```
1353+
<Card padding="nano" shape="rounded">
1354+
<details>
1355+
<summary>
1356+
<Text as="h6" marginBottom="none" marginTop="none">
1357+
Sample Response
1358+
</Text>
1359+
</summary>
1360+
<CodeBlockWithCopy language="json">{`
1361+
{
1362+
"success": false,
1363+
"error": {
1364+
"code": "invalid-bill",
1365+
"message": "Bill reference ID not found or inactive"
1366+
},
1367+
"traceId": "SIM4PE82LTNJE9O014OE0"
1368+
}
1369+
`}</CodeBlockWithCopy>
1370+
</details>
1371+
</Card>
1372+
<br />
1373+
12761374
- **On Forbidden: HTTP 403 Forbidden** - If attempted in the Production environment.
1277-
```json
1278-
{
1279-
"success": false,
1280-
"error": {
1281-
"code": "forbidden-operation",
1282-
"message": "Simulation API not allowed in this environment"
1283-
},
1284-
"traceId": "CV4PE82LTNJE9O014OE2"
1285-
}
1286-
```
1375+
<Card padding="nano" shape="rounded">
1376+
<details>
1377+
<summary>
1378+
<Text as="h6" marginBottom="none" marginTop="none">
1379+
Sample Response
1380+
</Text>
1381+
</summary>
1382+
<CodeBlockWithCopy language="json">{`
1383+
{
1384+
"success": false,
1385+
"error": {
1386+
"code": "forbidden-operation",
1387+
"message": "Simulation API not allowed in this environment"
1388+
},
1389+
"traceId": "CV4PE82LTNJE9O014OE2"
1390+
}
1391+
`}</CodeBlockWithCopy>
1392+
</details>
1393+
</Card>
1394+
<br />
1395+
12871396
- **On Not Found: HTTP 404 Not Found** - If the specified `billRefId` does not exist.
1288-
```json
1289-
{
1290-
"success": false,
1291-
"error": {
1292-
"code": "bill-not-found",
1293-
"message": "Bill with the specified refId not found"
1294-
},
1295-
"traceId": "CV4PE82LTNJE9O014OE4"
1296-
}
1297-
```
1397+
<Card padding="nano" shape="rounded">
1398+
<details>
1399+
<summary>
1400+
<Text as="h6" marginBottom="none" marginTop="none">
1401+
Sample Response
1402+
</Text>
1403+
</summary>
1404+
<CodeBlockWithCopy language="json">{`
1405+
{
1406+
"success": false,
1407+
"error": {
1408+
"code": "bill-not-found",
1409+
"message": "Bill with the specified refId not found"
1410+
},
1411+
"traceId": "CV4PE82LTNJE9O014OE4"
1412+
}
1413+
`}</CodeBlockWithCopy>
1414+
</details>
1415+
</Card>
1416+
<br />
1417+
12981418
- **On Server Error: HTTP 500 Internal Server Error**.
1299-
```json
1300-
{
1301-
"success": false,
1302-
"error": {
1303-
"code": "internal-error",
1304-
"message": "Internal Error"
1305-
},
1306-
"traceId": "CV4PE82LTNJE9O014OE2"
1307-
}
1308-
```
1419+
<Card padding="nano" shape="rounded">
1420+
<details>
1421+
<summary>
1422+
<Text as="h6" marginBottom="none" marginTop="none">
1423+
Sample Response
1424+
</Text>
1425+
</summary>
1426+
<CodeBlockWithCopy language="json">{`
1427+
{
1428+
"success": false,
1429+
"error": {
1430+
"code": "internal-error",
1431+
"message": "Internal Error"
1432+
},
1433+
"traceId": "CV4PE82LTNJE9O014OE2"
1434+
}
1435+
`}</CodeBlockWithCopy>
1436+
</details>
1437+
</Card>
1438+
<br />
13091439

13101440
**Handling the Asynchronous Callback Outcome:**
13111441

@@ -1323,7 +1453,7 @@ Shortly after receiving the 200 OK acknowledgment, your configured webhook liste
13231453
- Successful reception and processing of `SKIP_PAYMENT`.
13241454
- Handling potential errors if simulation is called with non-existent `upmsRegistrationRefId` or `billRefId`.
13251455
- **Correlation:** Pay attention to correlating the simulation API call with the resulting callback using `traceId` and the relevant reference IDs (`upmsRegistrationRefId`, `billRefId`).
1326-
- **Idempotency:** While simulating, consider how your webhook handler deals with potentially receiving the same callback event more than once.
1456+
- **Idempotency:** While simulating, ensure your webhook handler deals with potentially receiving the same callback event more than once.
13271457

13281458
This concludes the guide on integrating with Setu's UPMS APIs.
13291459

0 commit comments

Comments
 (0)