AsiaPay Payment Gateway Integration
Comprehensive guide to integrate AsiaPay's secure online payment services into your application
Introduction
AsiaPay is a secure online payment gateway that enables merchants to process payments in Iraqi Dinar (IQD). This documentation provides developers with a comprehensive guide to integrate AsiaPay's payment services seamlessly into their applications.
Secure Payments
Process payments securely using industry-standard encryption and authentication mechanisms.
Easy Integration
Simple API allows for quick and hassle-free integration with your existing systems.
IQD Support
Full support for Iraqi Dinar (IQD) transactions with competitive processing fees.
Integration Flow
The diagram below illustrates the standard flow of integrating and processing payments with AsiaPay:
Create an instance of the AsiaPay client with your API credentials.
Obtain an authentication token using your App Key and App Secret.
Generate a payment order with the required transaction details.
Redirect the customer to the AsiaPay payment page using the URL from the order response.
Process the payment notification and redirect the customer back to your application.
Prerequisites
Before you begin integration with AsiaPay, ensure you have the following:
Merchant Account
You must have a registered merchant account with AsiaPay. Contact AsiaPay support to create an account if you don't have one already.
API Credentials
The following credentials will be provided by AsiaPay after your merchant account is approved:
- Domain URL (Production and Sandbox)
- App Key
- App Secret
- Private Key
- Merchant Code
- App ID
- Integration credentials – Used for JWT encoding/decoding.
Technical Requirements
Note: The integration examples in this documentation are based on PHP. However, the API can be integrated with any programming language that supports HTTP requests.
For PHP integration, you'll need:
- PHP 7.0 or higher
- Firebase JWT library (
composer require firebase/php-jwt) - cURL extension enabled
For .Net integration, you'll need below packages:
- dotnet add package System.IdentityModel.Tokens.Jwt
- dotnet add package Microsoft.IdentityModel.Tokens
Authentication
AsiaPay uses a token-based authentication system. You must first obtain a token before making any API calls.
Authentication Flow
- Make a POST request to the token endpoint using your App Key and App Secret
- Store the received token for subsequent API calls
- Include the token in the Authorization header for all API requests
Important: Authentication tokens are valid for a limited time. If a token expires, you'll need to generate a new one.
API Reference
This section details the endpoints available in the AsiaPay API.
Get Token
Authenticates and retrieves an access token.
| Endpoint | https://apitest.asiapay.iq:5443/apiaccess/payment/gateway/payment/v1/token
|
|---|---|
| Method | POST |
| Content Type | application/json |
Headers:
| Header | Value | Description |
|---|---|---|
| X-APP-Key | Your App Key | API key provided by AsiaPay |
| Content-Type | application/json | Request body format |
Request Body:
{
"appSecret": "YOUR_APP_SECRET"
}
Response:
{"token":"Bearer 76e0ac549fce799159aaf558694815c6","effectiveDate":"20250506233829","expirationDate":"20250507003829"}
Note: Regarding the Sign parmeter in the body of the request you need to sign the whole body of the request using AsiaPay PrivateKey (JWT) add the signed value in the sign paramter Signed value example eyJhbGciOiJIUzI1NiJ9.eyJtc2ciOiJzdWNjZXNzIiwicmVzdWx0IjoiU1VDQ0VTUyIsIm5vbmNlX3N0ciI6I jAyMWUzYWE2YjI3M zQwNTRiMGJmOWZjMjAwZmEzNTVhIiwiY29kZSI 6IjAiLCJtZXJjaF9vcmRlcl9pZCI6IjIxMjI5MTc2MzM5MDczMyIsInByZXBh eV9pZCI6IjA3N2U5OTdkYWYzZDU4ZTM 0ZTlkYThmYzQ4ZDJhMTM4ZTFjMDAxIn0.9Lf6tCJddOwS6W2AGJdbULY9mc8_7RvpllWxnnC4WXo
Create Order
Creates a payment order and returns a redirect URL for the payment page.
| Endpoint | https://apitest.asiapay.iq:5443/apiaccess/payment/gateway/payment/v1/merchant/preOrder
|
|---|---|
| Method | POST |
| Content Type | application/json |
Headers:
| Header | Value | Description |
|---|---|---|
| X-APP-Key | Your App Key | API key provided by AsiaPay |
| Content-Type | application/json | Request body format |
| Authorization | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ.. | Authorization Token |
Request Parameters
Create Order Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| appid | String | Yes | Application ID provided by AsiaPay |
| business_type | String | Yes | Type of transaction (e.g., "BuyGoods") |
| merch_code | String | Yes | Merchant code provided by AsiaPay |
| merch_order_id | String | Yes | Unique order ID generated by merchant |
| redirect_url | String | Yes | URL to redirect after payment completion |
| notify_url | String | Yes | Webhook URL for payment notifications |
| timeout_express | String | Yes | Order expiration time (e.g., "30m" for 30 minutes) |
| title | String | Yes | Order title/description |
| total_amount | String | Yes | Transaction amount (e.g., "12.00") |
| trade_type | String | Yes | Payment method type (e.g., "Checkout","Cross-App","PWA") PWA → for static URL usage. Checkout → for WebView scenario. Cross-App → for mobile payment flow. |
| trans_currency | String | Yes | Transaction currency (fixed to "IQD") |
| wallet_reference_data | Object | No | Contains operatorId and add Items in json format Example PHP: "VERSACE1"=> "15","VERSACE2"=> "9","VERSACE3"=> "15","VERSACE4"=> "9","operatorId"=>"9647731744404" |
Request Body:
{
"biz_content": {
"appid": "YOUR_APP_ID",
"business_type": "BuyGoods",
"merch_code": "YOUR_MERCHANT_CODE",
"merch_order_id": "UNIQUE_ORDER_ID",
"redirect_url": "YOUR_REDIRECT_URL",
"notify_url": "YOUR_NOTIFICATION_URL",
"timeout_express": "30m",
"title": "Order Title",
"total_amount": "12.00",
"trade_type": "Checkout",
"trans_currency": "IQD"
},
"method": "payment.preorder",
"nonce_str": "RANDOM_UNIQUE_STRING",
"sign_type": "JWTSecret",
"timestamp": "CURRENT_TIMESTAMP",
"version": "1.0",
"sign": "JWT_SIGNATURE"
}
Response:
{
"result": "SUCCESS",
"code": "0",
"msg": "success",
"nonce_str": "8941e36049bf4c2a9534a5ea11f81e51",
"sign": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"sign_type": "JWTSecret",
"biz_content": {
"merch_order_id": "212291746601184",
"prepay_id": "120bfb1ccc3a532b197cdb6fafad7493643002",
"redirect_url": "https://apitest.asiapay.iq:5443/payment/web/paygate?appid=1170344370329602&merch_code=260224&nonce_str=8941e36049bf4c2a9534a5ea11f81e51&prepay_id=120bfb1ccc3a532b197cdb6fafad7493643002×tamp=1746601183&sign=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&sign_type=JWTSecret&version=1.0™_type=Checkout&language=en"
}
}
Query Order
Checks the payment status of a previously created order using the merchant order ID.
| Endpoint | https://apitest.asiapay.iq:5443/apiaccess/payment/gateway/payment/v1/merchant/queryOrder
|
|---|---|
| Method | POST |
| Content Type | application/json |
Headers:
| Header | Value | Description |
|---|---|---|
| X-APP-Key | Your App Key | API key provided by AsiaPay |
| Content-Type | application/json | Request body format |
| Authorization | Bearer {your_token} | Authorization Token (JWT) |
Request Parameters
Query Order Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| appid | String | Yes | Application ID provided by AsiaPay |
| merch_code | String | Yes | Merchant code provided by AsiaPay |
| merch_order_id | String | Yes | Unique order ID to query |
Request Body:
{ "biz_content": { "appid": "1170344370329602", "merch_code": "260224", "merch_order_id": "20251746539388" },
"method": "payment.queryorder",
"nonce_str": "d3ef4d049ec44150b212efa76b7e2aa7",
"sign_type": "JWTSecret",
"timestamp": "CURRENT_TIMESTAMP",
"version": "1.0",
"sign": "JWT_SIGNATURE" }
Response:
{ "result": "SUCCESS",
"code": "0",
"msg": "success",
"nonce_str": "24755162ba4d42bcab7f411b55d6ead3",
"sign": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"sign_type": "JWTSecret",
"biz_content": { "merch_order_id": "20251746539388",
"order_status": "PAY_SUCCESS",
"trans_currency": "IQD",
"total_amount": "1250.000",
"trans_id": "0377830000000660613",
"trans_time": "2025-05-06 16:50:06",
"payment_order_id": "120011075616500500001001" } }
Refund Order
Initiates a refund for an existing payment order.
| Endpoint | https://apitest.asiapay.iq:5443/apiaccess/payment/gateway/payment/v1/merchant/refund
|
|---|---|
| Method | POST |
| Content Type | application/json |
Headers:
| Header | Value | Description |
|---|---|---|
| X-APP-Key | Your App Key | API key provided by AsiaPay |
| Content-Type | application/json | Request body format |
| Authorization | Bearer YOUR_TOKEN | JWT Bearer token for authentication |
Request Parameters
Refund Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| appid | String | Yes | Application ID provided by AsiaPay |
| merch_code | String | Yes | Merchant code provided by AsiaPay |
| merch_order_id | String | Yes | Original order ID to be refunded |
| refund_request_no | String | Yes | Unique ID for this refund request |
| refund_reason | String | Yes | Reason for the refund |
Request Body:
{ "biz_content": { "appid": "1170344370329602",
"merch_code": "260224",
"merch_order_id": "20251746603699",
"refund_request_no": "20250507",
"refund_reason": "Wala Etr" },
"method": "payment.refund",
"nonce_str": "1c6c09a41156478b892626cc5d383fa0",
"sign_type": "JWTSecret",
"timestamp": "1746603834",
"version": "1.0",
"sign": "JWT_SIGNATURE" }
Response:
{ "result": "SUCCESS",
"code": "0",
"msg": "success",
"nonce_str": "0f710dce49a94f12a1bd3476121c45f6",
"sign": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"sign_type": "JWTSecret",
"biz_content": { "merch_order_id": "20251746603699",
"trans_order_id": "120011075710424400001001",
"refund_order_id": "120010075710435500001001",
"refund_amount": "1250.000",
"refund_currency": "IQD",
"refund_status": "REFUND_SUCCESS",
"refund_time": "2025-05-07 10:43:55",
"business_type": "BuyGoods" } }
AsiaPay Payment Webhook Integration Guide
Overview
The AsiaPay Payment Webhook allows merchants to receive automatic notifications when a payment transaction is updated or completed.
AsiaPay sends an HTTP POST request containing transaction details in JSON format to the merchant's configured webhook URL
(notify_url). The merchant is responsible for implementing an endpoint that listens for incoming POST requests, validates the
notification, and updates the payment status in its system.
Webhook Configuration
The merchant must provide a publicly accessible HTTPS endpoint to receive payment notifications.
Example Webhook URL:
https://yourdomain.com/api/payment/webhook
HTTP Request Details:
| Property | Value |
|---|---|
| Method | POST |
| Content-Type | application/json |
| Protocol | HTTPS |
| Payload | JSON |
| Authentication | Signature verification |
The webhook endpoint must accept incoming POST requests from AsiaPay.
Example Webhook Notification
{
"notify_url": "https://asiapaytest.free.beeceptor.com",
"appid": "",
"notify_time": "1782287734170",
"merch_code": "",
"merch_order_id": "19328238601",
"payment_order_id": "198011086O10550900001001",
"total_amount": "1.000",
"trans_currency": "IQD",
"trade_status": "Completed",
"trans_end_time": "1782287711000",
"trans_id": "04192000000001022150",
"sign": "<signature-value>",
"sign_type": "JWTSecret"
}
The sign value is shortened for readability. Actual webhook requests contain the complete signature.
Webhook Parameters
| Parameter | Description |
|---|---|
notify_url | Configured webhook notification URL |
appid | Application identifier assigned by AsiaPay |
notify_time | Notification timestamp in milliseconds |
merch_code | Merchant code assigned by AsiaPay |
merch_order_id | Merchant's original order ID |
payment_order_id | Payment order ID generated by the payment platform |
total_amount | Transaction amount |
trans_currency | Transaction currency, such as IQD |
trade_status | Payment transaction status |
trans_end_time | Transaction completion timestamp in milliseconds |
trans_id | AsiaPay transaction reference ID |
sign | Digital signature for verification |
sign_type | Signature mechanism identifier |
How the Webhook Works
- The customer initiates a payment through AsiaPay.
- AsiaPay processes the transaction.
- The payment platform generates a notification containing transaction details.
- AsiaPay sends an HTTP POST request to the merchant's configured
notify_url. - The merchant's backend receives the JSON payload.
- The merchant validates the signature and checks the transaction details.
- The merchant updates the corresponding order status in its database.
- The merchant returns the required acknowledgment response to AsiaPay.
Example Webhook Implementation (Java Spring Boot)
The following example demonstrates how to receive an AsiaPay webhook using Java Spring Boot.
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/api/payment")
public class PaymentWebhookController {
@PostMapping("/webhook")
public ResponseEntity<String> receiveWebhook(
@RequestBody Map<String, Object> payload) {
String merchantOrderId =
String.valueOf(payload.get("merch_order_id"));
String transactionId =
String.valueOf(payload.get("trans_id"));
String paymentStatus =
String.valueOf(payload.get("trade_status"));
String signature =
String.valueOf(payload.get("sign"));
// TODO: Verify signature using the
// officially configured AsiaPay signing method.
// TODO: Validate merchant, amount, currency,
// and original order information.
// TODO: Update the payment status only
// after successful verification.
System.out.println("Order ID: " + merchantOrderId);
System.out.println("Transaction ID: " + transactionId);
System.out.println("Payment Status: " + paymentStatus);
return ResponseEntity.ok("SUCCESS");
}
}
Important: This example demonstrates how to receive the POST request only. Signature verification
and database updates must be implemented before production deployment. The acknowledgment body
SUCCESS is illustrative and must be replaced with the exact response format required by the
AsiaPay integration specification.
Testing the Webhook
The merchant can test its webhook endpoint using Postman or cURL.
Example cURL Request:
curl -X POST \
"https://yourdomain.com/api/payment/webhook" \
-H "Content-Type: application/json" \
-d '{
"appid": "1170344370329602",
"merch_code": "260224",
"merch_order_id": "19328238601",
"payment_order_id": "198011086O10550900001001",
"total_amount": "1.000",
"trans_currency": "IQD",
"trade_status": "Completed",
"trans_id": "04192000000001022150",
"sign_type": "JWTSecret",
"sign": "<signature-value>"
}'
This test verifies whether the endpoint accepts POST requests. A valid signed notification is required to test signature verification.
Security Recommendations
- Use HTTPS with a valid, trusted SSL/TLS certificate.
- Verify the webhook signature before processing transactions.
- Validate the merchant code, application ID, order ID, amount, and currency against the original payment.
- Prevent duplicate processing of the same transaction.
- Never mark an order as paid solely because a request contains
trade_status: Completed. - Keep signing credentials secure.
- Return the acknowledgment only after the notification has been safely handled according to the integration requirements.
Important Notes
- The merchant must implement a POST endpoint to receive payment notifications.
- The webhook URL must be accessible from AsiaPay's notification infrastructure.
- AsiaPay sends transaction information to the configured notification URL.
- The merchant should process notifications securely and support duplicate deliveries.
- The signature verification algorithm and acknowledgment format must follow the agreed AsiaPay integration specification.
Code Examples
Complete Integration Example
<?php
// 1. Include the AsiaPay Integration Class
require_once 'AsiaPayIntegration.php';
// 2. Configure your API credentials
$domain = "https://apitest.asiapay.iq:5443/apiaccess";
$appKey = "your-app-key";
$appSecret = "your-app-secret";
$privateKey = "your-private-key";
// 3. Set up order parameters
$appid = "your-app-id";
$businessType = "BuyGoods";
$merchCode = "your-merchant-code";
$merchOrderId = "ORDER" . time(); // Generate unique order ID
$redirectUrl = "callbackUrl=your.app.scheme";
$notifyUrl = "https://your-server.com/webhook";
$timeoutExpress = "30m";
$title = "Product Purchase";
$totalAmount = "50.00";
$tradeType = "Checkout";
try {
// 4. Initialize the AsiaPay client
$client = new AsiaPayIntegration($domain, $appKey, $appSecret, $privateKey);
// 5. Create a payment order
$response = $client->createOrder(
$appid,
$businessType,
$merchCode,
$merchOrderId,
$redirectUrl,
$notifyUrl,
$timeoutExpress,
$title,
$totalAmount,
$tradeType
);
// 6. Handle the response
if (isset($response['biz_content']['redirect_url'])) {
// For web applications:
header("Location: " . $response['biz_content']['redirect_url']);
exit;
// For mobile applications, return the URL to the app
// echo json_encode(['payment_url' => $response['biz_content']['redirect_url']]);
} else {
// Handle error
echo "Error: " . $response['message'];
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
?>
public static String createOrder(String appSecret, String appId, String appKey, String merchCode, String redirectUrl, String notifyUrl, String timeout, String title, String totalAmount, String privateKey) {
String nonceStr = UUID.randomUUID().toString().replace("-", "");
long timestamp = Instant.now().getEpochSecond();
Map<String,Object>bizContent = new HashMap<>();
bizContent.put("appid", appId);
bizContent.put("merch_code", merchCode);
bizContent.put("merch_order_id", "2025" + timestamp);
bizContent.put("redirect_url", redirectUrl);
bizContent.put("notify_url", notifyUrl);
bizContent.put("timeout_express", timeout);
bizContent.put("title", title);
bizContent.put("total_amount", totalAmount);
bizContent.put("trade_type", "Checkout");
bizContent.put("trans_currency", "IQD");
Map<String, Object> data = new HashMap<>();
data.put("biz_content", bizContent);
data.put("method", "payment.preorder");
data.put("nonce_str", nonceStr);
data.put("sign_type", "JWTSecret");
data.put("timestamp", String.valueOf(timestamp));
data.put("version", "1.0");
String jwt = AsiapayIntegration.createJwt(data, privateKey);
data.put("sign", jwt);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(data, AsiapayIntegration.getHttpHeaders(appKey, appSecret, TOKEN_URL));
ResponseEntity<JsonNode> response = restTemplate.exchange(PRE_ORDER_URL, HttpMethod.POST, request, JsonNode.class);
return String.valueOf(response.getBody().get("biz_content").get("redirect_url").asText());
}
// 1. Import the AsiaPay Integration Module
const AsiaPayClient = require('asiapay-sdk');
// 2. Configure your API credentials
const domain = 'https://apitest.asiapay.iq:5443/apiaccess';
const appKey = 'your-app-key';
const appSecret = 'your-app-secret';
const privateKey = 'your-private-key';
// 3. Set up order parameters
const orderParams = {
appid: 'your-app-id',
businessType: 'BuyGoods',
merchCode: 'your-merchant-code',
merchOrderId: `ORDER${Date.now()}`, // Generate unique order ID
redirectUrl: 'callbackUrl=your.app.scheme',
notifyUrl: 'https://your-server.com/webhook',
timeoutExpress: '30m',
title: 'Product Purchase',
totalAmount: '50.00',
tradeType: 'Checkout'
};
async function createPaymentOrder() {
try {
// 4. Initialize the AsiaPay client
const client = new AsiaPayClient({
domain,
appKey,
appSecret,
privateKey
});
// 5. Create a payment order
const response = await client.createOrder(orderParams);
// 6. Handle the response
if (response.biz_content && response.biz_content.redirect_url) {
// For web applications:
console.log(`Payment URL: ${response.biz_content.redirect_url}`);
// For Express.js web applications:
// res.redirect(response.biz_content.redirect_url);
// For mobile/React Native applications, return the URL:
// res.json({ payment_url: response.biz_content.redirect_url });
} else {
console.error('Error:', response.message);
}
} catch (error) {
console.error('Error:', error.message);
}
}
// Execute the payment order creation
createPaymentOrder();
import time
import requests
from asiapay_sdk import AsiaPayClient, OrderRequest
# 1. Configure your API credentials
domain = "https://apitest.asiapay.iq:5443/apiaccess"
app_key = "your-app-key"
app_secret = "your-app-secret"
private_key = "your-private-key"
# 2. Set up order parameters
appid = "your-app-id"
business_type = "BuyGoods"
merch_code = "your-merchant-code"
merch_order_id = f"ORDER{int(time.time())}" # Generate unique order ID
redirect_url = "callbackUrl=your.app.scheme"
notify_url = "https://your-server.com/webhook"
timeout_express = "30m"
title = "Product Purchase"
total_amount = "50.00"
trade_type = "Checkout"
def create_payment_order():
try:
# 3. Initialize the AsiaPay client
client = AsiaPayClient(
domain=domain,
app_key=app_key,
app_secret=app_secret,
private_key=private_key
)
# 4. Create order request object
order = OrderRequest(
appid=appid,
business_type=business_type,
merch_code=merch_code,
merch_order_id=merch_order_id,
redirect_url=redirect_url,
notify_url=notify_url,
timeout_express=timeout_express,
title=title,
total_amount=total_amount,
trade_type=trade_type
)
# 5. Create a payment order
response = client.create_order(order)
# 6. Handle the response
if 'biz_content' in response and 'redirect_url' in response['biz_content']:
payment_url = response['biz_content']['redirect_url']
print(f"Payment URL: {payment_url}")
# For Flask applications:
# return redirect(payment_url)
# For API endpoints:
# return jsonify({"payment_url": payment_url})
else:
print(f"Error: {response.get('message', 'Unknown error')}")
except Exception as e:
print(f"Error: {str(e)}")
# Execute the payment order creation
if __name__ == "__main__":
create_payment_order()
Support & FAQ
How do I get credentials?
You can contact the B2B team for registering your wallet: b2bchannel@asiapay.iq
Who do I contact for help?
Email our technical support team at devops@asiapay.iq.