juspay / juspay/grace

[Tech Spec] asiapay — Unknown

Open
#168 0 comments 0 reactions 0 assignees View on GitHub
connector-integration
Dominant language
Python
Stars
4
Forks
6
PR merge metrics
No merged PRs in 30d

Description

# asiapay — Unknown

**Complexity:** low
**Generated by:** Grace pipeline run `run-2026-05-21T21-17-36-785Z-44b1a5`

## Summary

Implement Unknown payment method for asiapay connector. Technical Specification: AsiaPay Connector

## Scope

# Technical Specification: AsiaPay Connector

## 1. Connector Profile

| Field | Value |
|-------|-------|
| **Name** | AsiaPay (PayDollar) |
| **Primary Flow Scope** | Card payments (Authorize, Capture, Sale, Refund, Void, Query) |
| **API Family** | Form POST / Server-to-Server Direct Connection (HTTP POST, application/x-www-form-urlencoded) |
| **Production Host (PayDollar)** | `https://www.paydollar.com` |
| **Sandbox Host** | `https://test.paydollar.com` |
| **Regional Hosts** | AsiaPay SG/MY/IN: `https://www.asiapay.com`; SiamPay (TH): `https://www.siampay.com`; PesoPay (PH): `https://www.pesopay.com` |

AsiaPay (branded as PayDollar in some regions) is a Hong Kong-based payment gateway with extensive coverage across Asia-Pacific. The integration uses a direct server-to-server POST model with form-encoded bodies and a secure hash for request authentication. All responses are also form-encoded key-value pairs returned in the HTTP response body.

---

## 2. Authentication

| Field | Value |
|-------|-------|
| **Scheme** | HMAC-SHA256 Secure Hash |
| **Header** | None — hash embedded in request body as `secureHash` field |
| **Credentials Required** | `merchantId` (numeric string), `secureHashSecret` (shared secret configured in merchant portal) |

### Secure Hash Computation

The `secureHash` is computed as the SHA-256 hash (hex-encoded) of a pipe-delimited string of specific transaction fields plus the secret:

```
secureHash = SHA256( merchantId | currCode | mRef | amount | payType | secureHashSecret )
```

- Field order is **fixed** and documented per API endpoint — any deviation causes hash mismatch rejection.
- The secret (`secureHashSecret`) is **never** transmitted; it is used only for hashing.
- For the Merchant API (refund/void/query), a separate `hashSecret` may be used depending on configuration.

### Implementation Notes
- The secure hash algorithm was historically SHA-1 on older integrations; SHA-256 is the current requirement.
- Some older PayDoll

## Out of Scope

Not specified in techspec

## Technical Constraints

- Follow existing connector patterns in the codebase

---

## Full Tech Spec

# Technical Specification: AsiaPay Connector

## 1. Connector Profile

| Field | Value |
|-------|-------|
| **Name** | AsiaPay (PayDollar) |
| **Primary Flow Scope** | Card payments (Authorize, Capture, Sale, Refund, Void, Query) |
| **API Family** | Form POST / Server-to-Server Direct Connection (HTTP POST, application/x-www-form-urlencoded) |
| **Production Host (PayDollar)** | `https://www.paydollar.com` |
| **Sandbox Host** | `https://test.paydollar.com` |
| **Regional Hosts** | AsiaPay SG/MY/IN: `https://www.asiapay.com`; SiamPay (TH): `https://www.siampay.com`; PesoPay (PH): `https://www.pesopay.com` |

AsiaPay (branded as PayDollar in some regions) is a Hong Kong-based payment gateway with extensive coverage across Asia-Pacific. The integration uses a direct server-to-server POST model with form-encoded bodies and a secure hash for request authentication. All responses are also form-encoded key-value pairs returned in the HTTP response body.

---

## 2. Authentication

| Field | Value |
|-------|-------|
| **Scheme** | HMAC-SHA256 Secure Hash |
| **Header** | None — hash embedded in request body as `secureHash` field |
| **Credentials Required** | `merchantId` (numeric string), `secureHashSecret` (shared secret configured in merchant portal) |

### Secure Hash Computation

The `secureHash` is computed as the SHA-256 hash (hex-encoded) of a pipe-delimited string of specific transaction fields plus the secret:

```
secureHash = SHA256( merchantId | currCode | mRef | amount | payType | secureHashSecret )
```

- Field order is **fixed** and documented per API endpoint — any deviation causes hash mismatch rejection.
- The secret (`secureHashSecret`) is **never** transmitted; it is used only for hashing.
- For the Merchant API (refund/void/query), a separate `hashSecret` may be used depending on configuration.

