Payment Hub API

Hub trung gian tại client.apinganhang.net — tích hợp SharkPay, WowPay và EeziePay. Website đối tác gọi Hub; Hub ký request, nhận callback, ghi logs_history và forward webhook về site.

Tổng quan

Endpoints chính

MethodPathMô tả
GET/POSTsettings.phpCấu hình gateway (sharkpay, wowpay, eeziepay)
GETbalance.php?gateway=Số dư cổng (WowPay, EeziePay)
POSTtest.phpTest kết nối / balance
POSTorders/create.phpTạo đơn nạp (payin)
GET/POSTorders/query.phpTra cứu đơn nạp
POSTpayouts/create.phpTạo lệnh rút (payout)
GET/POSTpayouts/query.phpTra cứu payout
GET/POSTwebsites.phpQuản lý website integration
Chống gửi tiền trùng cho payout (từ 2026-07-03): Hub claim 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ý

  1. Thu thập tất cả field của request (JSON body hoặc form-data).
  2. Loại bỏ các field: sign, website_secret, website_secret_plain, website_secret_runtime, secret.
  3. Loại bỏ field có giá trị rỗng ("") và field kiểu array/object.
  4. 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).
  5. 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.
  6. Ký HMAC-SHA256: HMAC-SHA256(canonical_string, website_secret) — kết quả là chuỗi hex thường (lowercase).
  7. Gửi chữ ký trong field sign cùng với website_key trong 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);
Lưu ý: website_secretnotify_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ỗiNguyên nhânCách fix
WEBSITE_AUTH_FAILEDThiếu website_key hoặc sai keyLấ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 đầuVào app.apinganhang.net → Xoay secret lần đầu
Chữ ký đúng nhưng vẫn lỗiGử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

JSON body mà Hub POST về notify_forward_url sau khi giao dịch hoàn thành:

Payin thành công

{
  "event":      "payment.confirmed",
  "gateway":    "sharkpay",
  "order_id":   "HUB_20260630_xyzabc",
  "merchant_order_no": "ORDER_20260630_001",
  "amount":     100000,
  "currency":   "VND",
  "status":     "confirmed",
  "paid_at":    "2026-06-30T10:15:30+07:00"
}

Payout thành công

{
  "event":      "payout.confirmed",
  "gateway":    "sharkpay",
  "order_id":   "HUB_PAYOUT_20260630_abc",
  "merchant_order_no": "PAYOUT_001",
  "amount":     50000,
  "currency":   "VND",
  "status":     "confirmed",
  "paid_at":    "2026-06-30T10:20:00+07:00"
}

Site đối tác trả về HTTP 200 với body bất kỳ để báo đã nhận. Nếu Hub nhận status khác 2xx, sẽ retry.

Chống trùng & chống bơm số tiền (từ 2026-07-03):
  • Idempotent — mỗi đơn chỉ được cộng tiền và forward webhook 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ộng logs_history và POST webhook về site. Các callback thành công trùng sau đó Hub vẫn ACK 200 cho cổng nhưng không forward lại.
  • Số tiền webhook luôn là số tiền đơn hàng gốc. Trường amount Hub gửi về site lấy từ số tiền đã chốt khi tạo đơn (payment_hub_orders.amount), 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, Hub chỉ cộng & báo đúng số tiền đơn.
  • 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.

sequenceDiagram participant Site as Website đối tác participant Hub as client.apinganhang.net participant EZ as EeziePay Site->>Hub: POST orders/create gateway=eeziepay Hub->>Hub: SHA1 sign, lưu payment_hub_orders Hub-->>Site: form_action + form_fields (fundtransfer.php) Site->>EZ: POST form target=_blank EZ->>Hub: backend_url callback (deposit) Hub->>Hub: verify SHA1, logs_history, Telegram Hub-->>EZ: XML status OK Hub->>Site: forward JSON + X-Payment-Signature

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ênhbank_code (ví dụ)Mô tả
Online bankingVCB.VNVietcombank Internet Banking
Online bankingTCB.VNTechcombank Internet Banking
QR chuyển khoảnVCB.QR.VNVietcombank QR
QR chuyển khoảnMM.QR.VNVí / 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

