[New Connector] asiapay — Authorize, PSync, Capture, Void, Refund, RSync, SetupMandate, RepeatPayment, IncomingWebhook
- Dominant language
- Python
- Stars
- 4
- Forks
- 6
- PR merge metrics
- No merged PRs in 30d
Description
# asiapay — New Connector Integration
**Workflow:** new-connector
**Flows:** Authorize, PSync, Capture, Void, Refund, RSync, SetupMandate, RepeatPayment, IncomingWebhook
**Auth scheme:** Signature
**Currency unit:** Minor
**Base URL:** https://www.paydollar.com/b2c2/eng/directPay/payComp.jsp
**Sandbox URL:** https://test.paydollar.com/b2cDemo/eng/directPay/payComp.jsp
**Generated by:** Grace pipeline run `run-2026-05-22T00-56-38-358Z-8be51f`
## Discovered Docs
- https://developer.asiapay.com/
- https://www.paydollar.com/pdf/op/enpdintguide.pdf
- https://docs.portone.cloud/docs/asiapay
## Acceptance Criteria
- [ ] Authorize flow compiles and runs
- [ ] gRPC Authorize call succeeds against sandbox
---
## Tech Spec
# AsiaPay UCS Connector Integration Technical Specification
## Connector Profile
- **Connector Name**: AsiaPay (brand family: PayDollar, PesoPay, SiamPay, BimoPay)
- **Owning Company**: AsiaPay Limited
- **Production Base URL (Legacy Direct Connect)**: `https://www.paydollar.com/b2c2/eng/directPay/payComp.jsp`
- **Production Base URL (Client Post / Redirect)**: `https://www.paydollar.com/b2c2/eng/dPayment/payComp.jsp`
- **Production Base URL (Modern JSON API)**: `https://api.asiapay.iq/apiaccess`
- **Sandbox Base URL (Legacy)**: `https://test.paydollar.com/b2cDemo/eng/directPay/payComp.jsp`
- **Sandbox Base URL (Modern API)**: `https://apitest.asiapay.iq:5443/apiaccess`
- **Supported Countries**: Hong Kong, China, Macau, Taiwan, Singapore, Malaysia, India, Vietnam, Australia, New Zealand, Philippines, Thailand, Indonesia
- **Regional Brand Names**: PayDollar (HK/CN/SG/AU/NZ/MY/IN/VN/MO/TW), PesoPay (PH), SiamPay (TH), BimoPay (ID)
- **Supported Currencies**: HKD, USD, SGD, CNY, JPY, TWD, AUD, EUR, GBP, CAD, MOP, PHP, THB, MYR, IDR, KRW, SAR, NZD, AED, BND
## Authentication
AsiaPay exposes two API paradigms. UCS should target the **Modern JSON REST API** where possible; fall back to Legacy for unsupported operations.
### Legacy PayDollar Direct Connect (Server-to-Server Form POST)
**Scheme**: SHA1 HMAC Signature
**Auth Location**: Body (`secureHash` parameter)
**Credential Fields**:
- `merchantId` — Merchant identifier assigned by AsiaPay
- `secureHashSecret` — Shared secret for SHA1 HMAC computation
**Signature Algorithm**:
```
secureHash = SHA1(merchantId + "|" + orderRef + "|" + currCode + "|" + amt + "|" + payType + "|" + secureHashSecret)
```
The `secureHash` is appended as a form field. No HTTP Authorization header is used.
### Modern AsiaPay JSON REST API
**Scheme**: Bearer Token (short-lived) + JWT body signature
**Auth Location**: Header (`Authorization: Bearer {token}`) + Body (`sign` parameter)
**Credential Fields**:
- `appid` — Application ID issued by AsiaPay
- `merch_code` — Merchant code
- `app_key` — Key used to obtain Bearer token
- `app_secret` — Secret used to obtain Bearer token
- `private_key` — RSA private key for JWT request body signing
**Token Acquisition**:
```
POST /apiaccess/token
Authorization: Basic base64(app_key:app_secret)
```
Token response:
```json
{
"token": "Bearer 76e0ac549fce799159aaf558694815c6",
"effectiveDate": "20250506233829",
"expirationDate": "20250507003829"
}
```
Tokens expire after ~1 hour. Renew before expiry.
**Request Signing**: Serialize `biz_content` to JSON, sign with RSA private key using JWT (sign_type = `JWTSecret`), place result in top-level `sign` field.
**Authorization Header**:
```
Authorization: Bearer {token}
Content-Type: application/json
```
## Supported Flows
| Flow | HTTP Method | Endpoint Path | Idempotency | Notes |
|------|-------------|---------------|-------------|-------|
| Authorize | POST | `payment.preorder` (modern) or `/directPay/payComp.jsp` with `payType=AUTH` (legacy) | `merch_order_id` / `orderRef` | Pre-auth; not settled until Capture |
| Capture | POST | `payment.capture` (modern) or merchant admin portal (legacy) | `merch_order_id` | Must capture within 14 days or auth released |
| Void | POST | `payment.void` (modern) or merchant admin portal (legacy) | `merch_order_id` | Cancel authorized transaction |
| Refund | POST | `payment.refund` (modern) | `merch_order_id` | Full refund within 24h; partial after 24h |
| PSync | POST | `payment.queryorder` | `merch_order_id` | Query payment status |
| RSync | POST | `payment.queryorder` with refund ref | `refund_order_id` | Query refund status |
| RepeatPayment | POST | Schedule Payment API | Schedule ID | Weekly/Monthly/Quarterly/SemiAnnual/Annual |
| IncomingWebhook | POST | `{merchantNotifyUrl}` (merchant-configured) | — | AsiaPay POSTs to merchant; respond CBTOKEN:MPSTATOK |
## Request Schema
### Authorize Request
**Modern API**:
```json
{
"method": "payment.preorder",
"nonce_str": "a1b2c3d4e5f6",
"sign_type": "JWTSecret",
"timestamp": "20250522120000",
"version": "1.0",
"biz_content": {
"appid": "your-app-id",
"businessType": "BuyGoods",
"merchCode": "your-merchant-code",
"merchOrderId": "ORDER-20250522-001",
"redirectUrl": "https://merchant.com/success",
"notifyUrl": "https://merchant.com/webhook",
"timeoutExpress": "30",
"title": "Order description",
"totalAmount": 1000,
"tradeType": "Checkout",
"transCurrency": "HKD"
},
"sign": "jwt-signed-biz-content-string"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| method | String | Yes | API method: `payment.preorder` |
| nonce_str | String | Yes | Unique random string for replay prevention |
| sign_type | String | Yes | Signature type: `JWTSecret` |
| timestamp | String | Yes | Request timestamp (YYYYMMDDHHmmss) |
| version | String | Yes | API version: `1.0` |
| biz_content.appid | String | Yes | Application ID |
| biz_content.businessType | String | Yes | `BuyGoods` |
| biz_content.merchCode | String | Yes | Merchant code |
| biz_content.merchOrderId | String | Yes | Unique merchant order ID |
| biz_content.redirectUrl | String | Yes | URL to redirect user after payment |
| biz_content.notifyUrl | String | Yes | Server-to-server webhook URL |
| biz_content.timeoutExpress | String | No | Payment session timeout in minutes |
| biz_content.title | String | Yes | Payment description shown to payer |
| biz_content.totalAmount | Integer | Yes | Amount in minor units (cents) |
| biz_content.tradeType | String | Yes | `Checkout` |
| biz_content.transCurrency | String | Yes | ISO 4217 alpha-3 currency code |
| sign | String | Yes | JWT signature of biz_content |
**Legacy Direct Connect (Form POST)**:
```json
{
"merchantId": "88888888",
"amount": "10.00",
"currCode": "344",
"mpsMode": "NIL",
"successUrl": "https://merchant.com/success",
"failUrl": "https://merchant.com/fail",
"cancelUrl": "https://merchant.com/cancel",
"payType": "N",
"lang": "E",
"orderRef": "ORDER-20250522-001",
"remark": "Order description",
"cardNo": "4111111111111111",
"cardHolder": "John Doe",
"cardExpiryMo": "12",
"cardExpiryYr": "2026",
"cardSecurityCode": "123",
"secureHash": "computed-sha1-hash"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| merchantId | String | Yes | AsiaPay-assigned merchant ID |
| amount | Numeric(12,2) | Yes | Amount in major units (e.g., 10.00 for $10) |
| currCode | String(3) | Yes | ISO 4217 numeric code (344=HKD, 840=USD, etc.) |
| mpsMode | String | Yes | Currency mode: NIL, MCP, SCP, or DCC |
| successUrl | String | Yes | Redirect on success |
| failUrl | String | Yes | Redirect on failure |
| cancelUrl | String | No | Redirect on user cancel |
| payType | String | Yes | `N`=Normal sale, `AUTH`=Pre-authorize, `CREDIT`=Refund |
| lang | String | Yes | `E`=English, `C`=Chinese(T), `X`=Chinese(S), `K`=Korean, `J`=Japanese, `T`=Thai |
| orderRef | String(35) | Yes | Unique merchant order reference |
| remark | String(100) | No | Order description |
| cardNo | String | Yes (direct) | PAN |
| cardHolder | String | Yes (direct) | Cardholder name |
| cardExpiryMo | String(2) | Yes (direct) | Expiry month MM |
| cardExpiryYr | String(4) | Yes (direct) | Expiry year YYYY |
| cardSecurityCode | String(4) | No | CVV/CVC |
| secureHash | String | Yes (if enabled) | SHA1 HMAC signature |
### Capture Request
```json
{
"method": "payment.capture",
"nonce_str": "unique-nonce",
"sign_type": "JWTSecret",
"timestamp": "20250522120000",
"version": "1.0",
"biz_content": {
"appid": "your-app-id",
"merchCode": "your-merchant-code",
"merchOrderId": "ORDER-20250522-001",
"captureAmount": 1000
},
"sign": "jwt-signature"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| biz_content.appid | String | Yes | Application ID |
| biz_content.merchCode | String | Yes | Merchant code |
| biz_content.merchOrderId | String | Yes | Original order ID to capture |
| biz_content.captureAmount | Integer | Yes | Amount to capture in minor units |
### Void Request
```json
{
"method": "payment.void",
"nonce_str": "unique-nonce",
"sign_type": "JWTSecret",
"timestamp": "20250522120000",
"version": "1.0",
"biz_content": {
"appid": "your-app-id",
"merchCode": "your-merchant-code",
"merchOrderId": "ORDER-20250522-001"
},
"sign": "jwt-signature"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| biz_content.appid | String | Yes | Application ID |
| biz_content.merchCode | String | Yes | Merchant code |
| biz_content.merchOrderId | String | Yes | Original order ID to void |
### Refund Request
```json
{
"method": "payment.refund",
"nonce_str": "unique-nonce",
"sign_type": "JWTSecret",
"timestamp": "20250522120000",
"version": "1.0",
"biz_content": {
"appid": "your-app-id",
"merchCode": "your-merchant-code",
"merchOrderId": "ORDER-20250522-001",
"refundAmount": 500,
"refundReason": "Customer request"
},
"sign": "jwt-signature"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| biz_content.appid | String | Yes | Application ID |
| biz_content.merchCode | String | Yes | Merchant code |
| biz_content.merchOrderId | String | Yes | Original order ID |
| biz_content.refundAmount | Integer | Yes | Refund amount in minor units |
| biz_content.refundReason | String | No | Reason for refund |
### PSync Request
```json
{
"method": "payment.queryorder",
"nonce_str": "unique-nonce",
"sign_type": "JWTSecret",
"timestamp": "20250522120000",
"version": "1.0",
"biz_content": {
"appid": "your-app-id",
"merchCode": "your-merchant-code",
"merchOrderId": "ORDER-20250522-001"
},
"sign": "jwt-signature"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| biz_content.appid | String | Yes | Application ID |
| biz_content.merchCode | String | Yes | Merchant code |
| biz_content.merchOrderId | String | Yes | Merchant order ID to query |
### RSync Request
```json
{
"method": "payment.queryorder",
"nonce_str": "unique-nonce",
"sign_type": "JWTSecret",
"timestamp": "20250522120000",
"version": "1.0",
"biz_content": {
"appid": "your-app-id",
"merchCode": "your-merchant-code",
"refundOrderId": "REFUND-20250522-001"
},
"sign": "jwt-signature"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| biz_content.refundOrderId | String | Yes | AsiaPay refund reference ID to query |
### RepeatPayment Request (Schedule Payment)
```json
{
"method": "recurring.schedule",
"nonce_str": "unique-nonce",
"sign_type": "JWTSecret",
"timestamp": "20250522120000",
"version": "1.0",
"biz_content": {
"appid": "your-app-id",
"merchCode": "your-merchant-code",
"scheduleType": "Monthly",
"startDate": "20250601",
"amount": 1000,
"currency": "HKD",
"cardToken": "stored-card-token",
"notifyUrl": "https://merchant.com/webhook"
},
"sign": "jwt-signature"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| biz_content.scheduleType | String | Yes | `Weekly`, `Monthly`, `Quarterly`, `SemiAnnual`, `Annual` |
| biz_content.startDate | String | Yes | First payment date YYYYMMDD |
| biz_content.amount | Integer | Yes | Recurring amount in minor units |
| biz_content.currency | String | Yes | ISO 4217 alpha-3 currency code |
| biz_content.cardToken | String | Yes | Stored card token from initial payment |
| biz_content.notifyUrl | String | No | Webhook URL for recurring charge notifications |
## Response Schema
### Authorize Response
**Success (Modern API)**:
```json
{
"code": "0",
"biz_content": {
"redirect_url": "https://www.paydollar.com/payment/page?ref=abc123",
"merch_order_id": "ORDER-20250522-001",
"pay_ref": "12345678"
}
}
```
**Error Response**:
```json
{
"code": "1001",
"message": "Invalid signature",
"biz_content": null
}
```
| Field | Type | Description |
|-------|------|-------------|
| code | String | `0` = success; other = error code |
| message | String | Error description when code != `0` |
| biz_content.redirect_url | String | URL to redirect user for hosted checkout |
| biz_content.merch_order_id | String | Echoed merchant order ID |
| biz_content.pay_ref | String | AsiaPay internal payment reference |
**Success (Legacy Direct Connect)**:
```
Ref=12345678&successcode=0&Ord=ORDER-001&Amt=10.00&Cur=344&prc=00&src=00&Holder=John+Doe&AuthId=AUTH001&TxTime=20250522120000&payerAuth=Y
```
| Field | Type | Description |
|-------|------|-------------|
| successcode | String | `0`=Success, `1`=Failure |
| Ref | String | AsiaPay transaction reference |
| Ord | String | Merchant order reference |
| Amt | String | Transaction amount in major units |
| Cur | String | ISO 4217 numeric currency code |
| prc | String | Primary Response Code (`00`=Approved) |
| src | String | Secondary Response Code |
| AuthId | String | Bank authorization ID |
| TxTime | String | Transaction timestamp |
| payerAuth | String | `Y`=3DS authenticated, `N`=not |
### Capture Response
```json
{
"code": "0",
"biz_content": {
"merch_order_id": "ORDER-20250522-001",
"pay_ref": "12345678",
"status": "CAPTURED"
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| code | String | `0` = success |
| biz_content.status | String | `CAPTURED` on success |
| biz_content.pay_ref | String | AsiaPay payment reference |
### Void Response
```json
{
"code": "0",
"biz_content": {
"merch_order_id": "ORDER-20250522-001",
"pay_ref": "12345678",
"status": "VOIDED"
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| code | String | `0` = success |
| biz_content.status | String | `VOIDED` on success |
### Refund Response
```json
{
"code": "0",
"biz_content": {
"merch_order_id": "ORDER-20250522-001",
"refund_order_id": "REFUND-20250522-001",
"refund_amount": 500,
"status": "REFUNDED"
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| code | String | `0` = success |
| biz_content.refund_order_id | String | AsiaPay refund reference |
| biz_content.refund_amount | Integer | Refunded amount in minor units |
| biz_content.status | String | `REFUNDED` on success |
### PSync Response
```json
{
"code": "0",
"biz_content": {
"merch_order_id": "ORDER-20250522-001",
"pay_ref": "12345678",
"status": "ACCEPTED",
"amount": 1000,
"currency": "HKD",
"prc": "00",
"src": "00",
"auth_id": "AUTH001",
"tx_time": "20250522120000"
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| biz_content.status | String | Order status (see Status Mapping) |
| biz_content.prc | String | Primary Response Code from bank |
| biz_content.src | String | Secondary Response Code |
| biz_content.auth_id | String | Bank authorization ID |
| biz_content.tx_time | String | Transaction timestamp YYYYMMDDHHmmss |
### RSync Response
```json
{
"code": "0",
"biz_content": {
"refund_order_id": "REFUND-20250522-001",
"merch_order_id": "ORDER-20250522-001",
"refund_amount": 500,
"status": "REFUNDED",
"tx_time": "20250522130000"
}
}
```
### IncomingWebhook
AsiaPay POSTs URL-encoded form to merchant `notifyUrl`:
```
src=00&prc=00&Ref=12345678&PayRef=12345678&successcode=0&Ord=ORDER-20250522-001&Amt=10.00&Cur=344&Holder=John+Doe&AuthId=AUTH001&TxTime=20250522120000&payerAuth=Y&nbcb=1&skey=computed-sha1-hash
```
| Field | Type | Description |
|-------|------|-------------|
| src | String | Secondary Response Code |
| prc | String | Primary Response Code (`00`=Approved) |
| Ref | String | AsiaPay transaction reference |
| PayRef | String | Payment reference |
| successcode | String | `0`=Success, `1`=Failure |
| Ord | String | Merchant order reference |
| Amt | String | Transaction amount in major units |
| Cur | String | ISO 4217 numeric currency code |
| Holder | String | Cardholder name |
| AuthId | String | Bank authorization ID |
| TxTime | String | Transaction timestamp |
| payerAuth | String | `Y`=3DS authenticated, `N`=not |
| nbcb | String | `1`=server callback; absent=return URL |
| skey | String | SHA1 HMAC signature for verification |
Merchant must respond with: `CBTOKEN:MPSTATOK` (plaintext only, no HTML, no quotes).
## Error Handling
| HTTP Status | Connector Error Code | UCS Error Mapping | Cause |
|-------------|---------------------|-------------------|-------|
| 200 | code=0 | Success | Transaction approved |
| 200 | code=1001 | AuthenticationError | Invalid JWT signature |
| 200 | code=1002 | AuthenticationError | Invalid or expired merchant credentials |
| 200 | code=1003 | InvalidRequestError | Missing required parameters |
| 200 | code=1004 | InvalidRequestError | Invalid parameter format or value |
| 200 | code=2001 | PaymentDeclined | Card declined by bank |
| 200 | code=2002 | InsufficientFunds | Insufficient funds |
| 200 | code=2003 | ExpiredCard | Card expired |
| 200 | code=2004 | InvalidCard | Invalid card number |
| 200 | code=2005 | LostStolenCard | Card reported lost or stolen |
| 200 | code=3001 | ProcessingError | AsiaPay internal system error |
| 200 | prc=00 | Success | Bank approved |
| 200 | prc=01 | PaymentDeclined | Refer to card issuer |
| 200 | prc=05 | PaymentDeclined | Do not honor |
| 200 | prc=12 | InvalidTransaction | Invalid transaction type |
| 200 | prc=14 | InvalidCard | Invalid card number |
| 200 | prc=51 | InsufficientFunds | Insufficient funds |
| 200 | prc=54 | ExpiredCard | Expired card |
| 200 | prc=55 | InvalidPin | Incorrect PIN |
| 200 | prc=57 | NotPermittedTransaction | Transaction not permitted to cardholder |
| 200 | prc=62 | RestrictedCard | Restricted card |
| 200 | prc=65 | ExceedWithdrawalLimit | Exceeds withdrawal frequency limit |
| 200 | prc=91 | IssuerUnavailable | Card issuer unavailable |
| 200 | prc=96 | ProcessingError | System malfunction |
| 200 | successcode=1 | Failure | Legacy: payment failed |
| 400 | — | InvalidRequestError | Malformed HTTP request |
| 401 | — | AuthenticationError | Invalid or expired Bearer token |
| 500 | — | ProcessingError | AsiaPay server error |
**Retry Semantics**: Retry with exponential backoff on HTTP 500 errors and prc=91 (issuer temporarily unavailable). Do NOT retry on definitive declines (prc=05, 51, 54, 57, 62). Webhook retries: AsiaPay retries up to 3 times at 15-minute intervals if `CBTOKEN:MPSTATOK` ACK is not received.
## Status Mapping
| Connector Status (verbatim) | UCS AttemptStatus | Notes |
|----------------------------|-------------------|-------|
| ACCEPTED | Charged | Payment authorized and captured/settled |
| AUTHORIZED | Authorized | Pre-auth approved, capture pending |
| CAPTURED | Charged | Successfully captured from authorized state |
| PENDING | Pending | Awaiting confirmation (status code 22) |
| VOIDED | Voided | Authorization cancelled by merchant |
| REFUNDED | AutoRefunded | Full refund successfully processed |
| PARTIALLY_REFUNDED | AutoRefunded | Partial refund processed |
| FAILED | Failure | Transaction declined or processing error |
| CANCELLED | Voided | Cancelled by user or merchant |
| EXPIRED | Failure | Pre-auth not captured within 14 days |
| prc=00, successcode=0 | Charged | Legacy: bank approved and settled |
| prc=00, payType=AUTH | Authorized | Legacy: pre-auth approved |
| prc!=00, successcode=1 | Failure | Legacy: bank declined |
| prc=91 | Pending | Legacy: issuer unavailable, may retry |
| statusCode=22 | Pending | Legacy: transaction pending bank response |
## Webhooks
**Subscription Mechanism**: No separate webhook registration API. Merchant specifies `notifyUrl` (server-to-server IPN callback) per-transaction in the payment request body. The `redirectUrl` is the browser-redirect URL (not a webhook).
**Payload Format**: HTTP POST, `Content-Type: application/x-www-form-urlencoded`
**Signature Verification**:
- Header: None — signature embedded in `skey` body parameter
- Algorithm: SHA1 over selected transaction fields concatenated with `secureHashSecret`
- Recompute: `expected_skey = SHA1(merchantId + "|" + orderRef + "|" + currCode + "|" + amt + "|" + successcode + "|" + secureHashSecret)`
- Compare `expected_skey` with received `skey`; reject if mismatch
**Retry / Delivery Policy**:
- AsiaPay retries delivery up to **3 times** at **15-minute intervals**
- Merchant must respond within timeout with plaintext body: `CBTOKEN:MPSTATOK`
- No HTML, no JSON, no whitespace around the token — exactly the 16-character string
- Distinguishing callbacks from return URLs: presence of `nbcb=1` means server-to-server IPN
**Event Types and UCS Flow Equivalents**:
| AsiaPay Event | Condition | UCS Flow Equivalent |
|--------------|-----------|---------------------|
| Payment success | successcode=0, prc=00 | IncomingWebhook → Charged |
| Payment failed | successcode=1 | IncomingWebhook → Failure |
| Payment pending | statusCode=22 | IncomingWebhook → Pending |
| Refund notification | Refund completed | IncomingWebhook → Refunded |
| 3DS result | payerAuth=Y/N | IncomingWebhook (embedded in payment) |
**Security Best Practices**:
- Always validate `skey` HMAC before processing
- Verify `Amt` and `Cur` match the expected order values
- Verify `Ord` matches a known pending order reference
- Reject any webhook without a valid `skey`
## References
### API Reference
- https://developer.asiapay.com/ — AsiaPay Developer Portal (modern JSON REST API)
- https://github.com/asiapay-lib/integration_guide — AsiaPay GitHub Integration Guide
### Integration Guides
- https://www.paydollar.com/pdf/op/enpdintguide.pdf — PayDollar PayGate Integration Guide v3.67 (primary legacy reference)
- https://docs.portone.cloud/docs/asiapay — PortOne AsiaPay Integration Guide
- https://dev-docs.portone.cloud/docs/payment_channels/asiapay/ — PortOne Dev Docs AsiaPay channel
### Error Reference
- https://www.paydollar.com/b2c2/eng/merchant/help/f_onlinehelp_orderstatus.htm — PayDollar order status and error codes
- https://www.paydollar.com/pdf/op/enpdintguide.pdf — PRC/SRC bank response code tables
### Testing
- https://test.paydollar.com/b2cDemo/ — Sandbox environment (legacy)
- https://apitest.asiapay.iq:5443/apiaccess — Modern API sandbox
### Mobile SDKs (reference only — not applicable to UCS backend connector)
- https://github.com/asiapay-lib/paysdk-ios-lib — PaySDK iOS (Swift)
- https://github.com/asiapay-lib/paysdk-android-lib — PaySDK Android
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.