### Implementation Notes
- The secure hash algorithm was historically SHA-1 on older integrations; SHA-256 is the current requirement.
- Some older PayDollar documentation references `secureHashAlgorithm` field; omit if not required by the endpoint.
- The merchant portal allows configuring IP whitelist in addition to hash validation.

---

## 3. Supported Flows

| Flow | HTTP | Path | Notes |
|------|------|------|-------|
| **Authorize** | POST | `/eng/payment/payForm.jsp` | `payType=H` (Hold); card details in body |
| **Capture** | POST | `/eng/merchant/api/orderInq.jsp` | Follow-on capture via Merchant API using `payRef` from Authorize |
| **Sale (Auth+Capture)** | POST | `/eng/payment/payForm.jsp` | `payType=N` (Normal); immediate settle |
| **Refund** | POST | `/eng/merchant/api/orderInq.jsp` | `actionType=REFUND`; partial refund supported via `refundAmt` |
| **Void** | POST | `/eng/merchant/api/orderInq.jsp` | `actionType=VOID`; only valid before settlement |
| **PSync (Payment Query)** | POST | `/eng/merchant/api/orderInq.jsp` | `actionType=Query`; returns current transaction status |
| **RSync (Refund Query)** | POST | `/eng/merchant/api/orderInq.jsp` | `actionType=Query` with `refundId`; retrieves refund status |
| **Webhooks (Data Feedback)** | POST | Merchant-configured URL | AsiaPay POSTs transaction result to `dataFeedbackURL` after payment |

---

## 4. Request Schema Highlights

### Payment Request (`/eng/payment/payForm.jsp`)

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `merchantId` | string (numeric) | Yes | Merchant identifier |
| `currCode` | string (numeric ISO-4217) | Yes | Currency: `840`=USD, `344`=HKD, `702`=SGD, `458`=MYR, `360`=IDR, `356`=INR |
| `amount` | string (decimal) | Yes | Transaction amount, 2 decimal places (e.g., `100.00`) |
| `mRef` | string (≤35 chars) | Yes | Merchant order reference — must be **unique per transaction** |
| `payType` | enum | Yes | `N`=Normal (sale), `H`=Hold (authorize-only), `R`=Capture |
| `pMethod` | enum | Yes | `VISA`, `Master`, `JCB`, `AMEX`, `UnionPay` |
| `cardNo` | string | Yes | Card number (plain or encrypted depending on integration type) |
| `epMonth` | string (MM) | Yes | Expiry month |
| `epYear` | string (YYYY) | Yes | Expiry year |
| `secureHash` | string (hex, 64 chars) | Yes | SHA-256 authentication hash |
| `cardSecurityCode` | string (3-4 digits) | No | CVV/CVC |
| `lang` | string | No | Response language: `E`=English (default), `C`=Chinese |
| `remark` | string (≤100 chars) | No | Order remark/description |
| `successUrl` | string (URL) | No | Redirect URL on success (browser-redirect model only) |
| `failUrl` | string (URL) | No | Redirect URL on failure |
| `cancelUrl` | string (URL) | No | Redirect URL on cancel |
| `dataFeedbackURL` | string (URL) | No | Async webhook callback URL |

### Merchant API Request (`/eng/merchant/api/orderInq.jsp`)

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `merchantId` | string | Yes | Merchant identifier |
| `loginId` | string | Yes | Merchant API login |
| `password` | string | Yes | API password (hashed) |
| `payRef` | string | Yes (for Void/Capture/Refund) | Gateway payment reference from original auth response |
| `mRef` | string | Yes (for Query) | Merchant reference for lookup |
| `actionType` | enum | Yes | `VOID`, `REFUND`, `Capture`, `Query` |
| `refundAmt` | string (decimal) | No | Partial refund amount (if omitted, full refund) |
| `secureHash` | string | Yes | SHA-256 hash of `merchantId|actionType|payRef|secureHashSecret` |

### Idempotency
- AsiaPay does **not** expose a native idempotency key header.
- `mRef` (merchant reference) serves as the de-facto idempotency identifier — duplicate `mRef` values are typically rejected or flagged.
- Connectors must track `mRef` to detect duplicates before re-submission.

---

## 5. Response Schema Highlights