sequenceDiagram participant Site as Website đối tác participant Hub as client.apinganhang.net participant EZ as EeziePay Site->>Hub: POST payouts/create gateway=eeziepay Hub->>Hub: SHA1 sign v3.0, lưu order Hub->>EZ: POST withdrawal.php EZ-->>Hub: XML response Hub-->>Site: kết quả tạo lệnh EZ->>Hub: notify_url callback (payout) Hub->>Hub: verify, cập nhật order Hub-->>EZ: XML status OK Hub->>Site: forward webhook

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/.

sequenceDiagram participant Site as Website đối tác participant Hub as client.apinganhang.net participant WP as WowPay Site->>Hub: POST orders/create.php gateway=wowpay Hub->>Hub: chuẩn hóa input, amount ×100 → apply_amount, ký MD5 Hub->>WP: POST /api/payin/create/ WP-->>Hub: charge_info / cashier_info (qrcode, deeplink...) Hub-->>Site: pay_url + qr_code WP->>Hub: POST callbacks/wowpay.php (mch_order_no, status, real_amount) Hub->>Hub: verify MD5, tra merchant theo mch_order_no, cập nhật order Hub-->>WP: "OK" Hub->>Site: forward webhook + X-Payment-Signature

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.

Lưu ý quan trọng: callback payin/payout hiện tại của WowPay không gửi 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 APInganhangTrên WowPay / APIGhi chú
Bật cổngBật để cho phép tạo đơn/payout qua gateway=wowpay.
Domain APIHost API WowPayVí 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 IDmch_idID merchant (số) do WowPay cấp.
API Keypayin_secret_key / payout_secret_keyWowPay cho dùng chung 1 key cho cả payin và payout.
Application IDkhông dùng cho WowPayTrườ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 Hubcallback_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 URLreturn_urlOptional — URL chuyển khách (cashier redirect) sau khi thanh toán payin.
IP whitelistIP 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).

Khuyến nghị cho đối tác: luôn truyền 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ộcMap sang API WowPay
merchant_order_nomch_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_codekhi pay_type = bankcard/bankcard_qrbank_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_idkhuyến nghịuser_id (mặc định "guest" nếu bỏ trống)
device_ip / client_iptự độngdevice_ip — Hub tự lấy IP request nếu không truyền
return_urloptionalreturn_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ộcMap sang API WowPay
merchant_order_nomch_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_codepayout_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_numberpayout_account_no
payout_name / account_namepayout_name — tên người nhận
payout_phone_no / phoneoptionalpayout_phone_no
user_id / customer_idkhuyế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).

Lỗi thường gặp: thiếu hẳn field 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_codeTên ngân hàngbank_codeTên ngân hàng
ACBAsia Commercial BankNAMANam A Bank
SACSacombankNCBNational Citizen Bank
TCBTechcombankOCEANOCEAN Bank
VCBVietcombankPVCOMPVcomBank
VTBVietinbankSAIGONSaigonBank
DABDongA BankSEASeABank
BIDVBIDV BankSHBVNShinhan Bank VN
EXIMEximbankVIBVIB Bank
AGBAgribankVRBVietnam-Russia Bank
TPBTienPhong BankVABViet A Bank
MBMBBank (Quân Đội)VDBVietnam Development Bank
VPBVPBankGPBGPBank
OCBOCB (Phương Đông)VIETCAPITALBANKViet Capital Bank
SCBSCB BankPGBANKPGBank
SHBSHB (Sài Gòn Hà Nội)CIMBCIMB Bank
ABBABBankHLBHong Leong Bank
BACABac A BankIVBIndovina Bank
KLBKien Long BankPBVNVID Public Bank
BVBBaoViet BankUOBUOB Bank
HDBHDBankVIETBVietBank
LPBLienVietPostBankWOOWoori Bank
MSBMaritime BankYOLOYOLO (VPDirect)
DEUTDeutsche Bank
MBVModern Bank of Vietnam
VIKKIVikki Digital Bank
TIMOTimo Bank

Hub tự chuẩn hoá (viết hoa, bỏ khoảng trắng, map vài alias tên đầy đủ phổ biến: VIETCOMBANKVCB, MBBANKMB, VIETTINBANKVTB, TPBANKTPB, SEABANKSEA...). 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_typebankcard hoặc bankcard_qr:

