Tổng quan
- Base URL:
https://client.apinganhang.net/api/v1/payments/ - Xác thực:
Authorization: Bearer <token>(user API) hoặc HMAC website (website_key+website_secret) cho orders/payouts. - Callback Hub:
/api/v1/payments/callbacks/{gateway}.php— cấu hình URL này trên cổng hoặc để Hub tự điền quabackend_url/notify_url. - Forward site: Hub POST JSON tới
notify_forward_urlkèm headerX-Payment-Signature: sha256=....
Endpoints chính
| Method | Path | Mô tả |
|---|---|---|
| GET/POST | settings.php | Cấu hình gateway (sharkpay, wowpay, eeziepay, 1dpay) |
| GET | balance.php?gateway= | Số dư cổng (WowPay, EeziePay, 1DPay) |
| POST | test.php | Test kết nối / balance |
| POST | orders/create.php | Tạo đơn nạp (payin) |
| GET/POST | orders/query.php | Tra cứu đơn nạp |
| POST | payouts/create.php | Tạo lệnh rút (payout) |
| GET/POST | payouts/query.php | Tra cứu payout |
| GET/POST | websites.php | Quản lý website integration |
merchant_order_no nguyên tử trước khi gọi cổng — gọi payouts/create.php nhiều lần với cùng merchant_order_no (retry do timeout mạng, double-click...) trong khi lệnh trước còn đang xử lý hoặc đã thành công sẽ bị từ chối ngay, Hub không gửi tiền lần 2: HTTP 409, {"success":false,"data":{"code":"DUPLICATE_ORDER","status":"pending|success"}}. Nếu lệnh trước đó thất bại rõ ràng ở tầng Hub/cổng (validate lỗi, cổng từ chối) thì có thể gọi lại với cùng merchant_order_no. Khuyến nghị: luôn truyền merchant_order_no duy nhất cho mỗi lệnh rút — nếu bỏ trống, Hub không chống được trùng.Xác thực đối tác — Website HMAC Bắt buộc
Mọi request gọi Hub từ phía đối tác (tạo đơn, rút tiền, tra cứu) đều phải xác thực bằng cặp website_key / website_secret. Lấy hai giá trị này tại app.apinganhang.net → Cổng thanh toán → Website đã đăng ký.
Thuật toán ký
- Thu thập tất cả field của request (JSON body hoặc form-data).
- Loại bỏ các field:
sign,website_secret,website_secret_plain,website_secret_runtime,secret. - Loại bỏ field có giá trị rỗng (
"") và field kiểu array/object. - Sắp xếp các field còn lại theo tên key — thứ tự bảng chữ cái ASCII (case-sensitive, chữ hoa trước chữ thường).
- Nối chuỗi:
key1=value1|key2=value2|key3=value3— dấu pipe|ngăn cách giữa các cặp, không có dấu cách, không trailing pipe. - Ký HMAC-SHA256:
HMAC-SHA256(canonical_string, website_secret)— kết quả là chuỗi hex thường (lowercase). - Gửi chữ ký trong field
signcùng vớiwebsite_keytrong body request.
Ví dụ minh hoạ — tạo đơn nạp (Payin)
Request body (trước khi ký):
{
"website_key": "wk_abc123",
"gateway": "sharkpay",
"amount": 100000,
"channel": "bank_transfer",
"merchant_order_no": "ORDER_20260630_001",
"notify_url": "https://yourdomain.com/payment/callback",
"return_url": "https://yourdomain.com/payment/result"
}
Bước 1–3: giữ tất cả field, không field nào bị loại (không có sign/rỗng).
Bước 4: Sort theo key alphabetically:
amount, channel, gateway, merchant_order_no, notify_url, return_url, website_key
Bước 5: Canonical string:
amount=100000|channel=bank_transfer|gateway=sharkpay|merchant_order_no=ORDER_20260630_001|notify_url=https://yourdomain.com/payment/callback|return_url=https://yourdomain.com/payment/result|website_key=wk_abc123
Bước 6: HMAC-SHA256(canonical, "your_website_secret") → ví dụ: 3a7f9c2e...
Bước 7: Request cuối cùng:
{
"website_key": "wk_abc123",
"gateway": "sharkpay",
"amount": 100000,
"channel": "bank_transfer",
"merchant_order_no": "ORDER_20260630_001",
"notify_url": "https://yourdomain.com/payment/callback",
"return_url": "https://yourdomain.com/payment/result",
"sign": "3a7f9c2e..."
}
Implement mẫu — PHP
function hubSign(array $params, string $secret): string {
$skip = ['sign', 'website_secret', 'website_secret_plain', 'website_secret_runtime', 'secret'];
$pairs = [];
foreach ($params as $k => $v) {
if (in_array($k, $skip, true)) continue;
if (is_array($v) || is_object($v)) continue;
$val = trim((string)$v);
if ($val === '') continue;
$pairs[$k] = $val;
}
ksort($pairs, SORT_STRING);
$canonical = implode('|', array_map(fn($k, $v) => "$k=$v", array_keys($pairs), $pairs));
return hash_hmac('sha256', $canonical, $secret);
}
$body = [
'website_key' => 'wk_abc123',
'gateway' => 'sharkpay',
'amount' => 100000,
'channel' => 'bank_transfer',
'merchant_order_no' => 'ORDER_20260630_001',
'notify_url' => 'https://yourdomain.com/payment/callback',
];
$body['sign'] = hubSign($body, 'your_website_secret');
$ch = curl_init('https://client.apinganhang.net/api/v1/payments/orders/create.php');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
]);
$res = json_decode(curl_exec($ch), true);
Implement mẫu — JavaScript (Node.js)
const crypto = require('crypto');
function hubSign(params, secret) {
const skip = new Set(['sign','website_secret','website_secret_plain','website_secret_runtime','secret']);
const pairs = {};
for (const [k, v] of Object.entries(params)) {
if (skip.has(k)) continue;
if (typeof v === 'object' && v !== null) continue;
const val = String(v).trim();
if (val === '') continue;
pairs[k] = val;
}
const canonical = Object.keys(pairs).sort().map(k => `${k}=${pairs[k]}`).join('|');
return crypto.createHmac('sha256', secret).update(canonical).digest('hex');
}
const body = {
website_key: 'wk_abc123',
gateway: 'sharkpay',
amount: 100000,
channel: 'bank_transfer',
merchant_order_no: 'ORDER_20260630_001',
notify_url: 'https://yourdomain.com/payment/callback',
};
body.sign = hubSign(body, 'your_website_secret');
await fetch('https://client.apinganhang.net/api/v1/payments/orders/create.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
Implement mẫu — Python
import hmac, hashlib, json, requests
def hub_sign(params: dict, secret: str) -> str:
skip = {'sign','website_secret','website_secret_plain','website_secret_runtime','secret'}
pairs = {k: str(v).strip() for k, v in params.items()
if k not in skip and not isinstance(v, (dict, list)) and str(v).strip() != ''}
canonical = '|'.join(f'{k}={v}' for k, v in sorted(pairs.items()))
return hmac.new(secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()
body = {
'website_key': 'wk_abc123',
'gateway': 'sharkpay',
'amount': 100000,
'channel': 'bank_transfer',
'merchant_order_no': 'ORDER_20260630_001',
'notify_url': 'https://yourdomain.com/payment/callback',
}
body['sign'] = hub_sign(body, 'your_website_secret')
resp = requests.post(
'https://client.apinganhang.net/api/v1/payments/orders/create.php',
json=body, timeout=20
).json()
Callback webhook từ Hub về site đối tác
Sau khi giao dịch được xác nhận, Hub POST JSON đến notify_forward_url (cấu hình tại app.apinganhang.net) kèm header:
X-Payment-Signature: sha256=<HMAC-SHA256 của raw JSON body>
Secret dùng để ký là notify_forward_secret (xem tại app.apinganhang.net → Website đã đăng ký → icon mắt). Cách xác thực phía đối tác:
// PHP
$rawBody = file_get_contents('php://input');
$sigHeader = $_SERVER['HTTP_X_PAYMENT_SIGNATURE'] ?? ''; // "sha256=abc..."
$secret = 'your_notify_forward_secret';
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expected, $sigHeader)) {
http_response_code(403); exit('bad signature');
}
$data = json_decode($rawBody, true);
website_secret và notify_forward_secret là 2 secret khác nhau. website_secret dùng để ký request gọi Hub; notify_forward_secret dùng để Hub ký webhook gửi về site.
Lỗi xác thực thường gặp
| Mã lỗi | Nguyên nhân | Cách fix |
|---|---|---|
WEBSITE_AUTH_FAILED | Thiếu website_key hoặc sai key | Lấy đúng website_key từ dashboard |
WEBSITE_AUTH_FAILED (Chữ ký không hợp lệ) | Canonical string sai — sort sai, có field rỗng, dùng | thay = | Log ra canonical string và so sánh từng bước |
WEBSITE_AUTH_FAILED (Website chưa có secret) | Chưa tạo secret lần đầu | Vào app.apinganhang.net → Xoay secret lần đầu |
| Chữ ký đúng nhưng vẫn lỗi | Gửi JSON array [] hoặc nested object bị skip trong ký nhưng không skip khi xử lý | Chỉ dùng string/number ở cấp cao nhất khi ký |
Webhook callback — payload mẫu từ Hub về site
Sau khi cổng thanh toán báo kết quả cho Hub, Hub xác thực callback của cổng, cập nhật đơn rồi POST JSON tới notify_forward_url của website đã tạo đơn, kèm header:
Content-Type: application/json X-Payment-Signature: sha256=<HMAC-SHA256(raw JSON body, notify_forward_secret)> User-Agent: Apinganhang-PaymentHub/1.0
Chữ ký ký trên đúng chuỗi JSON đã gửi (không phải JSON decode/encode lại), dùng secret notify_forward_secret của website (xem tại app.apinganhang.net → Website đã đăng ký → icon mắt) — khác với website_secret dùng để ký request gọi Hub.
Envelope chung cho mọi cổng (WowPay, SharkPay, EeziePay, 1DPay)
{
"event": "payment.<gateway>.callback",
"gateway": "sharkpay",
"timestamp": 1790856752,
"data": {
"gateway": "sharkpay",
"success": true,
"status": "...",
"amount": 100000,
"merchant_order_no": "ORDER_20260630_001"
/* + các field gốc do cổng gửi, khác nhau theo từng cổng — xem bên dưới */
}
}
event luôn là payment.<gateway>.callback (ví dụ payment.sharkpay.callback, payment.wowpay.callback, payment.eeziepay.callback, payment.1dpay.callback) — kể cả cho lệnh rút (payout), không có event riêng payout.confirmed. Phân biệt payin/payout bằng mã đơn (merchant_order_no) phía site tự quản lý, hoặc field order_type nếu cổng đó có trả (xem ví dụ 1DPay).
Field trong data | Luôn có? | Ý nghĩa |
|---|---|---|
gateway | Có | Mã cổng viết thường: wowpay/sharkpay/eeziepay/1dpay |
success | Có | true = giao dịch thành công. Callback đang xử lý/thất bại có success: false — site phải tự kiểm tra field này, không coi mọi webhook nhận được là thành công |
status | Có | Trạng thái thô (tuỳ cổng) ứng với callback đó |
amount | Có | Số tiền của đơn gốc khi tạo (payment_hub_orders.amount) — Hub không lấy theo số tiền trong callback của cổng, kể cả khi callback bị giả mạo/bơm số tiền |
merchant_order_no | Có | Mã đơn/lệnh của site đã dùng lúc tạo đơn |
| field khác (viết hoa/thường tuỳ cổng) | Tuỳ cổng | Dữ liệu gốc cổng gửi về Hub được giữ nguyên trong data — tên field khác nhau theo từng cổng, xem phần riêng của từng cổng: WowPay (mch_order_no, real_amount...), SharkPay (payin/payout) và Settlement (settleOrderId...), EeziePay (billno...), 1DPay (payload mẫu đầy đủ + bảng field) |
Xác thực chữ ký phía đối tác (giống nhau cho mọi cổng):
// PHP
$rawBody = file_get_contents('php://input');
$sigHeader = $_SERVER['HTTP_X_PAYMENT_SIGNATURE'] ?? ''; // "sha256=abc..."
$secret = 'your_notify_forward_secret';
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expected, $sigHeader)) {
http_response_code(403); exit('bad signature');
}
$payload = json_decode($rawBody, true);
$data = $payload['data'] ?? [];
if (($data['success'] ?? false) === true) {
// tìm đơn theo $data['merchant_order_no'] -> nếu chưa xử lý, cộng $data['amount']; đã xử lý -> bỏ qua
} else {
// đang xử lý / thất bại -> không cộng tiền, tuỳ xử lý UI/hoàn tiền phía site
}
http_response_code(200); echo 'OK';
website_secret và notify_forward_secret là 2 secret khác nhau. website_secret dùng để ký request gọi Hub; notify_forward_secret dùng để Hub ký webhook gửi về site.
- Idempotent — mỗi đơn chỉ được cộng tiền và forward webhook thành công 1 lần. Cổng thanh toán có thể gửi callback thành công nhiều lần (retry/replay), nhưng Hub dùng khoá nguyên tử trên đơn hàng (
credited_at) nên chỉ callback thành công đầu tiên mới cộnglogs_historyvà POST webhook về site. Các callback thành công trùng sau đó Hub vẫn ACK cho cổng nhưng không forward lại. - Callback đang xử lý / thất bại vẫn được forward. Chỉ callback thành công bị chặn forward lặp lại (trùng/replay) — các trạng thái khác (
success: false, ví dụ đang xử lý hoặc gateway báo lỗi) được forward về site mỗi lần Hub nhận, để site cập nhật đúng trạng thái đơn (kể cả báo thất bại cho đơn rút). - Số tiền webhook luôn là số tiền đơn hàng gốc. Trường
amountHub gửi về site lấy từ số tiền đã chốt khi tạo đơn, không lấy theo số tiền trong callback của cổng. - Không có cơ chế tự động gửi lại (retry/redelivery) phía Hub. Hub gọi
notify_forward_urlđúng 1 lần cho mỗi callback cần forward (timeout 8 giây); nếu site đối tác timeout/lỗi/trả về khác 2xx, Hub không tự gửi lại — chỉ ghi nhận kết quả gửi (thành công/thất bại) vào log nội bộ. Site đối tác nên: (1) trả HTTP 2xx thật nhanh ngay khi xác thực chữ ký xong, xử lý nghiệp vụ sau nếu cần; (2) tự đối soát định kỳ qua API tra cứu đơn của từng cổng (không dựa hoàn toàn vào webhook) để không bỏ sót trường hợp webhook gửi thất bại. - Khuyến nghị: phía site đối tác vẫn nên tự chống trùng theo
merchant_order_no(bỏ qua nếu đơn đã xử lý) như một lớp phòng thủ bổ sung.
Luồng Payin — EeziePay Form POST
EeziePay dùng form POST mở tab mới tới fundtransfer.php (không iframe). Hub trả về form_action + form_fields để site render form.
Ký SHA1 (deposit v3.1)
UPPER(SHA1("service_version=3.1&partner_code=...&partner_orderid=...&...&key=EncryptionKey"))
Thứ tự field theo tài liệu chính thức; bỏ field rỗng; remarks không ký. Callback thành công: status 000 hoặc 002. Hub trả XML:
<xml><billno>...</billno><status>OK</status></xml>
Bank codes VND — Online banking & QR
EeziePay chọn kênh qua field bank_code khi tạo đơn. Hub forward nguyên giá trị vào form_fields.bank_code.
| Kênh | bank_code (ví dụ) | Mô tả |
|---|---|---|
| Online banking | VCB.VN | Vietcombank Internet Banking |
| Online banking | TCB.VN | Techcombank Internet Banking |
| QR chuyển khoản | VCB.QR.VN | Vietcombank QR |
| QR chuyển khoản | MM.QR.VN | Ví / MoMo QR |
Hoặc truyền pay_type + bank thay cho bank_code:
// Online banking Vietcombank
{ "pay_type": "online_banking", "bank": "VCB" } → bank_code = VCB.VN
// QR Vietcombank
{ "pay_type": "qr", "bank": "VCB" } → bank_code = VCB.QR.VN
// QR MoMo
{ "pay_type": "qr", "bank": "MOMO" } → bank_code = MM.QR.VN
Danh sách đầy đủ theo merchant: EeziePay Deposit API.
Cấu hình Domain API & endpoint paths
Domain API chỉ là gốc, ví dụ https://gogomart168com.com — không dán path fundtransfer.php hoặc fundtransfer_enquiry.php vào ô Domain.
5 path endpoint (Fund Transfer / Query / Payout / …) nhập riêng từng file trên dashboard. Hub ghép: {Domain}/{fundtransfer.php}. Nếu thấy URL dạng .../fundtransfer_enquiry.php/fundtransfer.php → Domain hoặc path bị cấu hình nhầm.
Luồng Payout — EeziePay
Luồng Payin/Payout — WowPay JSON API
WowPay dùng JSON API thuần (không form/iframe). Hub ký MD5 uppercase rồi POST trực tiếp tới {Domain API}/api/payin/create/ hoặc /api/payout/create/.
Ký MD5
UPPER(MD5(sort_by_key_asc("key1=value1&key2=value2&...&key=SecretKey")))
Field rỗng/null không tham gia ký. Áp dụng cho mọi request (payin/payout/query/balance) và cả callback gửi tới Hub.
mch_id, chỉ có mch_order_no. Hub tra merchant bằng cách tìm đơn đã lưu (payment_hub_orders) theo mch_order_no, không còn dựa vào merchant ID trong callback.Cấu hình WowPay Dashboard
Thiết lập tại app.apinganhang.net/integration/wowpay (yêu cầu gói VIP).
| Trường trên APInganhang | Trên WowPay / API | Ghi chú |
|---|---|---|
| Bật cổng | — | Bật để cho phép tạo đơn/payout qua gateway=wowpay. |
| Domain API | Host API WowPay | Ví dụ https://api.open.mwowpay.com. Hub tự ghép /api/payin/create/, /api/payin/query/, /api/payout/create/, /api/payout/query/, /api/payin/balance/, /api/payout/balance/. |
| Merchant ID | mch_id | ID merchant (số) do WowPay cấp. |
| API Key | payin_secret_key / payout_secret_key | WowPay cho dùng chung 1 key cho cả payin và payout. |
| Application ID | không dùng cho WowPay | Trường này chỉ hiển thị chung trên form; hiện không map vào field nào của API WowPay (khác SharkPay dùng product_id). |
| URL callback Hub | callback_url (tham số request, optional) | https://client.apinganhang.net/api/v1/payments/callbacks/wowpay.php — Hub tự gửi field này ở mỗi request tạo đơn/payout. Nếu muốn an toàn hơn, khai báo thêm URL này làm callback mặc định trong merchant dashboard WowPay (áp dụng khi field callback_url bị bỏ trống). |
| Return URL | return_url | Optional — URL chuyển khách (cashier redirect) sau khi thanh toán payin. |
| IP whitelist | — | IP server website đối tác được phép gọi API Hub. Để trống = không giới hạn. |
user_id (bắt buộc theo API WowPay)
WowPay yêu cầu field user_id ở mọi request tạo đơn/payout — đây là ID khách hàng cuối (do website đối tác tự định danh), không phải ID cấu hình tĩnh của merchant. WowPay dùng field này để kiểm soát rủi ro/blacklist theo từng khách (xem mã lỗi 1225 User in blacklist).
user_id hoặc customer_id khi gọi orders/create.php / payouts/create.php với gateway=wowpay, ứng với ID khách hàng của bạn. Nếu không truyền, Hub mặc định gửi "guest" sang WowPay cho tất cả giao dịch không định danh — có thể bị WowPay flag nhầm nếu 1 giao dịch "guest" bị đưa vào blacklist.WowPay Payin API Tóm tắt
Gọi qua Hub: POST /api/v1/payments/orders/create.php với "gateway": "wowpay".
| Field (gửi cho Hub) | Bắt buộc | Map sang API WowPay |
|---|---|---|
merchant_order_no | ✓ | mch_order_no — phải duy nhất |
amount (VNĐ) | ✓ | apply_amount = amount × 100 (cent) |
pay_type / channel | ✓ (mặc định momo) | pay_type — xem danh sách kênh: momo, zalo, bankcard, bankcard_qr, bankcard_free |
bank_code | khi pay_type = bankcard/bankcard_qr | bank_code — field cấp cao nhất, KHÔNG lồng trong object khác. Xem danh sách mã hợp lệ; Hub tự chuẩn hoá hoa/thường và vài tên thường gặp (VIETCOMBANK→VCB, MBBANK→MB...) |
user_id / customer_id | khuyến nghị | user_id (mặc định "guest" nếu bỏ trống) |
device_ip / client_ip | tự động | device_ip — Hub tự lấy IP request nếu không truyền |
return_url | optional | return_url |
Response data từ Hub: gateway_order_id (order_no của WowPay), pay_url (charge_info — link mở để thanh toán), qr_code (cashier_info.qrcode nếu có), amount, channel.
WowPay Payout API Tóm tắt
Gọi qua Hub: POST /api/v1/payments/payouts/create.php với "gateway": "wowpay". WowPay hiện chỉ hỗ trợ pay_type=bankcard (Hub tự gửi cố định).
| Field (gửi cho Hub) | Bắt buộc | Map sang API WowPay |
|---|---|---|
merchant_order_no | ✓ | mch_order_no |
amount (VNĐ) | ✓ | amount = amount × 100 (cent) — payout API gọi field này là amount, không phải apply_amount |
payout_bank_code / bank_code | ✓ | payout_bank_code — mã ngân hàng nhận tiền, xem danh sách mã hợp lệ (Hub tự chuẩn hoá hoa/thường và alias tên đầy đủ) |
payout_account_no / account_no / bank_number | ✓ | payout_account_no |
payout_name / account_name | ✓ | payout_name — tên người nhận |
payout_phone_no / phone | optional | payout_phone_no |
user_id / customer_id | khuyến nghị | user_id (mặc định "guest") |
Danh sách bank_code WowPay Bắt buộc khi bankcard/bankcard_qr/payout
Áp dụng cho bank_code ở payin (pay_type=bankcard hoặc bankcard_qr) và payout_bank_code ở payout. Đây là mã WowPay yêu cầu — khác với mã ngân hàng dùng ở phần xác minh giao dịch ngân hàng (vd Hub dùng VIETCOMBANK, WowPay dùng VCB).
bank_code khi pay_type=bankcard/bankcard_qr → WowPay trả 1010 Bank Code Missing. Phải gửi field bank_code ở cấp cao nhất của request, không lồng trong form_fields hay đặt nhầm vào field pay_type/bank_type.| bank_code | Tên ngân hàng | bank_code | Tên ngân hàng |
|---|---|---|---|
ACB | Asia Commercial Bank | NAMA | Nam A Bank |
SAC | Sacombank | NCB | National Citizen Bank |
TCB | Techcombank | OCEAN | OCEAN Bank |
VCB | Vietcombank | PVCOM | PVcomBank |
VTB | Vietinbank | SAIGON | SaigonBank |
DAB | DongA Bank | SEA | SeABank |
BIDV | BIDV Bank | SHBVN | Shinhan Bank VN |
EXIM | Eximbank | VIB | VIB Bank |
AGB | Agribank | VRB | Vietnam-Russia Bank |
TPB | TienPhong Bank | VAB | Viet A Bank |
MB | MBBank (Quân Đội) | VDB | Vietnam Development Bank |
VPB | VPBank | GPB | GPBank |
OCB | OCB (Phương Đông) | VIETCAPITALBANK | Viet Capital Bank |
SCB | SCB Bank | PGBANK | PGBank |
SHB | SHB (Sài Gòn Hà Nội) | CIMB | CIMB Bank |
ABB | ABBank | HLB | Hong Leong Bank |
BACA | Bac A Bank | IVB | Indovina Bank |
KLB | Kien Long Bank | PBVN | VID Public Bank |
BVB | BaoViet Bank | UOB | UOB Bank |
HDB | HDBank | VIETB | VietBank |
LPB | LienVietPostBank | WOO | Woori Bank |
MSB | Maritime Bank | YOLO | YOLO (VPDirect) |
DEUT | Deutsche Bank | ||
MBV | Modern Bank of Vietnam | ||
VIKKI | Vikki Digital Bank | ||
TIMO | Timo Bank | ||
Hub tự chuẩn hoá (viết hoa, bỏ khoảng trắng, map vài alias tên đầy đủ phổ biến: VIETCOMBANK→VCB, MBBANK→MB, VIETTINBANK→VTB, TPBANK→TPB, SEABANK→SEA...). Nếu gửi mã không nhận diện được, Hub trả lỗi VALIDATION_FAILED ngay (không cần đợi gọi WowPay).
Ví dụ tạo đơn WowPay
Payin — MoMo
POST /api/v1/payments/orders/create.php
Authorization: Bearer <token>
Content-Type: application/json
{
"gateway": "wowpay",
"merchant_order_no": "ORD20260623001",
"amount": 50000,
"pay_type": "momo",
"user_id": "user123",
"return_url": "https://shop.example.com/return"
}
Response thành công:
{
"success": true,
"data": {
"gateway": "wowpay",
"merchant_order_no": "ORD20260623001",
"gateway_order_id": "2301051608200009",
"pay_url": "https://pay.cashier.com/cashier/?token=...",
"qr_code": "2|99|0936434203|PHAM VAN SINH||0|0|50000|9W6T7|transfer_myqr",
"amount": 50000,
"channel": "momo"
}
}
Payin — Quét mã QR ngân hàng (bankcard_qr)
bank_code là field cấp cao nhất, bắt buộc khi pay_type là bankcard hoặc bankcard_qr:
{
"gateway": "wowpay",
"merchant_order_no": "ORD20260623002",
"amount": 200000,
"pay_type": "bankcard_qr",
"bank_code": "VCB",
"user_id": "user123"
}
Payout
POST /api/v1/payments/payouts/create.php
Authorization: Bearer <token>
Content-Type: application/json
{
"gateway": "wowpay",
"merchant_order_no": "POUT20260623001",
"amount": 300000,
"payout_name": "NGUYEN VAN A",
"payout_bank_code": "VCB",
"payout_account_no": "0123456789",
"user_id": "user123"
}
So sánh cổng
| SharkPay | WowPay | EeziePay | 1DPay | |
|---|---|---|---|---|
| Payin | JSON/form API | JSON API | Form → fundtransfer.php | JSON API — QR ngân hàng (chi tiết) |
| Sign | MD5 uppercase | MD5 uppercase | SHA1 uppercase | AES-256-CBC + RSA-SHA1 (Hub tự xử lý) |
| Callback ack | text success | text success | XML <status>OK</status> | text success |
| Balance | — | 1 số dư | Fund Transfer + Fund Out | 1 số dư (available/current) |
| Amount VND | fen (×100) | cent (×100) | integer, không lẻ | integer VND (không ×100) |
Cấu hình EeziePay Dashboard
Thiết lập tại app.apinganhang.net/integration/eeziepay (yêu cầu gói VIP). Các trường trên form khớp với cấu hình merchant EeziePay như sau:
| Trường trên APInganhang | Trên EeziePay / API | Ghi chú |
|---|---|---|
| Bật cổng | — | Bật để cho phép tạo đơn/payout qua gateway=eeziepay. |
| Domain API | Gateway base URL | URL gốc do EeziePay cấp, ví dụ https://gogomart168com.com. Hub ghép với các đường dẫn API bên dưới. |
| Fund Transfer / Query / Payout / Balance API | Endpoint paths | Copy từ merchant panel: fundtransfer.php, fundtransfer_enquiry.php, withdrawal.php, withdrawal_enquiry.php, querybalance.php. |
| Merchant ID | partner_code | Mã đối tác / merchant trên EeziePay. |
| Encryption Key | Encryption / signing key | Dùng chung cho payin + payout. Ký SHA1 uppercase theo thứ tự field trong tài liệu EeziePay. |
| URL callback Hub | backend_url (deposit), notify_url (payout) | https://client.apinganhang.net/api/v1/payments/callbacks/eeziepay.php — Hub tự thêm ?type=deposit hoặc ?type=payout khi tạo lệnh. |
| Return URL | redirect_url | URL chuyển khách về sau khi thanh toán (có thể ghi đè khi tạo đơn). |
| IP whitelist | — | IP server website của bạn được phép gọi API Hub (create order/payout). Để trống = không giới hạn. |
| Notify forward URL / secret | — | Sau khi Hub nhận callback từ EeziePay, forward JSON về website kèm header X-Payment-Signature: sha256=.... |
Quy trình cấu hình (khuyến nghị)
- Lấy Domain API, Merchant ID, Encryption Key và 5 đường dẫn API từ merchant EeziePay.
- Điền các trường trên vào tab EeziePay, bật cổng, nhấn Lưu.
- Copy URL callback Hub dán vào merchant EeziePay (nếu bảng điều khiển yêu cầu đăng ký URL cố định).
- Nhấn Kiểm tra kết nối — gọi balance inquiry qua Hub (endpoint cấu hình
querybalance.phphoặc tương đương). - Nhấn Cập nhật số dư — xem Fund Transfer (nạp) và Fund Out (chi hộ).
- Thêm Website Integration phía dưới nếu nhiều site; mỗi site có
website_key+website_secretriêng.
Balance inquiry
EeziePay có API balance (thường POST {base_url}/querybalance.php hoặc balance.php tùy merchant). Hub bọc qua:
POST /api/v1/payments/balance.php
Authorization: Bearer <token>
Content-Type: application/json
{
"gateway": "eeziepay",
"currency": "VND"
}
Response mẫu:
{
"success": true,
"data": {
"currency": "VND",
"items": [
{ "type": "Fund Transfer", "available": "1000000", "current": "1000000" },
{ "type": "Fund Out", "available": "500000", "current": "500000" }
]
}
}
Fund Transfer = số dư dùng nạp tiền; Fund Out = số dư chi hộ. Hỗ trợ VND và IDR.
EeziePay Deposit API Tóm tắt
Form POST tới {Domain API}/fundtransfer.php. Ký SHA1 uppercase theo thứ tự field:
service_version, partner_code, partner_orderid, member_id, member_ip, currency, amount, backend_url, redirect_url, bank_code, trans_time
bank_code quyết định kênh online banking hay QR (xem bảng ở trên). Bỏ trống nếu để EeziePay hiển thị trang chọn ngân hàng.
Hub trả form_action + form_fields + pay_channel khi gọi POST /api/v1/payments/orders/create.php với gateway=eeziepay.
Tài liệu gốc: EeziePay Deposit EN
Ví dụ tạo đơn EeziePay
Online banking (Vietcombank)
POST /api/v1/payments/orders/create.php
Authorization: Bearer <token>
Content-Type: application/json
{
"gateway": "eeziepay",
"website_key": "wk_xxx",
"website_secret": "ws_xxx",
"merchant_order_no": "ORD20260614001",
"amount": 100000,
"currency": "VND",
"bank_code": "VCB.VN",
"member_id": "user123",
"member_ip": "1.2.3.4",
"return_url": "https://shop.example.com/return"
}
QR chuyển khoản (Vietcombank QR)
{
"gateway": "eeziepay",
"merchant_order_no": "ORD20260614002",
"amount": 200000,
"currency": "VND",
"pay_type": "qr",
"bank": "VCB",
"return_url": "https://shop.example.com/return",
"member_id": "user123",
"member_ip": "1.2.3.4"
}
Response thành công:
{
"success": true,
"data": {
"form_action": "https://gogomart168com.com/fundtransfer.php",
"form_fields": { "...": "...", "bank_code": "VCB.QR.VN" },
"pay_channel": "qr",
"bank_code": "VCB.QR.VN"
}
}
Site render form:
<form method="POST" action="{form_action}" target="_blank">
<!-- hidden inputs từ form_fields -->
<button type="submit">Thanh toán</button>
</form>
1DPay — Tổng quan gateway=1dpay
1DPay là cổng nạp QR ngân hàng (VietQR) + chi hộ (rút tiền) VND. Mã cổng khi gọi Hub: "gateway": "1dpay". Toàn bộ phần mã hoá/ký riêng của 1DPay do Hub tự xử lý — website đối tác không cần mã hoá gì thêm, chỉ gọi Hub như các cổng khác: header Authorization: Bearer <token> + website_key + sign (HMAC-SHA256 bằng website_secret, xem Xác thực đối tác).
| Chức năng | Endpoint Hub | Ghi chú |
|---|---|---|
| Tạo đơn nạp (payin) | POST orders/create.php | Trả QR (chuỗi + ảnh), STK, tên chủ TK, nội dung CK, link trang thanh toán |
| Tra cứu đơn nạp | POST orders/query.php | Trả state = success | failed | processing |
| Tạo lệnh rút (payout) | POST payouts/create.php | 500.000 – 200.000.000 VND / lệnh |
| Tra cứu lệnh rút | POST payouts/query.php | Giống tra cứu đơn nạp |
| Kết quả giao dịch | Webhook Hub → notify_forward_url | JSON + header X-Payment-Signature (xem bên dưới) |
website_key RIÊNG cho 1DPay. Hub gửi webhook kết quả về notify_forward_url + ký bằng notify_forward_secret của chính website (website_key) đã tạo đơn. Vì vậy hãy đăng ký 1 website riêng cho 1DPay tại app.apinganhang.net → Cổng thanh toán → Website đã đăng ký (VD tên TenSite-1dpay, notify_forward_url trỏ tới endpoint nhận callback 1DPay của site), rồi dùng bộ website_key / website_secret / notify_forward_secret đó cho mọi request gateway=1dpay. Không dùng chung khoá với website của WowPay/SharkPay/EeziePay — nếu dùng chung, webhook 1DPay sẽ bị gửi về URL của cổng khác và site không xác nhận được giao dịch.
- Field
notify_urltrong request không được dùng cho 1DPay — Hub tự khai báo URL callback của Hub với 1DPay và chỉ forward vềnotify_forward_urlcủa website. amountlà số nguyên VND (không nhân ×100). Hub chấp nhận cả100000,"100000","100.000".merchant_order_nophải duy nhất cho mỗi đơn/lệnh (Hub cũng nhận aliasmch_order_no,order_code).
1DPay Payin — Tạo đơn nạp QR ngân hàng
Gọi qua Hub: POST /api/v1/payments/orders/create.php với "gateway": "1dpay".
| Field (gửi cho Hub) | Bắt buộc | Ý nghĩa |
|---|---|---|
gateway | ✓ | 1dpay |
website_key + sign | ✓ | Khoá website riêng cho 1DPay + chữ ký HMAC (xem Xác thực) |
merchant_order_no | ✓ | Mã đơn của site, duy nhất |
amount (VNĐ) | ✓ | Số nguyên > 0 |
channel (hoặc pay_type / payment_method) | khuyến nghị | QR — nạp bằng quét mã QR ngân hàng (VietQR). Bỏ trống = QR. Xem bảng kênh bên dưới. |
member_id (hoặc user_id / customer_id) | khuyến nghị | ID/username khách nạp phía site — 1DPay dùng để định danh khách. Bỏ trống = guest. |
device_ip / client_ip | khuyến nghị | IP của khách nạp. Bỏ trống = Hub dùng IP server gọi API. |
return_url | optional | URL đưa khách quay về sau khi thanh toán trên trang 1DPay (pay_url). |
Kênh nạp (channel)
channel gửi Hub | Kênh 1DPay | Ghi chú |
|---|---|---|
QR (hoặc bỏ trống, BANK_QR, VIETQR, BANKCARD_QR) | BQR — QR ngân hàng | Kênh đang dùng thực tế, đã chạy thật end-to-end. Khuyến nghị dùng kênh này. |
BANK_TRANSFER | BTR — chuyển khoản | Chỉ dùng khi 1DPay đã mở kênh này cho merchant — hỏi quản trị Hub trước. |
BANK / ONLINE_BANKING | BMR — online banking | Bắt buộc thêm bank_code (ngân hàng khách dùng). Chỉ dùng khi đã được mở kênh. |
Hub không áp hạn mức nạp riêng cho 1DPay; nếu số tiền nằm ngoài hạn mức 1DPay áp cho merchant, 1DPay từ chối và Hub trả lỗi GATEWAY_FAILED kèm mã lỗi của cổng (xem Mã lỗi). Hạn mức hiển thị cho khách nên cấu hình ở phía site.
Ví dụ request
POST https://client.apinganhang.net/api/v1/payments/orders/create.php
Authorization: Bearer <token>
Content-Type: application/json
{
"gateway": "1dpay",
"website_key": "ws_live_xxxxxxxxxxxxxxxx",
"merchant_order_no": "ORD20261002001",
"amount": 100000,
"channel": "QR",
"member_id": "user123",
"device_ip": "113.161.1.2",
"return_url": "https://yourdomain.com/profile?page=transaction-history",
"sign": "<hmac_sha256>"
}
Chuỗi ký (canonical, sort key ASCII, nối bằng |):
amount=100000|channel=QR|device_ip=113.161.1.2|gateway=1dpay|member_id=user123|merchant_order_no=ORD20261002001|return_url=https://yourdomain.com/profile?page=transaction-history|website_key=ws_live_xxxxxxxxxxxxxxxx
Response thành công
{
"success": true,
"message": "Order created",
"data": {
"gateway": "1dpay",
"merchant_order_no": "ORD20261002001",
"gateway_order_id": "D2026100110148101",
"pay_url": "https://cashier.1dpayapp.com/Deposit/VietQRDeposit/?a=...",
"qr_code": "00020101021138520010A000000727...6304ABCD",
"qr_image_base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...",
"bank_code": "EXB",
"account_number": "1234567890",
"account_name": "NGUYEN VAN B",
"transfer_content": "KHOAN3JZ2TU",
"amount": 100000,
"actual_amount": 100000,
"channel": "BQR",
"raw": { "...": "phản hồi gốc của 1DPay (tham khảo, không cần dùng)" }
}
}
| Field | Cách dùng |
|---|---|
gateway_order_id | Mã giao dịch phía 1DPay (đơn nạp bắt đầu bằng D). Lưu lại để đối soát. |
qr_image_base64 | Ảnh QR đã kèm tiền tố data URI (data:image/...;base64,...) → gán thẳng vào <img src>, không cần thêm tiền tố. |
qr_code | Chuỗi VietQR (EMVCo) — dùng nếu site muốn tự vẽ QR. |
bank_code, account_number, account_name | Ngân hàng / số tài khoản / tên chủ tài khoản nhận tiền — hiển thị cho khách chuyển khoản thủ công. |
transfer_content | Nội dung chuyển khoản bắt buộc ghi đúng — 1DPay dùng để khớp lệnh. Nhắc khách ghi đúng nội dung và đúng số tiền. |
pay_url | Trang thanh toán của 1DPay (hiện QR + thông tin CK) — có thể mở tab mới thay vì tự hiển thị. |
actual_amount | Số tiền khách cần chuyển theo 1DPay (thường bằng amount). |
1DPay Payout — Tạo lệnh rút 500.000 – 200.000.000 VND
Gọi qua Hub: POST /api/v1/payments/payouts/create.php với "gateway": "1dpay".
| Field (gửi cho Hub) | Bắt buộc | Ý nghĩa |
|---|---|---|
gateway | ✓ | 1dpay |
website_key + sign | ✓ | Khoá website riêng cho 1DPay + chữ ký HMAC |
merchant_order_no | ✓ | Mã lệnh rút duy nhất — Hub dùng để chống chi 2 lần |
amount (VNĐ) | ✓ | Số nguyên, từ 500.000 đến 200.000.000 |
bank_code (hoặc payout_bank_code) | ✓ | Mã ngân hàng nhận — xem danh sách. Hub tự chuẩn hoá hoa/thường và alias phổ biến. |
account_number (hoặc account_no / bank_number / payout_account_no) | ✓ | Số tài khoản người nhận |
account_name (hoặc payout_name) | ✓ | Tên chủ tài khoản người nhận |
member_id (hoặc user_id / customer_id) | khuyến nghị | ID khách rút phía site. Bỏ trống = guest. |
device_ip / client_ip | optional | IP khách. Bỏ trống = IP server gọi API. |
merchant_order_no): HTTP 422
{
"success": false,
"message": "Số tiền rút qua 1dpay phải từ 500.000 đến 200.000.000 VND.",
"data": { "code": "AMOUNT_OUT_OF_RANGE", "min": 500000, "max": 200000000 }
}
Lệnh rút lớn hơn 200.000.000 VND cần tách thành nhiều lệnh (mỗi lệnh 1 merchant_order_no riêng).Ví dụ request
POST https://client.apinganhang.net/api/v1/payments/payouts/create.php
Authorization: Bearer <token>
Content-Type: application/json
{
"gateway": "1dpay",
"website_key": "ws_live_xxxxxxxxxxxxxxxx",
"merchant_order_no": "WD20261002001",
"amount": 1500000,
"bank_code": "VCB",
"account_number": "0123456789",
"account_name": "NGUYEN VAN A",
"member_id": "user123",
"sign": "<hmac_sha256>"
}
Response thành công (đã gửi lệnh sang 1DPay)
{
"success": true,
"message": "Payout submitted",
"data": {
"gateway": "1dpay",
"merchant_order_no": "WD20261002001",
"gateway_order_id": "W2026100200000001",
"bank_code": "VCB",
"raw": { "...": "phản hồi gốc của 1DPay" }
}
}
success: true ở bước này chỉ có nghĩa là 1DPay đã nhận lệnh — tiền chưa chắc đã chuyển. Kết quả cuối cùng (thành công / thất bại) đến qua webhook hoặc tra cứu.
- Gọi lại cùng
merchant_order_nokhi lệnh trước đang xử lý/đã thành công → HTTP 409DUPLICATE_ORDER, Hub không gửi tiền lần 2. - Nếu 1DPay không phản hồi rõ ràng (timeout/lỗi 5xx) → Hub trả
GATEWAY_TIMEOUT(HTTP 502) và giữ khoámerchant_order_no, vì lệnh có thể đã được 1DPay nhận. Không tạo lệnh mới cho cùng yêu cầu rút — hãy tra cứu hoặc chờ webhook. - Nếu 1DPay từ chối rõ ràng (
GATEWAY_FAILED) hoặc lỗi validate → chưa có tiền nào được gửi, có thể gọi lại cùngmerchant_order_nosau khi sửa dữ liệu.
Danh sách bank_code 1DPay Payout
Mã ngân hàng nhận tiền khi rút qua 1DPay (khác một số mã của WowPay). Hub nhận cả mã 1DPay lẫn alias thông dụng / mã WowPay và tự chuyển đổi, ví dụ: VIETCOMBANK→VCB, TCB/TECHCOMBANK→TEC, VTB/VIETINBANK/CTG→VTN, MB/MBBANK→MBB, AGB/AGRIBANK→AGR, SAC/STB/SACOMBANK→SAB, EXIM/EIB→EXB, BACA→BAB, NAMA→NAB, SEA/SEABANK→SEAB, OCEAN→OB, CIMB→CIMBV, WOORI→WOO, SHINHAN→SHBVN, VIETCAPITALBANK/BVBANK→Viet Capital Bank. Mã không nhận diện được → HTTP 422 VALIDATION_FAILED (chưa gọi sang cổng).
ABB ACB ACBCORP AGR BAB BIDV BIDVCORP BVB CAKE CIMBV DAB EXB EXBCORP GPB HDB HLB HSBCVN IVB KLB LIO LPB LPBANK MBB MBBCORP MSB MSBCORP NAB NCB OB OCB OCBCORP PBVN PGB PVCOM SAB SABCORP SAIGON SCB SCBV SEAB SHB SHBCORP SHBVN TCBCORP TEC TPB TPBCORP VAB VBSP VCB VCBCORP VIB "Viet Capital Bank" VIETB VIKKI VPB VPBCORP VRB VTN VTNCORP WOO
Mã có hậu tố CORP là tài khoản doanh nghiệp của ngân hàng tương ứng.
1DPay — Tra cứu đơn nạp / lệnh rút
POST https://client.apinganhang.net/api/v1/payments/orders/query.php (đơn nạp)
POST https://client.apinganhang.net/api/v1/payments/payouts/query.php (lệnh rút)
Authorization: Bearer <token>
Content-Type: application/json
{
"gateway": "1dpay",
"website_key": "ws_live_xxxxxxxxxxxxxxxx",
"merchant_order_no": "ORD20261002001",
"sign": "<hmac_sha256>"
}
Response data gồm chi tiết giao dịch từ 1DPay, cộng thêm các field chuẩn hoá của Hub:
{
"success": true,
"message": "Queried",
"data": {
"...": "các field chi tiết của 1DPay (statusId, amount, ...)",
"gateway": "1dpay",
"merchant_order_no": "ORD20261002001",
"gateway_order_id": "D2026100110148101",
"gateway_status": "6",
"state": "success"
}
}
Bảng trạng thái
| Loại | Mã 1DPay (gateway_status / status) | state (Hub chuẩn hoá) | Site nên làm |
|---|---|---|---|
| Nạp (payin) | 6 | success | Cộng tiền (1 lần duy nhất) |
7 | failed | Đánh dấu thất bại | |
mã khác (VD 4) | processing | Chờ tiếp — chưa phải thất bại | |
| Rút (payout) | 4 | success | Hoàn tất lệnh rút |
5 | failed | Lệnh rút thất bại → xử lý hoàn tiền cho khách phía site | |
| mã khác | processing | Chờ tiếp |
Lưu ý: mã thành công của nạp (6) và rút (4) khác nhau — nên dựa vào field state (hoặc success trong webhook) thay vì tự so mã số. Tra cứu đơn không tồn tại → NOT_FOUND.
1DPay — Webhook kết quả (Hub → site) X-Payment-Signature
Khi 1DPay báo kết quả, Hub xác thực callback của cổng, cập nhật đơn rồi POST JSON tới notify_forward_url của website đã tạo đơn, kèm header:
Content-Type: application/json X-Payment-Signature: sha256=<HMAC-SHA256(raw JSON body, notify_forward_secret)> User-Agent: Apinganhang-PaymentHub/1.0
Payload mẫu — nạp thành công
{
"event": "payment.1dpay.callback",
"gateway": "1dpay",
"timestamp": 1790856752,
"data": {
"CurrencyCode": "VND",
"MerchantTransactionId": "ORD20261002001",
"Status": 6,
"Amount": 100000,
"NetAmount": 99400,
"PaymentMethodCode": "BQR",
"UniqueReferenceNo": "KHOAN3JZ2TU",
"BankReferenceNo": null,
"Remark": null,
"merchant_order_no": "ORD20261002001",
"order_id": "D2026100110148101",
"order_type": "payin",
"status": "6",
"state": "success",
"success": true,
"amount": 100000,
"gateway": "1dpay"
}
}
Field trong data | Ý nghĩa |
|---|---|
merchant_order_no | Mã đơn/lệnh của site |
order_type | payin (nạp) hoặc payout (rút) |
success | true = giao dịch thành công. Chỉ cộng tiền / hoàn tất lệnh rút khi success === true |
state / status | Trạng thái chuẩn hoá / mã 1DPay — xem bảng trạng thái |
amount | Số tiền của đơn gốc khi tạo (Hub không lấy theo số tiền trong callback cổng) — dùng giá trị này để cộng tiền |
NetAmount | Số tiền thực nhận sau phí cổng (tham khảo đối soát) |
order_id | Mã giao dịch 1DPay (D… nạp, W… rút) |
Các field viết hoa (Status, Amount, UniqueReferenceNo...) | Dữ liệu gốc 1DPay gửi — chỉ để tham khảo/đối soát; có thể có thêm field khác |
Xác thực chữ ký (giống mọi cổng khác của Hub)
// PHP — ký trên RAW body, không decode rồi encode lại
$raw = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $raw, 'your_1dpay_notify_forward_secret');
if (!hash_equals($expected, $_SERVER['HTTP_X_PAYMENT_SIGNATURE'] ?? '')) {
http_response_code(403); exit('bad signature');
}
$p = json_decode($raw, true);
$d = $p['data'] ?? [];
if (($p['gateway'] ?? '') !== '1dpay') { http_response_code(400); exit; }
if (($d['success'] ?? false) === true) {
// tìm đơn theo $d['merchant_order_no'] + $d['order_type'];
// nếu đơn chưa xử lý -> cộng $d['amount'] (nạp) / hoàn tất (rút); đã xử lý -> bỏ qua
} elseif (($d['state'] ?? '') === 'failed') {
// đánh dấu thất bại (rút: hoàn tiền cho khách phía site)
}
http_response_code(200); echo 'OK';
// Node.js
const crypto = require('crypto');
const expected = 'sha256=' + crypto.createHmac('sha256', NOTIFY_FORWARD_SECRET).update(rawBody).digest('hex');
const ok = expected.length === sigHeader.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sigHeader));
- Secret dùng để verify là
notify_forward_secretcủa website 1DPay (không phảiwebsite_secret, không phải secret của website cổng khác). - Trả HTTP 2xx khi đã nhận. Hub chỉ forward webhook thành công 1 lần cho mỗi đơn; các callback trạng thái khác (đang xử lý / thất bại) vẫn được forward — site phải kiểm tra
success/state, không coi mọi webhook là thành công. - Site vẫn nên tự chống trùng theo
merchant_order_no(đơn đã xử lý thì bỏ qua).
1DPay — Mã lỗi thường gặp
| HTTP | data.code | Nguyên nhân | Xử lý |
|---|---|---|---|
| 401 | WEBSITE_AUTH_FAILED / Unauthorized | Thiếu/sai Bearer token, website_key hoặc chữ ký | Xem Xác thực đối tác |
| 422 | VALIDATION_FAILED | Thiếu merchant_order_no, amount ≤ 0, payout thiếu STK/tên, bank_code không hợp lệ | Sửa dữ liệu rồi gửi lại |
| 422 | AMOUNT_OUT_OF_RANGE | Payout ngoài 500.000 – 200.000.000 VND | Điều chỉnh/tách số tiền |
| 422 | — | "Gateway đang tắt hoặc chưa cấu hình đủ" | Liên hệ quản trị Hub bật 1DPay cho tài khoản |
| 200 | GATEWAY_FAILED (success:false) | 1DPay từ chối — message chứa mã lỗi cổng (VD PMT10005 Invalid Transaction Amount) | Kiểm tra success, không chỉ HTTP status |
| 502 | GATEWAY_TIMEOUT | Payout: 1DPay không phản hồi rõ ràng | Không tạo lệnh mới; tra cứu / chờ webhook |
| 409 | DUPLICATE_ORDER | Payout trùng merchant_order_no | Tra cứu lệnh cũ |
Tham khảo
- Xác thực đối tác — Website HMAC (thuật toán + code mẫu PHP/JS/Python)
- Webhook callback payload mẫu (Hub → site)
- Quản lý website_key / website_secret tại dashboard
- Cấu hình SharkPay (tóm tắt trên Hub)
- SharkPay Payin API (tóm tắt trên Hub)
- SharkPay Payout API — Agent Pay (tóm tắt trên Hub)
- SharkPay Settlement — hệ thống rút tiền thứ 2 (tóm tắt trên Hub)
- SharkPay Payin/Settlement API (vendor)
- SharkPay Agent Pay API (vendor)
- SPA cấu hình: app.apinganhang.net/integration/sharkpay
- Cấu hình WowPay (tóm tắt trên Hub)
- WowPay Payin API (tóm tắt trên Hub)
- WowPay Payout API (tóm tắt trên Hub)
- Danh sách bank_code WowPay (bankcard/bankcard_qr/payout)
- SPA cấu hình: app.apinganhang.net/integration/wowpay
- EeziePay API Documentation
- EeziePay Deposit API (tóm tắt trên Hub)
- EeziePay Balance API (tóm tắt trên Hub)
- EeziePay Deposit API (vendor)
- EeziePay Balance API (vendor)
- 1DPay — tổng quan & quy tắc website_key riêng
- 1DPay Payin — tạo đơn nạp QR (tóm tắt trên Hub)
- 1DPay Payout — tạo lệnh rút (tóm tắt trên Hub)
- Danh sách bank_code 1DPay (payout)
- 1DPay — tra cứu & bảng trạng thái
- 1DPay — webhook kết quả & xác thực chữ ký
- 1DPay — mã lỗi thường gặp
- SPA cấu hình: app.apinganhang.net/integration/1dpay
- API docs chung (xác thực giao dịch ngân hàng — sản phẩm khác, không liên quan Payment Hub)
- SPA cấu hình: app.apinganhang.net/integration/eeziepay