| Field | Type | Description |
|-------|------|-------------|
| `successcode` | enum (`0`, `1`) | `0`=Transaction approved, `1`=Transaction failed |
| `prc` | string (numeric) | Primary result code from issuer |
| `src` | string | Secondary authorization result code |
| `Ord` | string | Echo of merchant's `mRef` |
| `Ref` | string | AsiaPay internal reference number |
| `payRef` | string | **Gateway payment reference** — unique transaction ID; required for Void/Capture/Refund |
| `amt` | string (decimal) | Authorized/charged amount |
| `currCode` | string | ISO-4217 numeric currency code |
| `pMethod` | string | Payment method used |
| `maskedCardNo` | string | Masked card number (e.g., `4111xxxxxxxx1111`) |
| `eci` | string | Electronic Commerce Indicator; `05`=Full 3DS, `06`=Attempt, `07`=Non-3DS |
| `errCode` | string | Error code if failed |
| `errMsg` | string | Human-readable error message |
| `transactionTime` | string (datetime) | Transaction timestamp (`YYYYMMDDHHMMSS`) |

---

## 6. Error Handling

| HTTP | `successcode` / `prc` | Cause |
|------|-----------------------|-------|
| 200 | `successcode=1`, `prc=2` | Transaction declined by issuer |
| 200 | `successcode=1`, `prc=8` | Honour with identification |
| 200 | `successcode=1`, `prc=13` | Invalid amount |
| 200 | `successcode=1`, `prc=14` | Invalid card number |
| 200 | `successcode=1`, `prc=51` | Insufficient funds |
| 200 | `successcode=1`, `prc=54` | Expired card |
| 200 | `successcode=1`, `prc=61` | Exceeds withdrawal amount limit |
| 200 | `successcode=1`, `prc=65` | Exceeds withdrawal frequency limit |
| 200 | `successcode=1`, `prc=91` | Issuer or switch inoperative |
| 200 | `successcode=1`, `prc=96` | System malfunction |
| 200 | `errCode=PS000` | Secure hash mismatch — authentication failure |
| 200 | `errCode=PS001` | Merchant ID not found |
| 200 | `errCode=PS002` | Currency not supported |
| 200 | `errCode=PS003` | Payment method not supported |
| 400 | N/A | Malformed POST body (missing required fields) |
| 500 | N/A | Gateway internal error |

> **Note**: AsiaPay returns HTTP 200 for both successful and failed transactions. Always inspect `successcode` and `prc`.

---

## 7. Webhooks / Async Notifications

### Overview
AsiaPay supports asynchronous payment notifications via a configurable Data Feedback URL (`dataFeedbackURL`). After a payment is processed, AsiaPay POSTs the transaction result to this URL.

### Subscription
- Configured per merchant in the AsiaPay Merchant Administration portal.
- Can also be passed dynamically per request as `dataFeedbackURL` in the payment request body.

### Delivery Format
- Method: HTTP POST
- Content-Type: `application/x-www-form-urlencoded`
- Payload: Same key-value pairs as the synchronous response (`successcode`, `prc`, `payRef`, `Ref`, `Ord`, `amt`, `currCode`, `transactionTime`, `secureHash`, etc.)

### Verification
Merchants must verify the `secureHash` in the callback payload:
```
expectedHash = SHA256( merchantId | currCode | mRef | amount | payType | secureHashSecret )
```

### Retry Policy
- AsiaPay retries delivery up to **3 times** with increasing intervals if the merchant server returns non-2xx or times out (15-second timeout per attempt).
- After 3 failed attempts, no further retries — merchants must use PSync to reconcile missed notifications.

### Documented Gaps
- No official webhook signature header — verification relies on `secureHash` field in body.
- No webhook management API — all configuration via merchant portal UI.
- Refund/Void callbacks may not be sent depending on gateway configuration.

---

## 8. References

| Description | URL |
|-------------|-----|
| AsiaPay Developer Portal | https://developer.asiapay.com/ |
| Integration Guide Introduction | https://developer.asiapay.com/integration-guide/introduction-4 |
| Server-Side Direct Connection | https://developer.asiapay.com/integration-guide/web-integration/server-side-direct-connection |
| Payment Reference API | https://developer.asiapay.com/reference-payment |
| Void, Online Refund, Partial Refund | https://developer.asiapay.com/integration-guide/functions-of-merchant-api/void-online-refund-or-partial-refund |
| PayDollar Integration Guide (PDF) | https://www.paydollar.com/pdf/op/enpdintguide.pdf |
| AsiaPay Integration Guide (GitHub) | https://github.com/asiapay-lib/integration_guide |
| AsiaPay IQ Integration | https://www.asiapay.iq/integration |
| PayDollar Resources | https://www.paydollar.com/en/resources.html |

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.