Skip to main content
Version: Lastest

API Mobile Topup Async

Endpoint: /api/v2/service/topup/charging-async

Method: POST

Header: How to generate JWT_TOKEN

Language: en | vi

{
"X-APPOTAPAY-AUTH": Bearer JWT_TOKEN,
"Content-Type": "application/json",
"Language": LANGUAGE
}
Prerequisites
  • The partner must register an IPN URL with AppotaPay before using this API. Without an IPN URL, AppotaPay cannot deliver the transaction result to the partner.
  • This API only confirms that the transaction has been accepted, it does not return the topup result. The final result is delivered through the IPN.
  • See also the asynchronous flow overview.

Params​

ParamsRequiredTypeDescriptionNote
partnerRefId√StringThis is unique code corresponding to a request sendmax_length: 50
telcoStringVendor name (see more Table of content list vendor)
telcoServiceType√StringService type

prepaid: Topup mobile prepaid

postpaid: Topup mobile postpaid

productCode√StringProduct code (see more API to get list product code)
phoneNumber√StringPhone number charge topup (format: 09x, 08x,..)
signature√StringSignature of parameter passed to the API, the parameter is included into signature like this: partnerRefId + phoneNumber + productCode + telco + telcoServiceType (see more how to generate signature)

Note:

- APPOTAPAY has supported Partners in proactively checking the network of the transmitted phone number.

- Partners can use the common product code table to transmit to the API without having to clearly define the product_code according to each network of the phone number (This code table is used for regular topup, not for data topup).

Data result​

ParamsTypeDescription
errorCodeIntegerError code result.

35: the transaction has been accepted and is waiting to be processed

Other codes: the transaction was not accepted (see the error code table)

messageStringDescription error code detail

Note: errorCode = 35 is not the final result of the transaction. The partner may only mark the order as succeeded/failed when receiving an IPN with a final status or when the transaction status API returns a final status.

Example​

Request​

{
"partnerRefId": "AB123",
"telco": "viettel",
"telcoServiceType": "prepaid",
"phoneNumber": "0866123456",
"productCode": "viettel_10",
"signature": "5a2774918a29cf4d2bdb78cccceb956f4c27837fad09a03a56e1df68b1bf29dd"
}

Response​

Transaction accepted

{
"errorCode": 35,
"message": "Transaction is pending, please try again later"
}

Transaction not accepted

{
"errorCode": 31,
"message": "Duplicate transaction"
}

IPN (Instant Payment Notification)​

When a transaction reaches its final result, AppotaPay sends a notification to the IPN URL registered by the partner. The partner verifies the data integrity through the signature parameter and then updates the order status.

Method: POST

{
"Content-Type": "application/json"
}

Params sent by AppotaPay​

ParamsTypeDescription
errorCodeIntegerTransaction error code. 0 when the topup succeeded, other than 0 when it failed (see the error code table)
statusStringFinal transaction status: success or error
appotapayTransIdStringTransaction id from AppotaPay
partnerRefIdStringTransaction id from the partner
phoneNumberStringPhone number to charge topup
productCodeStringProduct code
amountIntegerTransaction amount
topupAmountIntegerAmount topped up for the subscriber
telcoStringVendor name

Telco may be different from the input request due to actual data recorded from provider

telcoServiceTypeStringService type (This value may vary based on the actual information returned by the telecom provider.)
timeStringTopup time (in RFC-3339 standard format)
signatureStringSignature of the IPN data, the signed fields are (amount + appotapayTransId + errorCode + partnerRefId + phoneNumber + productCode + status + telco + telcoServiceType + time + topupAmount)

How to verify the signature​

The params used to build the signature are sorted alphabetically, joined as key=value pairs separated by &, then signed with HMAC_SHA256 using the partner SECRET_KEY.

signature = HMAC_SHA256("amount=10000&appotapayTransId=01J7G2DYZTPCGHM3AAF8ANZC7J&errorCode=0&partnerRefId=AB123&phoneNumber=0866123456&productCode=viettel_10&status=success&telco=viettel&telcoServiceType=prepaid&time=2026-08-17T10:15:30+07:00&topupAmount=10000", YOUR_SECRET_KEY)

The partner regenerates the signature from the received data and compares it with the signature sent by AppotaPay. If they do not match, the order must not be updated.

IPN examples​

Successful transaction

{
"errorCode": 0,
"status": "success",
"appotapayTransId": "01J7G2DYZTPCGHM3AAF8ANZC7J",
"partnerRefId": "AB123",
"phoneNumber": "0866123456",
"productCode": "viettel_10",
"amount": 10000,
"topupAmount": 10000,
"telco": "viettel",
"telcoServiceType": "prepaid",
"time": "2026-08-17T10:15:30+07:00",
"signature": "44b2e44eaaecfbbe5d9512c323affad5a9515a7f606afc486de80b7c2f771f2f"
}

Failed transaction

{
"errorCode": 33,
"status": "error",
"appotapayTransId": "01J7G2DYZTPCGHM3AAF8ANZC7J",
"partnerRefId": "AB124",
"phoneNumber": "0866123456",
"productCode": "viettel_10",
"amount": 10000,
"topupAmount": 10000,
"telco": "viettel",
"telcoServiceType": "prepaid",
"time": "2026-08-17T10:15:30+07:00",
"signature": "046ae200d3210f0a5417ac2b3a8ccc83edf6452f00c8655fd31a13e73e1f84d8"
}

Response expected from the partner​

The partner returns HTTP 200 to confirm the IPN was received successfully. Any HTTP code other than 200 is treated by AppotaPay as a failed IPN delivery.

CriteriaValue
Success acknowledgement codeHTTP 200
Connect timeout5 seconds
Response timeout10 seconds
Maximum delivery attempts4 (including the first attempt)
Interval between retries5 minutes
Notes
  • AppotaPay only sends an IPN once the transaction has a final result (status is success or error), never while the transaction is still being processed.
  • The same transaction may be delivered several times. The partner system must prevent duplicate processing by partnerRefId: if the order result was already updated, skip it and still return HTTP 200.
  • If all 4 attempts fail, AppotaPay stops retrying. The partner should call the transaction status API for reconciliation, or contact AppotaPay to resend the IPN manually.
  • Only confirm a transaction as successful when status = success, errorCode = 0 and the signature is valid.

Code Examples​

curl --location 'https://gateway.dev.appotapay.com/api/v2/service/topup/charging-async' \
--header 'X-APPOTAPAY-AUTH: JWT_TOKEN' \
--header 'Content-Type: application/json' \
-d '{
"partnerRefId": "AB123",
"telco": "viettel",
"telcoServiceType": "prepaid",
"phoneNumber": "0866123456",
"productCode": "viettel_10",
"signature": "5a2774918a29cf4d2bdb78cccceb956f4c27837fad09a03a56e1df68b1bf29dd"
}'

Request​

REQUEST

Development server
Example (from schema)