{
  "gateway": "wowpay",
  "merchant_order_no": "ORD20260623002",
  "amount": 200000,
  "pay_type": "bankcard_qr",
  "bank_code": "VCB",
  "user_id": "user123"
}
Thiếu bank_code ở request trên sẽ bị WowPay trả 1010 Bank Code Missing. Xem danh sách mã đầy đủ.

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"
}

Cấu hình SharkPay Dashboard

Thiết lập tại app.apinganhang.net/integration/sharkpay (yêu cầu gói VIP).

Trường trên APInganhangTrên SharkPay / APIGhi chú
Bật cổngBật để cho phép tạo đơn/payout qua gateway=sharkpay.
Domain APIHost API SharkPayVí dụ https://p100-gw.vippp.top. Hub tự ghép /api/pay/create_order, /api/pay/query_order, /api/agentpay/apply, /api/agentpay/query_order, /api/agentpay/query_balance, /api/settlement/create_order, /api/settlement/query_order.
Merchant IDmchIdID merchant (số) do SharkPay cấp.
API Key (Payin + Payout)key (tham gia ký MD5)SharkPay cho dùng chung 1 key cho payin, payout (Agent Pay) và Settlement.
Application IDkhông dùng cho SharkPayTrường này chỉ hiển thị chung trên form; không map vào field nào của API SharkPay.
Product IDproductIdBắt buộc khi tạo đơn payin (vd: 8036) — thiếu sẽ bị Hub chặn trước khi gọi SharkPay (VALIDATION_FAILED).
URL callback HubnotifyUrlhttps://client.apinganhang.net/api/v1/payments/callbacks/sharkpay.php — Hub tự gửi field này ở mỗi request tạo đơn/payout/settlement.
Return URLkhông có ở SharkPaySharkPay không hỗ trợ tham số redirect riêng cho payin (khác WowPay/EeziePay).
IP whitelistIP server website đối tác được phép gọi API Hub. Để trống = không giới hạn.
Callback Source IPsIP của SharkPay được phép gọi callback vào Hub. Để trống nếu chưa có IP chính xác từ SharkPay — IP sai/cũ sẽ làm Hub tự 403 mọi callback thật (đã từng xảy ra thật, xem ghi chú dưới).
Lưu ý IP whitelist callback: chữ ký MD5 đã là lớp bảo mật chính cho callback (xác thực mật mã, không phải IP). Chỉ điền Callback Source IPs khi đã xác nhận IP đó từ SharkPay support — điền sai sẽ chặn nhầm toàn bộ callback thật mà không có dấu hiệu rõ ràng (HTTP 403, đối tác báo "không tự xác nhận").

SharkPay Payin API Tóm tắt

Gọi qua Hub: POST /api/v1/payments/orders/create.php với "gateway": "sharkpay".

Field (gửi cho Hub)Bắt buộcMap sang API SharkPay
merchant_order_nomchOrderNo — phải duy nhất
amount (VNĐ)amount = amount × 100 (cent)
subject / title / descriptionoptionalsubject — Hub tự sinh "Pay {mã đơn}" nếu bỏ trống
body / descriptionoptionalbody — Hub tự dùng lại subject nếu bỏ trống
return_urloptionalreturnUrl
device_ip / client_iptự độngclientIp — Hub tự lấy IP request nếu không truyền

Response data từ Hub: gateway_order_id (payOrderId), pay_url (payUrl/codeUrl), qr_code, amount.

Ví dụ

POST /api/v1/payments/orders/create.php
Authorization: Bearer <token>
Content-Type: application/json

{
  "gateway": "sharkpay",
  "merchant_order_no": "ORD20260629001",
  "amount": 100000,
  "subject": "Nap tien tai khoan"
}

SharkPay Payout API Tóm tắt — Agent Pay

Gọi qua Hub: POST /api/v1/payments/payouts/create.php với "gateway": "sharkpay" (mặc định dùng Agent Pay — xem Settlement nếu cần hệ thống rút tiền thứ 2).

Field (gửi cho Hub)Bắt buộcMap sang API SharkPay
merchant_order_nomchOrderNo
amount (VNĐ)amount = amount × 100 (cent)
account_name / payout_nameaccountName — tên người nhận
account_no / bank_number / payout_account_noaccountNo
bank_namebankName — tên ngân hàng dạng chữ thường (vd: "Vietcombank"), không phải mã enum
bank_net_nameoptionalbankNetName — tên chi nhánh
bank_code / payout_bank_codeoptionalbankCode
SharkPay Agent Pay không dùng danh sách bank_code cố định như WowPay — bankName là tên tự do, SharkPay tự nhận diện ngân hàng phía họ.

