Process installment result
After a credit card payment is converted to an installment plan, AppotaPay will send the result notification to the partner's registered API URL so the partner can update the installment transaction status.
Note
- It is necessary to thoroughly check the parameters
transaction.status,transaction.paymentAmount, andsignatureto ensure they are valid before confirming the installment transaction as successful - Use the
signatureparameter to verify the integrity of the received data. The partner generates a signature from the data received from AppotaPay, then compares it with thesignatureparameter sent by AppotaPay - The signature is calculated on the raw Base64 string of the
datafield (not on the decoded JSON) — verifysignaturebefore decodingdata - The IPN may be sent more than once for the same transaction
- The
timefield is only a reference to the sending time and is not part of thesignaturecalculation
IPN (Instant Payment Notification)
AppotaPay will send the installment transaction result notification via the partner's registered API URL. The partner's server verifies the integrity of the data via the signature parameter and then updates the status of the installment transaction.
Header
{
"Content-Type": "application/json"
}
Response params
Method: POST
| Params | Data type | Description |
|---|---|---|
| data | String | The transaction information is in base64encode & json_encode format |
| signature | String | Signature to verify data integrity signature = |
| time | String | Response time |
Decode data
- The partner uses the
Base64Decodefunction to decode the data into a string. - Use the
JSON_Decodefunction to decode the data for the second time into JSON format.
| Params | Requirement | Data type | Description |
|---|---|---|---|
| transaction | required | Object | Installment transaction information |
| transaction.transactionId | required | String | Installment transaction code generated by AppotaPay |
| transaction.partnerCode | required | String | Partner identifier code |
| transaction.referenceId | required | String | Order code of the original payment transaction (orderId) |
| transaction.bankCode | required | String | Card-issuing bank code |
| transaction.authCode | required | String | Auth code |
| transaction.paymentAmount | required | Integer | Total installment transaction amount (VND) |
| transaction.payPerMonth | required | Integer | Monthly payment amount (VND) |
| transaction.feeConversion | required | Float | Installment conversion fee rate (%) of the selected loan package |
| transaction.loanPackageId | required | String | ID of the applied installment loan package |
| transaction.gracePeriod | required | String | Installment term (number of months) |
| transaction.status | required | String | Installment transaction status |
| transaction.statusCancel | optional | String | Installment cancellation status |
| transaction.errorCode | required | Integer | Installment transaction error code |
| transaction.errorMessage | required | String | Error description corresponding to errorCode |
| transaction.feePartner | required | Integer | Fee borne by the partner (VND) |
| transaction.feeUser | required | Integer | Fee borne by the customer (VND) |
| transaction.reasonCancel | optional | String | Reason for cancelling the installment transaction |
| transaction.reasonUpdate | optional | String | Reason for updating the transaction |
| transaction.completedAt | optional | Integer | Time the installment transaction was completed (Unix timestamp in seconds) |
| transaction.updatedAt | required | Integer | Last updated time (Unix timestamp in seconds) |
| transaction.createdAt | required | Integer | Installment transaction creation time (Unix timestamp in seconds) |
Status code table
| Status | Description |
|---|---|
| pending | The transaction is pending processing. |
| success | The transaction is successful. |
| error | The transaction has failed. |
Cancellation status code table
| Status | Description |
|---|---|
| wait_vendor | Waiting for the vendor to process the cancellation request |
| wait_bank | Vendor processed, waiting for bank confirmation |
| bank_reject | Bank rejected the cancellation request |
| rejected | The cancellation request was rejected |
| cancelled | The installment transaction has been cancelled successfully |
Error code table
| Error code | Description |
|---|---|
| 2 | Param is invalid |
| 35 | System error, please try again |
| 44 | An error occurred during processing |
| 45 | Card is invalid |
| 46 | Webhook IP is invalid |
| 47 | Partner signature is invalid |
| 49 | System error, not try again |
| 50 | Bank code is invalid |
| 52 | Have an error while connecting with provider |
| 53 | Payment gateway secret key lack |
| 54 | System can't cancel the transaction |
| 55 | Transaction canceled |
| 56 | Order ID has existed |
| 57 | Amount is invalid |
| 100 | New transaction |
| 101 | Waiting for conversion |
| 102 | Transferred request to bank |
| 103 | Succeeded |
| 104 | Failed (provider rejected request) |
| 105 | Failed (bank rejected request) |
| 108 | Canceled successfully |
| 109 | Transaction failed |
| 401 | Token is invalid |
Example Request:
{
"data": "eyJ0cmFuc2FjdGlvbiI6eyJ0cmFuc2FjdGlvbklkIjoiQVAyMDA5MTAwMTQxMjVCIiwicGFydG5lckNvZGUiOiJNRVJDSEFOVF9DT0RFIiwicmVmZXJlbmNlSWQiOiJNUkNfT1JERVJfMTIzNDUiLCJiYW5rQ29kZSI6IlZDQiIsImF1dGhDb2RlIjoiMTMxMjMzOCIsInBheW1lbnRBbW91bnQiOjEyMDAwMDAwLCJwYXlQZXJNb250aCI6MTAwMDAwMCwiZmVlQ29udmVyc2lvbiI6Mi41LCJsb2FuUGFja2FnZUlkIjoiTFBfVkNCXzEyTSIsImdyYWNlUGVyaW9kIjoiMTIiLCJzdGF0dXMiOiJzdWNjZXNzIiwic3RhdHVzQ2FuY2VsIjpudWxsLCJlcnJvckNvZGUiOjEwMywiZXJyb3JNZXNzYWdlIjoiU3VjY2VlZGVkIiwiZmVlUGFydG5lciI6MzAwMDAwLCJmZWVVc2VyIjowLCJyZWFzb25DYW5jZWwiOm51bGwsInJlYXNvblVwZGF0ZSI6bnVsbCwiY29tcGxldGVkQXQiOjE3ODI5OTA5MDAsInVwZGF0ZWRBdCI6MTc4Mjk5MDkwMCwiY3JlYXRlZEF0IjoxNzgyOTg3MzAwfX0=",
"time": 1782990900,
"signature": "171846e6962c5537c546ec5d6e6a864800db2366c330f418d7eff87661248a4c"
}
Decoded data
{
"transaction": {
"transactionId": "AP200910014125B",
"partnerCode": "MERCHANT_CODE",
"referenceId": "MRC_ORDER_12345",
"bankCode": "VCB",
"authCode": "1312338",
"paymentAmount": 12000000,
"payPerMonth": 1000000,
"feeConversion": 2.5,
"loanPackageId": "LP_VCB_12M",
"gracePeriod": "12",
"status": "success",
"statusCancel": null,
"errorCode": 103,
"errorMessage": "Succeeded",
"feePartner": 300000,
"feeUser": 0,
"reasonCancel": null,
"reasonUpdate": null,
"completedAt": 1782990900,
"updatedAt": 1782990900,
"createdAt": 1782987300
}
}
Response format
- When confirming a successful installment transaction via IPN, the partner needs to respond to AppotaPay to confirm that they have received the result
- In case the partner does not respond successfully, AppotaPay will attempt to respond up to 3 times, with an interval of about 5 minutes between each attempt
- The response is considered successful when
HTTP code = 200and thestatusparameter in the response body =ok
Example success response
HTTP Code: 200
Body:
{"status": "ok"}