[Tech Spec] asiapay — Credit
- Dominant language
- Python
- Stars
- 4
- Forks
- 6
- PR merge metrics
- No merged PRs in 30d
Description
# asiapay — Credit
**Complexity:** high
**Generated by:** Grace pipeline run `run-2026-05-21T17-38-39-050Z-7ad28a`
## Summary
Implement Credit payment method for asiapay connector. AsiaPay (PayDollar) UCS Connector Integration Technical Specification
## Scope
# AsiaPay (PayDollar) UCS Connector Integration Technical Specification
## Connector Profile
- **Connector name:** AsiaPay / PayDollar
- **Owning company:** AsiaPay Limited
- **Regional brands:** PayDollar (HK, SG, MY, TW, IN, VN, AU, NZ), PesoPay (PH), SiamPay (TH), BimoPay (ID)
- **Production base URL:** `https://www.paydollar.com/b2c2/eng`
- **Sandbox base URL:** `https://test.paydollar.com/b2cDemo/eng`
- **Supported countries:** Hong Kong, Singapore, Malaysia, Thailand, Philippines, Indonesia, Taiwan, India, Vietnam, Australia, New Zealand, China (Macau)
- **Supported currencies (ISO 4217 alpha / numeric):**
| Alpha | Numeric | Alpha | Numeric |
|-------|---------|-------|----------|
| HKD | 344 | SGD | 702 |
| USD | 840 | CNY | 156 |
| JPY | 392 | TWD | 901 |
| AUD | 036 | EUR | 978 |
| GBP | 826 | CAD | 124 |
| AED | 784 | THB | 764 |
| MYR | 458 | PHP | 608 |
| INR | 356 | IDR | 360 |
| NZD | 554 | VND | 704 |
> **Important:** The API uses ISO 4217 **numeric** currency codes (e.g., `344` for HKD, `840` for USD), not alphabetic codes.
---
## Authentication
### Scheme
AsiaPay uses a **SHA-1 HMAC Signature** scheme. There are two distinct credential sets:
1. **Payment form / initiation** – a `secureHash` field computed from selected request parameters + a `secureHashSecret` held server-side.
2. **Merchant API (post-payment ops)** – HTTP Basic-style `loginId` + `password` submitted as form body fields alongside `merchantId`.
### Credential Fields
| Field | Scope | Description |
|-------|-------|-------------|
| `merchantId` | All requests | Numeric merchant account ID assigned by PayDollar |
| `secureHashSecret` | Payment initiation & webhook verification | Secret string obtained from PayDollar Service Dept |
| `loginId` | Merchant API (capture/void/refund/query) | API login ID (up to 30 chars), requested from support |
| `password` | Merchant API | API password (up to 15 chars), paired with loginId |
### Secure Hash Calculation (Payment Initiation)
A
## Out of Scope
Not specified in techspec
## Technical Constraints
- Follow existing connector patterns in the codebase
---
## Full Tech Spec
# AsiaPay (PayDollar) UCS Connector Integration Technical Specification
## Connector Profile
- **Connector name:** AsiaPay / PayDollar
- **Owning company:** AsiaPay Limited
- **Regional brands:** PayDollar (HK, SG, MY, TW, IN, VN, AU, NZ), PesoPay (PH), SiamPay (TH), BimoPay (ID)
- **Production base URL:** `https://www.paydollar.com/b2c2/eng`
- **Sandbox base URL:** `https://test.paydollar.com/b2cDemo/eng`
- **Supported countries:** Hong Kong, Singapore, Malaysia, Thailand, Philippines, Indonesia, Taiwan, India, Vietnam, Australia, New Zealand, China (Macau)
- **Supported currencies (ISO 4217 alpha / numeric):**
| Alpha | Numeric | Alpha | Numeric |
|-------|---------|-------|----------|
| HKD | 344 | SGD | 702 |
| USD | 840 | CNY | 156 |
| JPY | 392 | TWD | 901 |
| AUD | 036 | EUR | 978 |
| GBP | 826 | CAD | 124 |
| AED | 784 | THB | 764 |
| MYR | 458 | PHP | 608 |
| INR | 356 | IDR | 360 |
| NZD | 554 | VND | 704 |
> **Important:** The API uses ISO 4217 **numeric** currency codes (e.g., `344` for HKD, `840` for USD), not alphabetic codes.
---
## Authentication
### Scheme
AsiaPay uses a **SHA-1 HMAC Signature** scheme. There are two distinct credential sets:
1. **Payment form / initiation** – a `secureHash` field computed from selected request parameters + a `secureHashSecret` held server-side.
2. **Merchant API (post-payment ops)** – HTTP Basic-style `loginId` + `password` submitted as form body fields alongside `merchantId`.
### Credential Fields
| Field | Scope | Description |
|-------|-------|-------------|
| `merchantId` | All requests | Numeric merchant account ID assigned by PayDollar |
| `secureHashSecret` | Payment initiation & webhook verification | Secret string obtained from PayDollar Service Dept |
| `loginId` | Merchant API (capture/void/refund/query) | API login ID (up to 30 chars), requested from support |
| `password` | Merchant API | API password (up to 15 chars), paired with loginId |
### Secure Hash Calculation (Payment Initiation)
Algorithm: `SHA-1` (SHA-256 available on request)
```
secureHash = SHA1( merchantId + "|" + orderRef + "|" + currCode + "|" + amount + "|" + payType + "|" + secureHashSecret )
```
Field order is strict. All values are concatenated with the pipe character `|` before hashing.
### Webhook / Data-Feed Response Verification
```
secureHash = SHA1( src + "|" + prc + "|" + successCode + "|" + orderRef + "|" + payRef + "|" + currCode + "|" + amount + "|" + payerAuthStatus + "|" + secureHashSecret )
```
Recompute this hash from received parameters and compare with the `secureHash` field in the webhook payload.
### Merchant API Authentication
All body fields, transmitted as `application/x-www-form-urlencoded`:
```
merchantId=YOUR_MERCHANT_ID&loginId=YOUR_LOGIN_ID&password=YOUR_PASSWORD&actionType=Capture&payRef=4780&...
```
---
## Supported Flows
| Flow | HTTP Method | Endpoint Path | Idempotency | Notes |
|------|-------------|---------------|-------------|-------|
| Authorize | POST | `/payment/payForm.jsp` | `orderRef` (merchant-side unique) | Redirect-based; `payType=H` for auth-only, `payType=N` for immediate capture |
| Capture | POST | `/merchant/api/orderApi.jsp` | `payRef` | Captures a previously Authorized (Hold) transaction |
| Void | POST | `/merchant/api/orderApi.jsp` | `payRef` | Reverses Authorized transaction before settlement |
| Refund | POST | `/merchant/api/orderApi.jsp` | `payRef` + `orderRef` | Full refund within 24 h; partial refund after 24 h, within 14 days |
| PSync | POST | `/merchant/api/orderApi.jsp` | `payRef` | Query current status of a transaction |
| IncomingWebhook | POST | `{merchantNotifyUrl}` | PayDollar initiates; merchant must respond `OK` | Async notification after payment completion |
---
## Request Schema
### Authorize Request
Submitted as an HTML form `POST` to `https://www.paydollar.com/b2c2/eng/payment/payForm.jsp` (production) or `https://test.paydollar.com/b2cDemo/eng/payment/payForm.jsp` (sandbox).
Content-Type: `application/x-www-form-urlencoded`
```json
{
"merchantId": "12345",
"orderRef": "ORDER-20240101-001",
"amount": "100.50",
"currCode": "344",
"payType": "H",
"payMethod": "ALL",
"lang": "E",
"successUrl": "https://merchant.com/payment/success",
"failUrl": "https://merchant.com/payment/fail",
"cancelUrl": "https://merchant.com/payment/cancel",
"notifyUrl": "https://merchant.com/webhooks/paydollar",
"remark": "Order #001 - Widget purchase",
"secureHash": "a1b2c3d4e5f6...(40-char SHA-1)"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `merchantId` | Integer | Yes | Merchant account ID |
| `orderRef` | String (max 35) | Yes | Merchant's unique order reference |
| `amount` | Decimal (12,2) | Yes | Transaction amount in major units (e.g., `"100.50"`) |
| `currCode` | String (3) | Yes | ISO 4217 **numeric** currency code (e.g., `"344"` for HKD) |
| `payType` | String | Yes | `"N"` = Normal/Sale (auth+capture); `"H"` = Hold/Authorize-only |
| `payMethod` | String | Yes | `"ALL"` = all methods; `"CC"` = credit cards only |
| `lang` | String (1) | Yes | Language: `"E"` English, `"C"` Traditional Chinese, `"T"` Thai, `"X"` Simplified Chinese, `"K"` Korean, `"J"` Japanese |
| `successUrl` | String (max 300) | Yes | Redirect URL on success (display only – do NOT use for backend logic) |
| `failUrl` | String (max 300) | Yes | Redirect URL on failure |
| `cancelUrl` | String (max 300) | No | Redirect URL on cancellation |
| `notifyUrl` | String (max 300) | No | Server-to-server webhook URL (use for authoritative backend updates) |
| `remark` | String (max 200) | No | Additional reference (shown in confirmation emails) |
| `secureHash` | String (40) | Yes | SHA-1 hash for request authentication |
| `mpsMode` | String | No | Multi-currency: `"NIL"`, `"SCP"`, `"DCC"`, `"MCP"` |
### Capture Request
`POST https://www.paydollar.com/b2c2/eng/merchant/api/orderApi.jsp`
Content-Type: `application/x-www-form-urlencoded`
```json
{
"merchantId": "12345",
"loginId": "api_user",
"password": "api_pass",
"actionType": "Capture",
"payRef": "4780",
"amount": "100.50"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `merchantId` | Integer | Yes | Merchant account ID |
| `loginId` | String (max 30) | Yes | API login ID |
| `password` | String (max 15) | Yes | API password |
| `actionType` | String | Yes | Must be `"Capture"` |
| `payRef` | String (max 35) | Yes | PayDollar payment reference number from original authorization |
| `amount` | Decimal (12,2) | Yes | Amount to capture (must be ≤ original authorized amount) |
### Void Request
`POST https://www.paydollar.com/b2c2/eng/merchant/api/orderApi.jsp`
```json
{
"merchantId": "12345",
"loginId": "api_user",
"password": "api_pass",
"actionType": "Void",
"payRef": "4780"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `merchantId` | Integer | Yes | Merchant account ID |
| `loginId` | String (max 30) | Yes | API login ID |
| `password` | String (max 15) | Yes | API password |
| `actionType` | String | Yes | Must be `"Void"` |
| `payRef` | String (max 35) | Yes | PayDollar payment reference to void |
### Refund Request
`POST https://www.paydollar.com/b2c2/eng/merchant/api/orderApi.jsp`
```json
{
"merchantId": "12345",
"loginId": "api_user",
"password": "api_pass",
"actionType": "Refund",
"payRef": "4780",
"amount": "50.00"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `merchantId` | Integer | Yes | Merchant account ID |
| `loginId` | String (max 30) | Yes | API login ID |
| `password` | String (max 15) | Yes | API password |
| `actionType` | String | Yes | Must be `"Refund"` |
| `payRef` | String (max 35) | Yes | PayDollar payment reference to refund |
| `amount` | Decimal (12,2) | Conditional | Amount to refund; omit for full refund within 24 h; required for partial refund |
### PSync (Query) Request
`POST https://www.paydollar.com/b2c2/eng/merchant/api/orderApi.jsp`
```json
{
"merchantId": "12345",
"loginId": "api_user",
"password": "api_pass",
"actionType": "Query",
"payRef": "4780"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `merchantId` | Integer | Yes | Merchant account ID |
| `loginId` | String (max 30) | Yes | API login ID |
| `password` | String (max 15) | Yes | API password |
| `actionType` | String | Yes | Must be `"Query"` |
| `payRef` | String (max 35) | Yes | PayDollar payment reference to query |
---
## Response Schema
### Authorize Response
After the customer completes the hosted payment page, PayDollar redirects to `successUrl` or `failUrl` with URL-encoded parameters and sends an async notification to `notifyUrl`.
**Successful response (redirect params / webhook body):**
```
successCode=0&ref=ORDER-20240101-001&payRef=4780&amt=100.50&cur=344&prc=0&src=0&ord=6697090&holder=JOHN+DOE&authId=123456&txTime=2024-01-01+12%3A00%3A00.0&errMsg=Transaction+completed&orderStatus=Accepted&payerAuthStatus=Y&secureHash=a1b2c3...
```
**Error response:**
```
successCode=1&ref=ORDER-20240101-001&payRef=4780&amt=100.50&cur=344&prc=5&src=42&ord=6697090&errMsg=Insufficient+funds&orderStatus=Rejected&secureHash=a1b2c3...
```
| Field | Type | Description |
|-------|------|-------------|
| `successCode` | Integer | `0` = Success, `1` = Failure, `-1` = Error |
| `ref` / `orderRef` | String | Echo of merchant's `orderRef` |
| `payRef` | String | PayDollar unique payment reference (store this for subsequent ops) |
| `amt` | Decimal | Transaction amount |
| `cur` | String | Numeric ISO currency code |
| `prc` | Integer | Primary return code from bank/processor |
| `src` | Integer | Secondary return code |
| `ord` | String | PayDollar internal order number |
| `holder` | String | Cardholder name (max 40 chars) |
| `authId` | String | Bank approval code |
| `txTime` | Timestamp | Transaction time (`YYYY-MM-DD HH:MM:SS.ms`) |
| `errMsg` | String | Human-readable message |
| `orderStatus` | String | Current order status (see Status Mapping) |
| `payerAuthStatus` | String | 3DS authentication result (`Y`/`N`/`A`/`U`) |
| `secureHash` | String (40) | SHA-1 hash for response verification |
### Capture / Void / Refund / PSync Response
All Merchant API operations return URL-encoded parameters:
**Success:**
```
resultCode=0&orderStatus=Accepted&ref=ORDER-20240101-001&payRef=4780&amt=100.50&cur=344&errMsg=Capture+Successfully
```
**Failure:**
```
resultCode=-1&orderStatus=Accepted&ref=ORDER-20240101-001&payRef=4780&amt=100.50&cur=344&errMsg=Capture+failed%3A+already+captured
```
| Field | Type | Description |
|-------|------|-------------|
| `resultCode` | Integer | `0` = Success, `-1` = Failed |
| `orderStatus` | String | New order status after the operation |
| `ref` | String | Merchant order reference |
| `payRef` | String | PayDollar payment reference |
| `amt` | Decimal | Transaction amount |
| `cur` | String | Numeric ISO currency code |
| `errMsg` | String | Human-readable result or error message |
---
## Error Handling
### API-Level Result Codes
| HTTP Status | resultCode / successCode | UCS Error Mapping | Cause |
|-------------|--------------------------|-------------------|-------|
| 200 | `successCode=0` | `PaymentSuccess` | Transaction approved |
| 200 | `successCode=1` | `PaymentFailed` | Transaction declined by bank |
| 200 | `successCode=-1` | `ProcessorError` | System/technical error |
| 200 | `resultCode=0` | Operation success | Merchant API operation succeeded |
| 200 | `resultCode=-1` | `ProcessorError` | Merchant API operation failed |
### Bank Primary Return Codes (prc)
| prc | Meaning |
|-----|---------|
| 0 | Approved |
| 1 | Refer to card issuer |
| 2 | Refer to card issuer's special conditions |
| 3 | Invalid merchant |
| 4 | Pick up card |
| 5 | Do not honour / Declined |
| 12 | Invalid transaction |
| 13 | Invalid amount |
| 14 | Invalid card number |
| 30 | Format error |
| 41 | Lost card |
| 43 | Stolen card |
| 51 | Insufficient funds |
| 54 | Expired card |
| 55 | Incorrect PIN |
| 57 | Transaction not permitted to cardholder |
| 58 | Transaction not permitted to merchant |
| 61 | Exceeds withdrawal amount limit |
| 65 | Exceeds withdrawal frequency limit |
| 91 | Card issuer or switch inoperative |
| 96 | System malfunction |
### Retry Semantics
- `successCode=1` / `prc!=0`: Do **not** retry automatically – the card issuer declined. Ask the customer to use a different card or payment method.
- `successCode=-1` / system errors: Safe to retry with a new `orderRef`; never retry the same `orderRef` as it may cause duplicate charges.
- Webhook delivery: PayDollar retries delivery if the merchant does not respond with `OK` as the first two characters of the HTTP response body.
---
## Status Mapping
| Connector Status (verbatim) | UCS AttemptStatus | Notes |
|-----------------------------|-------------------|-------|
| `Accepted` | `Charged` | Payment fully captured and settled |
| `Authorized` | `Authorized` | Auth-only (payType=H); not yet captured |
| `Accepted_Adj` | `Charged` | Adjusted/settlement accepted |
| `Captured` | `Charged` | Explicit capture completed |
| `Pending` | `Pending` | Awaiting processing |
| `Pending_3D` | `AuthenticationPending` | Awaiting 3DS verification |
| `Capturing` | `CaptureInitiated` | Capture in progress |
| `Rejected` | `Failure` | Declined by bank or PayDollar |
| `Cancelled` | `Voided` | Customer cancelled before completion |
| `Voided` | `Voided` | Merchant voided authorized transaction |
| `Refunded` | `AutoRefunded` | Full refund processed |
| `Partial Refunded` | `AutoRefunded` | Partial refund processed |
| `RequestRefund` | `AutoRefunded` | Refund request submitted |
| `RequestPartialRefund` | `AutoRefunded` | Partial refund request submitted |
| `ChargeBack` | `AutoRefunded` | Chargeback initiated by cardholder |
| `Partial ChargeBack` | `AutoRefunded` | Partial chargeback |
| `Reversal-CB` | `Voided` | Chargeback reversal |
| `Reverse Auth` | `Voided` | Authorization reversed |
| `Reversal Void` | `Voided` | Void reversal |
---
## Webhooks
### Subscription Mechanism
Set the `notifyUrl` parameter in the Authorize request. PayDollar will POST the transaction result to this URL asynchronously after payment completion.
- URL must be publicly accessible (HTTP port 80 or HTTPS port 443)
- Configure the URL in the PayDollar merchant admin portal as the "Data Feed URL" as a backup
### Payload Structure
PayDollar POSTs `application/x-www-form-urlencoded` data:
```
successCode=0&ref=ORDER-20240101-001&payRef=4780&amt=100.50&cur=344&prc=0&src=0&ord=6697090&holder=JOHN+DOE&authId=123456&txTime=2024-01-01+12%3A00%3A00.0&errMsg=Transaction+completed&orderStatus=Accepted&payerAuthStatus=Y&secureHash=a1b2c3d4e5f6789...
```
All fields are the same as the Authorize Response fields documented above.
### Signature Verification
1. Extract `src`, `prc`, `successCode`, `ref` (orderRef), `payRef`, `cur` (currCode), `amt` (amount), `payerAuthStatus`, and your stored `secureHashSecret`.
2. Recompute: `SHA1(src + "|" + prc + "|" + successCode + "|" + orderRef + "|" + payRef + "|" + currCode + "|" + amount + "|" + payerAuthStatus + "|" + secureHashSecret)`
3. Compare with the `secureHash` field in the received payload. Reject if they do not match.
### Response Protocol
The merchant endpoint **must** return the string `OK` as the first two characters of the HTTP response body (plain text). If `OK` is not the first response, PayDollar treats delivery as failed and retries.
### Retry / Delivery Policy
- PayDollar retries webhook delivery on non-OK response or connection failure.
- Number and interval of retries is not publicly documented; implement idempotent handlers.
### Event Types
PayDollar sends a single event type per webhook call; the `orderStatus` and `successCode` fields distinguish the outcome:
| orderStatus | successCode | UCS Flow Equivalent |
|-------------|-------------|---------------------|
| `Accepted` | `0` | IncomingWebhook → PaymentSuccess |
| `Rejected` | `1` | IncomingWebhook → PaymentFailed |
| `Cancelled` | `1` | IncomingWebhook → PaymentCancelled |
| `Voided` | `0` | IncomingWebhook → Voided |
| `Refunded` | `0` | IncomingWebhook → Refunded |
---
## 3DS Support
- PayDollar supports EMV 3-D Secure 2.0 ("Xecure" 3DS 2.0).
- `payerAuthStatus` in the response indicates 3DS outcome:
- `Y` = Authenticated
- `A` = Attempted (partial auth)
- `N` = Not authenticated
- `U` = Unable to authenticate
- For full 3DS 2.0 flows, browser data parameters (userAgent, acceptHeader, etc.) are required in the Authorize request payload; contact PayDollar for the extended parameter list.
---
## References
### API Reference
- https://developer.asiapay.com/integration-guide/functions-of-merchant-api
- https://www.paydollar.com/pdf/op/enpdintguide.pdf
- https://github.com/asiapay-lib/integration_guide
### Authentication
- https://developer.asiapay.com/integration-guide/transaction-security-by-secure-hash
### Status & Error Codes
- https://www.paydollar.com/b2c2/eng/merchant/help/f_onlinehelp_orderstatus.htm
### Recurring / Reference Payments
- https://developer.asiapay.com/reference-payment
### Third-Party Integration Guides
- https://docs.portone.cloud/docs/asiapay
- https://www.odoo.com/documentation/18.0/applications/finance/payment_providers/asiapay.html
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.