SharkPay — Settlement Hệ thống rút tiền thứ 2

SharkPay có 2 hệ thống rút tiền độc lập: Agent Pay (/api/agentpay/*, mặc định) và Settlement (/api/settlement/*, balance/field/status khác hẳn). Chọn bằng field payout_method khi gọi POST /api/v1/payments/payouts/create.php.

payout_methodAPI SharkPayKhi dùng
(bỏ trống) hoặc agentpay/api/agentpay/applyMặc định — hành vi cũ, không đổi gì
settlement (hoặc sett)/api/settlement/create_orderKhi cần dùng quỹ Settlement riêng (balance khác Agent Pay)
Khác biệt quan trọng so với Agent Pay:
  • bank_net_name (tên chi nhánh/phòng giao dịch) là bắt buộc cho Settlement (Agent Pay thì optional).
  • Mã đơn platform trả về tên field settOrderId lúc tạo đơn, nhưng lại là settleOrderId lúc query/callback — đúng theo tài liệu gốc SharkPay, không phải lỗi. Hub đã xử lý cả 2 tên field này khi đọc response.
  • Mã status Settlement: 1-chờ duyệt, 2-đã duyệt, 3-từ chối, 4-đang chuyển, 5-thành công, 6-thất bại (khác hẳn Agent Pay: 0-chờ xử lý, 1-đang xử lý, 2-thành công, 3-thất bại).

Ví dụ tạo lệnh Settlement

POST /api/v1/payments/payouts/create.php
Authorization: Bearer <token>
Content-Type: application/json

{
  "gateway": "sharkpay",
  "payout_method": "settlement",
  "merchant_order_no": "SETT20260629001",
  "amount": 300000,
  "account_name": "NGUYEN VAN A",
  "account_no": "0123456789",
  "bank_name": "Vietcombank",
  "bank_net_name": "CN Ha Noi",
  "user_id": "user123"
}

Tra cứu lại lệnh Settlement (truyền lại đúng payout_method=settlement, không cần biết settleOrderId — Hub tự tra theo merchant_order_no đã lưu):

POST /api/v1/payments/payouts/query.php
Authorization: Bearer <token>
Content-Type: application/json

{
  "gateway": "sharkpay",
  "payout_method": "settlement",
  "merchant_order_no": "SETT20260629001"
}

So sánh cổng

SharkPayWowPayEeziePay
PayinJSON/form APIJSON APIForm → fundtransfer.php
SignMD5 uppercaseMD5 uppercaseSHA1 uppercase
Callback acktext successtext successXML <status>OK</status>
Balance1 số dưFund Transfer + Fund Out
Amount VNDfen (×100)cent (×100)integer, không lẻ

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 APInganhangTrên EeziePay / APIGhi chú
Bật cổngBật để cho phép tạo đơn/payout qua gateway=eeziepay.
Domain APIGateway base URLURL 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 APIEndpoint pathsCopy từ merchant panel: fundtransfer.php, fundtransfer_enquiry.php, withdrawal.php, withdrawal_enquiry.php, querybalance.php.
Merchant IDpartner_codeMã đối tác / merchant trên EeziePay.
Encryption KeyEncryption / signing keyDùng chung cho payin + payout. Ký SHA1 uppercase theo thứ tự field trong tài liệu EeziePay.
URL callback Hubbackend_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 URLredirect_urlURL chuyển khách về sau khi thanh toán (có thể ghi đè khi tạo đơn).
IP whitelistIP 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 / secretSau 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ị)

  1. Lấy Domain API, Merchant ID, Encryption Key5 đường dẫn API từ merchant EeziePay.
  2. Điền các trường trên vào tab EeziePay, bật cổng, nhấn Lưu.
  3. 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).
  4. Nhấn Kiểm tra kết nối — gọi balance inquiry qua Hub (endpoint cấu hình querybalance.php hoặc tương đương).
  5. Nhấn Cập nhật số dư — xem Fund Transfer (nạp) và Fund Out (chi hộ).
  6. Thêm Website Integration phía dưới nếu nhiều site; mỗi site có website_key + website_secret riê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ợ VNDIDR.

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>

Tham khảo