Apinganhang API v1

REST API xác thực giao dịch ngân hàng, quản lý tài khoản, kết nối OTP, và tích hợp cổng thanh toán tự động.

Thuộc tínhGiá trị
Base URLhttps://client.apinganhang.net/api/v1
Content-Typeapplication/json
AuthAuthorization: Bearer <token>
EncodingUTF-8
Health check: GET /api/v1/ping.php — không cần token, trả {"ok":true}

Xác thực

Tất cả endpoint (trừ ping.php) yêu cầu header Authorization: Bearer <token>.

Token nhận được từ endpoint POST /auth/login.php. Token không có thời hạn hết hạn — cookie được duy trì lâu dài trừ khi user đăng xuất hoặc admin reset token.

401 Unauthorized: Khi token sai hoặc không tồn tại, API trả HTTP 401. Client nên redirect về trang login.

Mã lỗi & Response format

Mọi response đều là JSON với field success (boolean).

HTTPÝ nghĩaVí dụ
200Thành công{"success":true,"data":{...}}
400Bad request / login bank thất bại{"success":false,"message":"..."}
401Chưa đăng nhập / token không hợp lệ
403Gói API hết hạn
404Không tìm thấy
405Method không hỗ trợ
422Thiếu / sai field
500Lỗi server

Rate Limit

Chưa áp dụng rate limiting cứng. Khuyến nghị polling giao dịch tối đa mỗi 10–30 giây. Bank cron cập nhật mỗi 1 phút.

Số dư ngân hàng — GET /accounts/balances.php

Endpoint gọn dành cho đối tác (site cá cược, cổng nạp...) lấy nhanh số dư các tài khoản ngân hàng của mình, phục vụ việc tự chọn ngân hàng công ty nhận tiền — ví dụ: luôn ưu tiên ngân hàng đang có số dư thấp nhất để dàn đều dòng tiền.

Khác gì accounts/index.php? index.php là endpoint của dashboard: trả rất nhiều field và có thể gọi live balance sang API ngân hàng (chậm, phụ thuộc ngân hàng). balances.php chỉ đọc số dư đã đồng bộ trong DB (cron poll ngân hàng chạy mỗi 1 phút) nên trả lời nhanh và ổn định — phù hợp gọi ngay lúc member bấm nạp tiền.

Xác thực

Bearer token như mọi endpoint /api/v1 khác: Authorization: Bearer <token>. Không có token → HTTP 401.

Query params (tất cả tuỳ chọn)

Tham sốMặc địnhÝ nghĩa
banks—Lọc theo mã ngân hàng, phân tách bằng dấu phẩy. Chấp nhận alias (VCB, MB, VIETINBANK...). VD: banks=ACB,BIDV
accounts—Lọc chính xác theo cặp BANK:SỐ_TK, phân tách bằng dấu phẩy. VD: accounts=ACB:68868983,BIDV:96247TPH8866. Cũng chấp nhận chỉ số tài khoản: accounts=68868983. So khớp bỏ qua khoảng trắng/gạch nối.
active_only1Chỉ lấy tài khoản đang bật và không bị need_relogin. Đặt 0 để lấy hết.
include_crypto01 = lấy cả ví TRON USDT / BEP20 USDT / BINANCE / BTC / ETH.
sortbalance_ascbalance_asc | balance_desc | none
pick—lowest = trả thêm data.selected là tài khoản có số dư thấp nhất. Nếu nhiều tài khoản bằng nhau thì chọn ngẫu nhiên trong nhóm thấp nhất.

Ví dụ

curl -H "Authorization: Bearer $TOKEN" \
  "https://client.apinganhang.net/api/v1/accounts/balances.php?accounts=ACB:68868983,ACB:22769257,BIDV:96247TPH8866&pick=lowest"
{
  "success": true,
  "message": "Balances loaded",
  "data": {
    "items": [
      {
        "id": 80,
        "source_table": "account_acb",
        "bank_code": "ACB",
        "account_number": "68868983",
        "holder_name": "TUNG VU THANH",
        "active": true,
        "connected": true,
        "need_relogin": false,
        "last_error": "",
        "sync_source": "direct",
        "balance": 31321,
        "balance_source": "last_transaction",
        "transaction_count": 223,
        "last_transaction_at": 1787032562
      }
    ],
    "count": 3,
    "selected": { "bank_code": "ACB", "account_number": "68868983", "balance": 31321 },
    "generated_at": 1787000000
  }
}

Ý nghĩa balance_source

Giá trịÝ nghĩa
last_transactionSố dư thật do ngân hàng trả về ở giao dịch mới nhất (balance_after). Áp dụng cho tài khoản sync_source = direct (cron poll thẳng ngân hàng).
calculatedSố dư tính = tổng tiền vào − tổng tiền ra. Áp dụng cho tài khoản sync_source = webhook (SePay/Casso — không có snapshot số dư), hoặc tài khoản chưa từng có snapshot.

Use case: chọn ngân hàng công ty có số dư thấp nhất

  1. Site lấy danh sách ngân hàng công ty đang mở trong admin của mình.
  2. Gọi balances.php?accounts=<danh sách BANK:STK>&pick=lowest.
  3. Dùng data.selected làm ngân hàng nhận tiền cho lệnh nạp; nếu API lỗi/timeout thì fallback chọn ngẫu nhiên như cũ.
  4. Nên cache kết quả 30–60 giây phía site — cron ngân hàng cũng chỉ cập nhật mỗi 1 phút.
Lưu ý: tài khoản chưa phát sinh giao dịch nào sẽ có balance = 0 và transaction_count = 0. Nếu không muốn nó luôn được chọn làm "thấp nhất", hãy lọc bằng accounts= đúng các STK đang thực sự dùng để nhận tiền.

Payment Hub — Hướng dẫn đối tác

Dùng chung cho đối tác kết nối nạp/chi qua Payment Hub. Tài liệu không chứa tài khoản, key thật hay cấu hình của đơn vị khác.

Thông tin cần được cấp

  • API base: https://client.apinganhang.net/api/v1/payments
  • Bearer token của tài khoản Hub riêng của đối tác.
  • website_key, website_secret cho website đăng ký.
  • URL nhận webhook HTTPS và notify_forward_secret tương ứng.
  • Cổng được bật, merchant được phép dùng, hạn mức và IP máy chủ đối tác được phép chi.
Bảo mật: Không dùng tài khoản/key của đối tác khác. Merchant key Anpay và mật khẩu quỹ do Hub quản lý, không gửi xuống trình duyệt. website_secret và Bearer token chỉ lưu phía backend.

API

Nghiệp vụĐường dẫn (sau API base)
Tạo nạpPOST /orders/create.php
Tra cứu nạpPOST /orders/query.php
Tạo chiPOST /payouts/create.php
Tra cứu chiPOST /payouts/query.php
Số dưPOST /balance.php

Gửi POST JSON với Content-Type: application/json và Authorization: Bearer <TOKEN_DOI_TAC>. Các cổng hiện có: anpay, 1dpay, minipay, sharkpay, wowpay, eeziepay — chỉ dùng cổng đã được cấu hình và bật cho tài khoản đó.

Payment Hub — Ký request

  1. Thêm website_key và timestamp (Unix giây, lệch đồng hồ tối đa 300 giây) trước khi ký.
  2. Loại các field sign, website_secret, website_secret_plain, website_secret_runtime, secret; bỏ null, chuỗi rỗng và array/object.
  3. Trim tên/giá trị, sắp xếp tên field theo thứ tự chuỗi, nối key=value bằng |.
  4. Ký HMAC-SHA256 bằng website_secret, xuất hex chữ thường. Không URL-encode chuỗi ký.
  5. Gửi chữ ký trong field sign; không gửi secret.

Ví dụ PHP

function hubSign(array $input, string $secret): string {
    $skip = ['sign','website_secret','website_secret_plain','website_secret_runtime','secret'];
    $pairs = [];
    foreach ($input as $k => $v) {
        $k = trim((string)$k);
        if ($k === '' || in_array(strtolower($k), $skip, true) || !is_scalar($v)) continue;
        $v = trim((string)$v);
        if ($v !== '') $pairs[$k] = $v;
    }
    ksort($pairs, SORT_STRING);
    $parts = [];
    foreach ($pairs as $k => $v) $parts[] = $k . '=' . $v;
    return hash_hmac('sha256', implode('|', $parts), $secret);
}

$body = [
    'website_key'       => getenv('HUB_WEBSITE_KEY'),
    'timestamp'         => time(),
    'gateway'           => 'anpay',
    'merchant_order_no' => 'PARTNER_DEP_20261012_0001',
    'amount'            => 100000,
    'currency'          => 'VND',
    'member_id'         => 'customer_001',
    'anpay_pay_type'    => 7,
    'return_url'        => 'https://partner.example/payment/result',
];
$body['sign'] = hubSign($body, getenv('HUB_WEBSITE_SECRET'));
// POST $body tới /orders/create.php từ backend, kèm Bearer token.
Số tiền là VND nguyên — không tính bằng nghìn, không nhân 100. Mỗi đơn dùng một mã duy nhất; lưu mã, loại nạp/chi, cổng, khách hàng và số tiền trước khi gọi Hub.

Payment Hub — Anpay: nạp

gateway=anpay; anpay_pay_type:

Giá trịKênh
7QR ngân hàng (mặc định)
9Chuyển khoản
6MoMo
5ZaloPay
4Viettel Money
Các kênh ví hiện tại trả thông tin chuyển vào ngân hàng, không mặc định hiểu là liên kết trực tiếp ví khách hàng.

Khi response success=true, đọc data: merchant_order_no, gateway_order_id, amount, pay_url, account_number, account_name, bank_code, transfer_content, qr_content, qr_image_base64. Hiển thị đúng QR/STK/nội dung của đơn vừa tạo, không tái sử dụng đơn cũ. Có thể bỏ bank_code để cổng tự chọn ngân hàng.

Hạn mức phụ thuộc merchant/kênh được cấp; không lấy hạn mức của merchant khác làm mặc định.

return_url chỉ để điều hướng, không chứng minh khách đã trả tiền.

Payment Hub — Anpay: chi

Payload tạo chi gồm các field xác thực ở trên + gateway=anpay, merchant_order_no, amount, currency=VND, bank_code (BIN ngân hàng), account_number, account_name, member_id.

  • Hub chặn Anpay ngoài khoảng 100.000 – 200.000.000 VND; merchant hoặc hạn mức riêng có thể chặt hơn.
  • IP backend gọi Hub phải được khai whitelist chi.
Response tạo chi thành công chỉ là đã nhận lệnh, chưa phải đã chuyển tiền. Timeout hoặc 5xx = kết quả chưa rõ: giữ đơn để tra cứu cùng mã, không tạo mã mới để chi lại và không tự hoàn tiền.

Payment Hub — Tra cứu & kết quả cuối

Tra cứu bằng gateway, merchant_order_no cùng thông tin xác thực. Với Anpay, dùng trạng thái chuẩn hoá data.state: success | processing | failed.

Loạigateway_status
Nạp1 thành công · 2 vẫn processing
Chi1 thành công · 2 thất bại · 3 processing
success=true của response tra cứu chỉ nói API gọi thành công, không phải giao dịch thành công.
  • Chỉ cập nhật tiền sau khi kiểm tra: đơn tồn tại, đúng cổng, đúng loại, đúng số tiền và trạng thái cuối.
  • HTTP 409 với AMOUNT_REVIEW/manual_review: giữ đối soát thủ công, không chi lại hoặc tự cộng/hoàn.
  • Poll có backoff, không gọi dồn mỗi vài giây; gặp giới hạn tần suất thì giãn thời gian.

Payment Hub — Nhận webhook

Hub POST JSON với header X-Payment-Signature: sha256=<hex>. Xác thực bằng HMAC-SHA256 trên nguyên raw body với notify_forward_secret — KHÔNG decode/encode lại rồi ký, KHÔNG dùng website_secret.

$raw      = file_get_contents('php://input');
$received = $_SERVER['HTTP_X_PAYMENT_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $raw, getenv('HUB_NOTIFY_SECRET'));
if (!hash_equals($expected, $received)) {
    http_response_code(403); exit;
}
$event = json_decode($raw, true);
// Lưu bền vững vào inbox/queue trước khi ACK 2xx.
// Worker kiểm tra đơn và xử lý tiền idempotent trong transaction DB.

Envelope có event=payment.anpay.callback, gateway, timestamp, data. Event này dùng cho cả nạp và chi — xác định loại đơn từ dữ liệu đã lưu, không suy ra từ tên event. Không coi mọi webhook là thành công.

Nạp được định tuyến theo website tạo đơn. Riêng tạo chi hiện lưu website_id=0 và có đường fallback callback về cấu hình cấp gateway — phải xác nhận URL/secret chi riêng cho tài khoản đối tác và kiểm chứng định tuyến trước khi bật chi. Không mặc định webhook chi dùng cùng secret với nạp.
Hub hiện chưa tự retry webhook. Đối tác phải có tác vụ tra cứu đơn treo, không phụ thuộc duy nhất callback. Phía đối tác vẫn phải có unique constraint/khoá transaction để mỗi đơn chỉ cộng/hoàn một lần.

Payment Hub — Nghiệm thu trước khi bật thật

  • Ký đúng/sai; timestamp cũ; IP chi ngoài whitelist bị từ chối.
  • Nạp thử có phê duyệt: tạo QR, nhận kết quả thật, đúng số tiền, chỉ cộng một lần.
  • Webhook lặp/sai chữ ký, dịch vụ nhận tạm ngừng: không cộng sai, đối soát phục hồi được.
  • Chi thử có phê duyệt: định tuyến URL/secret đúng, xử lý thành công/thất bại/timeout không chi hoặc hoàn lặp.
  • Token/key không xuất hiện ở frontend hoặc log; từng đối tác có tài khoản và quyền riêng.
Tài liệu này không tự cấp quyền merchant hoặc bật cổng. Chi tiết các cổng khác (1DPay, Minipay, SharkPay, WowPay, Eeziepay) xem payment-hub-docs.html — lưu ý bản đó có chỗ cũ (ví dụ thiếu timestamp, ví dụ gửi website_secret); ưu tiên quy tắc ký ở trang này.

USDT Crypto — Tổng quan

Hệ thống hỗ trợ nhận tiền tự động qua 2 mạng USDT: TRC20 (Tron) và BEP20 (BSC). Cron job chạy mỗi 1 phút để quét giao dịch mới, quy đổi sang VND và ghi vào logs_history.

Tỷ giá USDT/VND — Binance P2P

Tỷ giá được lấy tự động từ Binance P2P API — không cần cấu hình thủ công:

  1. Gọi API P2P Binance, lấy top 10 merchant đang đăng bán USDT nhận VND (SELL order, amount ≥ 10,000,000 VND).
  2. Tính trung bình cộng các mức giá (chỉ lấy mức ≥ 20,000 VND/USDT để loại outlier).
  3. Kết quả làm tròn xuống (floor) → ví dụ: 25,740 VND/USDT.
  4. Cache 5 phút — tự refresh mỗi lần cache hết hạn.
  5. Fallback 25,000 VND/USDT nếu Binance không phản hồi.
Lưu ý: Tỷ giá này được dùng chung cho cả TRON USDT và BEP20 USDT. Giao dịch được lưu amount (VND) và usdt_amount (USDT thực nhận) song song.

Luồng tổng quát

  1. User thêm địa chỉ ví USDT vào hệ thống tại app.apinganhang.net → Tài khoản → Thêm ví USDT.
  2. Cron job chạy mỗi 1 phút, gọi API blockchain để lấy giao dịch 14 ngày gần nhất.
  3. Lọc chỉ giao dịch vào ví (to === địa_chỉ_ví), bỏ qua giao dịch ra.
  4. Dedup theo tx_hash + method + ABS(amount VND) — mỗi giao dịch chỉ ghi 1 lần.
  5. Quy đổi USDT → VND theo tỷ giá Binance P2P hiện tại, ghi vào logs_history.
  6. Gửi thông báo Telegram + dispatch webhook transaction.received về site.

USDT TRC20 — Tron Network

Thuộc tínhGiá trị
MạngTron (TRC20)
method trong logs_historyTRON USDT
Smart contractTR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
API nguồnTronGrid (api.trongrid.io/v1/accounts/{address}/transactions/trc20)
Cửa sổ quét200 tx gần nhất, tối đa 14 ngày
Cron intervalMỗi 1 phút
Định dạng địa chỉBắt đầu bằng T, 34 ký tự (base58)

Cấu hình TronGrid API Key

TronGrid miễn phí nhưng giới hạn rate nếu không có API key. Khi thiếu key, cron sẽ gặp lỗi "Không lấy được lịch sử từ TronGrid".

  1. Đăng ký tại trongrid.io → lấy API key miễn phí.
  2. Vào app.apinganhang.net → Cài đặt → nhập TronGrid API Key.
  3. Hệ thống tự thêm header TRON-PRO-API-KEY: <key> vào mọi request TronGrid.

Thêm ví USDT Tron

Gọi API POST /accounts/store.php (hoặc dùng giao diện app) với:

{
  "bank_code": "TRON USDT",
  "account_number": "THa1vvKpShrkGNo2XjZsDVKzQdHwSMjfCp",
  "account_name": "Ví USDT Tron chính"
}

Response giao dịch USDT Tron (trong logs_history)

{
  "id": 1234,
  "bank":        "TRON USDT",
  "trans_id":    "abc123def456...",
  "amount":      2574000,
  "usdt_amount": 100.0,
  "type":        "in",
  "description": "Nhận 100 USDT (2,574,000 VND) từ TXabc...",
  "account":     "THa1vvKpShrkGNo2XjZsDVKzQdHwSMjfCp",
  "transaction_time": 1751234567,
  "status":      "SUCCESS"
}
trans_id = Transaction Hash trên blockchain Tron (64 ký tự hex). Có thể tra cứu tại tronscan.org.

USDT BEP20 — Binance Smart Chain

Thuộc tínhGiá trị
MạngBSC (BEP20)
method trong logs_historyBEP20 USDT
Smart contract0x55d398326f99059ff775485246999027b3197955
API nguồnBscScan / Etherscan v2 (api.etherscan.io/v2/api?chainid=56)
Cửa sổ quét100 tx gần nhất, tối đa 14 ngày
Cron intervalMỗi 1 phút
Định dạng địa chỉBắt đầu bằng 0x, 42 ký tự (EVM-compatible)

Cấu hình BscScan API Key (bắt buộc)

BEP20 bắt buộc phải có BscScan API key — không có key sẽ không lấy được giao dịch.

  1. Đăng ký tại bscscan.com/myapikey → tạo API key miễn phí.
  2. Khi thêm ví BEP20 tại app.apinganhang.net, nhập API key vào trường Password / API Key.
  3. API key được mã hoá AES-256-GCM trước khi lưu DB.

Thêm ví USDT BEP20

{
  "bank_code":      "BEP20 USDT",
  "account_number": "0xAbCd1234...",
  "account_name":   "Ví USDT BEP20 chính",
  "password":       "<BscScan API Key>"
}

Response giao dịch USDT BEP20 (trong logs_history)

{
  "id": 5678,
  "bank":        "BEP20 USDT",
  "trans_id":    "0xabc123...",
  "amount":      2574000,
  "usdt_amount": 100.0,
  "type":        "in",
  "description": "Nhận 100 USDT (2,574,000 VND) từ 0xsender...",
  "account":     "0xAbCd1234...",
  "transaction_time": 1751234567,
  "status":      "SUCCESS"
}
trans_id = Transaction Hash trên BSC. Tra cứu tại bscscan.com.

Webhook — Giao dịch USDT

Khi cron phát hiện giao dịch USDT mới hợp lệ, hệ thống dispatch event transaction.received về webhook URL đã cấu hình. Payload tương tự giao dịch ngân hàng nhưng bổ sung field usdt_amount:

FieldTypeMô tả
eventstring"transaction.received"
bankstring"TRON USDT" hoặc "BEP20 USDT"
trans_idstringTransaction hash (tx_hash) trên blockchain
amountintegerSố tiền VND (đã quy đổi theo tỷ giá Binance P2P)
usdt_amountfloatSố USDT thực tế nhận được (ví dụ: 100.5)
typestring"in" — chỉ nhận giao dịch vào ví
descriptionstringMô tả: "Nhận 100 USDT (2,574,000 VND) từ 0xabc..."
accountstringĐịa chỉ ví nhận (của mình)
balance_afternullLuôn null với USDT (không query số dư sau GD)

Ví dụ payload webhook USDT Tron

{
  "event":        "transaction.received",
  "bank":         "TRON USDT",
  "trans_id":     "f3a4b2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5",
  "amount":       2574000,
  "usdt_amount":  100.0,
  "type":         "in",
  "description":  "Nhận 100 USDT (2,574,000 VND) từ TXsenderAddress...",
  "account":      "THa1vvKpShrkGNo2XjZsDVKzQdHwSMjfCp",
  "balance_after": null
}

Xác minh thanh toán USDT

Luồng xác minh cho site nhận USDT — so sánh usdt_amount (không phải amount VND, vì tỷ giá biến động):

  1. Tạo đơn, hiển thị địa chỉ ví USDT + số USDT cần chuyển (ví dụ: 100 USDT).
  2. Khách gửi đúng số USDT đến địa chỉ ví trên Tron/BSC.
  3. Webhook nhận event transaction.received, kiểm tra usdt_amount === 100 và bank === "TRON USDT".
  4. Hoặc polling: GET /transactions/index.php?bank=TRON+USDT&limit=10, tìm usdt_amount khớp.
Khuyến nghị: So sánh theo usdt_amount (dung sai ±0.01 USDT) thay vì amount VND, vì tỷ giá thay đổi giữa lúc tạo đơn và lúc khách chuyển tiền.

BTC / ETH — Tổng quan

Ngoài USDT (TRC20/BEP20), hệ thống hỗ trợ nhận tiền tự động qua 2 đồng coin gốc (native coin): Bitcoin (BTC) và Ethereum (ETH). Cron job chạy mỗi 1 phút để quét giao dịch mới, quy đổi sang VND và ghi vào logs_history — cùng cơ chế với USDT/ngân hàng.

Tỷ giá BTC/USDT, ETH/USDT

Lấy trực tiếp từ Binance Spot API (GET /api/v3/ticker/price), cache 60 giây. Sau đó quy đổi USDT → VND theo tỷ giá Binance P2P hiện tại (giống USDT TRC20/BEP20).

Luồng tổng quát

  1. User thêm ví BTC/ETH tại app.apinganhang.net → Tài khoản → Thêm tài khoản.
  2. Cron job chạy mỗi 1 phút, gọi API blockchain lấy giao dịch tối đa 14 ngày gần nhất.
  3. Lọc chỉ giao dịch vào ví (nhận tiền), bỏ qua giao dịch ra.
  4. Dedup theo trans_id + method + ABS(amount VND) — mỗi giao dịch chỉ ghi 1 lần.
  5. Quy đổi ra VND, ghi logs_history, gửi Telegram + dispatch webhook transaction.received.

Bitcoin (BTC)

Thuộc tínhGiá trị
MạngBitcoin mainnet
method trong logs_historyBTC
API nguồnBlockstream Esplora API (miễn phí, không cần API key)
Cửa sổ quét50 tx gần nhất, tối đa 14 ngày
Cron intervalMỗi 1 phút
Định dạng địa chỉBắt đầu bằng 1, 3 (Base58Check) hoặc bc1 (Bech32/SegWit)
Không cần API key. Blockstream miễn phí, không cần cấu hình gì thêm ngoài địa chỉ ví.

Thêm ví BTC

Gọi API POST /accounts/store.php (hoặc dùng giao diện app) với:

{
  "bank_code": "BTC",
  "account_number": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "account_name": "Ví BTC chính"
}

Chỉ cần địa chỉ ví công khai — không cần private key hay API key, hệ thống chỉ theo dõi giao dịch nhận (không thể và không cần quyền chuyển tiền đi).

Response giao dịch BTC (trong logs_history)

{
  "id": 9001,
  "bank":        "BTC",
  "trans_id":    "6d292792a6b3d1078bd6edcc15e30a5f9d123198db1f736ebb1c003948b20f8",
  "amount":      167990,
  "type":        "in",
  "description": "Nhận 0.0001 BTC (~6.51 USDT / 167,990 VND)",
  "account":     "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "transaction_time": 1786304133,
  "status":      "SUCCESS"
}
trans_id = Transaction Hash (txid) trên blockchain Bitcoin. Tra cứu tại blockstream.info.

Ethereum (ETH)

Thuộc tínhGiá trị
MạngEthereum mainnet
method trong logs_historyETH
API nguồnEtherscan API v2 (api.etherscan.io/v2/api?chainid=1)
Cửa sổ quét100 tx gần nhất, tối đa 14 ngày
Cron intervalMỗi 1 phút
Định dạng địa chỉBắt đầu bằng 0x, 42 ký tự (EVM-compatible)

Cấu hình Etherscan API Key (bắt buộc)

ETH bắt buộc phải có Etherscan API key — không có key sẽ trả lỗi "Thiếu Etherscan API key" và không lấy được giao dịch.

  1. Đăng ký tại etherscan.io/myapikey → tạo API key miễn phí.
  2. Khi thêm ví ETH tại app.apinganhang.net, nhập API key vào trường Password / API Key.
  3. API key được mã hoá AES-256-GCM trước khi lưu DB (giống BEP20/BSC).

Thêm ví ETH

{
  "bank_code":      "ETH",
  "account_number": "0xAbCd1234...",
  "account_name":   "Ví ETH chính",
  "password":       "<Etherscan API Key>"
}

Response giao dịch ETH (trong logs_history)

{
  "id": 9002,
  "bank":        "ETH",
  "trans_id":    "0xabc123...",
  "amount":      2574000,
  "type":        "in",
  "description": "Nhận 0.052 ETH (~100 USDT / 2,574,000 VND)",
  "account":     "0xAbCd1234...",
  "transaction_time": 1751234567,
  "status":      "SUCCESS"
}
trans_id = Transaction Hash trên Ethereum. Tra cứu tại etherscan.io.

Webhook — Giao dịch BTC/ETH

Khi cron phát hiện giao dịch BTC/ETH mới hợp lệ, hệ thống dispatch event transaction.received về webhook URL đã cấu hình — cùng cơ chế với USDT/ngân hàng.

FieldTypeMô tả
eventstring"transaction.received"
bankstring"BTC" hoặc "ETH"
trans_idstringTransaction hash trên blockchain tương ứng
amountintegerSố tiền VND (đã quy đổi qua USDT theo tỷ giá Binance P2P)
btc_amount / eth_amountfloatSố BTC/ETH thực nhận (chỉ có ở giao dịch tương ứng)
typestring"in" — chỉ nhận giao dịch vào ví
accountstringĐịa chỉ ví nhận (của mình)
balance_afternullLuôn null (không query số dư sau GD)

Xác minh thanh toán BTC/ETH

  1. Tạo đơn, hiển thị địa chỉ ví BTC/ETH + số tiền VND cần thanh toán.
  2. Khách gửi BTC/ETH đến đúng địa chỉ ví trên đúng mạng (Bitcoin mainnet / Ethereum mainnet).
  3. Webhook nhận event transaction.received, kiểm tra bank === "BTC" hoặc "ETH" + amount.
  4. Hoặc polling: GET /transactions/index.php?bank=BTC&limit=10 (tương tự cho ETH).
Khuyến nghị: Do BTC/ETH biến động giá liên tục, nên chấp nhận dung sai ±2–3% so với số tiền VND yêu cầu, hoặc yêu cầu khách xác nhận số coin đã gửi qua UI trước khi đối soát.

Use Case: Xác minh thanh toán tự động

Luồng xác minh giao dịch cho website bán hàng / SaaS / game topup.

  1. Tạo đơn hàng trên website với order_code duy nhất + số tiền.
  2. Hiển thị QR / thông tin CK — yêu cầu khách ghi order_code vào nội dung.
  3. Polling API mỗi 10-30s: GET /transactions/index.php?search={order_code}&type=INCOME&limit=5
  4. Khớp giao dịch: so amount + description chứa order_code + type=in
  5. Cập nhật đơn paid khi tìm thấy.

Use Case: Webhook Callback

Nhận push notification thay vì polling. Server gửi callback khi có giao dịch mới.

Payload mẫu

FieldTypeMô tả
eventstring"transaction.confirmed"
order_codestringMã đơn hàng
amountintegerSố tiền
bankstringNgân hàng
trans_idstringMã GD ngân hàng
signstringHMAC-SHA256 chữ ký
Bảo mật: Luôn verify sign = hmac_sha256(secret, order_code|amount|trans_id|paid_at) trước khi xử lý.

Use Case: OTP Flow — Kết nối BIDV trong app

  1. User nhập login_id + password + account_number BIDV SmartBanking.
  2. Gọi Step 1: POST /accounts/connect.php với action: "request_otp".
  3. Hệ thống login BIDV, BIDV gửi SMS OTP đến SĐT user.
  4. User nhập OTP vào ô trên app.
  5. Gọi Step 2: POST /accounts/connect.php với action: "verify_otp" + otp: "123456".
  6. Nếu đúng, tài khoản được lưu với session đã xác thực, cron tự động đồng bộ giao dịch.

Demo trực tiếp

Test API ngay từ trình duyệt.

Lấy thông tin tài khoản + token hiện tại.

* Giữ nguyên login_id/password/account từ Step 1

Lấy cấu hình site (logo, title, contact).

// Kết quả sẽ hiện ở đây...

Base URL

https://client.apinganhang.net/api/v1

Auth Header

Authorization: Bearer eyJhbGci...

Login

curl -X POST https://client.apinganhang.net/api/v1/auth/login.php \
  -H "Content-Type: application/json" \
  -d '{"username":"demo","password":"123456"}'

200 Response:

{
  "success": true,
  "token": "eyJhbGci...",
  "user": {
    "id": 5,
    "username": "demo",
    "email": "[email protected]",
    "money": 150000,
    "time_momo": 1788998400
  }
}

Profile

curl https://client.apinganhang.net/api/v1/auth/profile.php \
  -H "Authorization: Bearer <token>"

200 Response:

{
  "success": true,
  "data": {
    "id": 5,
    "username": "demo",
    "email": "[email protected]",
    "money": 150000,
    "time_momo": 1788998400,
    "token": "eyJhbGci...",
    "id_telegram": 123456789
  }
}

List Accounts

curl "https://client.apinganhang.net/api/v1/accounts/index.php?bank=MBBANK" \
  -H "Authorization: Bearer <token>"

200 Response:

{
  "success": true,
  "data": [
    {
      "id": 268,
      "bank_code": "MBBANK",
      "account_number": "0368492618",
      "holder_name": "NGUYEN VAN A",
      "balance": 19437345,
      "active": 1
    }
  ]
}

Connect OTP — Step 1

curl -X POST https://client.apinganhang.net/api/v1/accounts/connect.php \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "request_otp",
    "bank_code": "BIDV",
    "login_id": "bidv_user",
    "password": "bidv_pass",
    "account_number": "8877172056"
  }'

200

{
  "success": true,
  "step": "otp_required",
  "message": "Mã OTP đã được gửi đến SĐT"
}

Connect OTP — Step 2

curl -X POST https://client.apinganhang.net/api/v1/accounts/connect.php \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "verify_otp",
    "bank_code": "BIDV",
    "login_id": "bidv_user",
    "password": "bidv_pass",
    "account_number": "8877172056",
    "otp": "123456"
  }'

200

{
  "success": true,
  "step": "done",
  "message": "Xác thực OTP thành công",
  "data": { "id": 68, "bank_code": "BIDV" }
}

Transactions

# 20 giao dịch mới nhất
curl "https://client.apinganhang.net/api/v1/transactions/index.php?limit=20" \
  -H "Authorization: Bearer <token>"

# Lọc theo bank + ngày
curl "https://client.apinganhang.net/api/v1/transactions/index.php?\
bank=MBBANK&date_from=2026-04-01&date_to=2026-04-16" \
  -H "Authorization: Bearer <token>"

# Tìm kiếm
curl "https://client.apinganhang.net/api/v1/transactions/index.php?\
search=INV2026001&type=INCOME" \
  -H "Authorization: Bearer <token>"

200

{
  "success": true,
  "data": [
    {
      "id": 25533,
      "amount": 1000000,
      "bank": "MBBANK",
      "ref_no": "FT26105370000088",
      "description": "NGUYEN VAN A CK",
      "type": "in",
      "account": "0368492618",
      "balance_after": 19437345,
      "transaction_time": "15/04/2026 09:30:00",
      "created_at": 1776395400
    }
  ],
  "pagination": {
    "page": 1, "limit": 20,
    "total": 150, "total_pages": 8
  },
  "totals": {
    "total_in": 5000000,
    "total_out": 2000000,
    "net": 3000000
  }
}

Xác minh thanh toán (PHP)

<?php
$token = 'YOUR_TOKEN';
$base  = 'https://client.apinganhang.net/api/v1';
$order = 'INV20260416001';
$expect = 500000;

$url = "$base/transactions/index.php?" .
  http_build_query([
    'search' => $order,
    'type'   => 'INCOME',
    'limit'  => 10,
  ]);

$ch = curl_init($url);
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer $token",
  ],
  CURLOPT_TIMEOUT => 15,
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);

foreach ($res['data'] ?? [] as $txn) {
  if (
    abs($txn['amount']) === $expect &&
    stripos($txn['description'], $order) !== false
  ) {
    echo "Paid! ref={$txn['ref_no']}\n";
    break;
  }
}
?>

Xác minh thanh toán (Node.js)

const axios = require('axios');
const TOKEN = 'YOUR_TOKEN';
const BASE = 'https://client.apinganhang.net/api/v1';

async function verify(order, amount, bank) {
  const { data } = await axios.get(
    `${BASE}/transactions/index.php`,
    {
      params: { search: order, type: 'INCOME', limit: 10, bank },
      headers: { Authorization: `Bearer ${TOKEN}` },
    }
  );
  return (data.data || []).find(t =>
    Math.abs(t.amount) === amount &&
    (t.description || '').toLowerCase()
      .includes(order.toLowerCase())
  );
}

verify('INV20260416001', 500000, 'MBBANK')
  .then(m => console.log(m ? 'Paid' : 'Pending'));

Webhook Callback Payload

POST https://your-site.com/payment/callback
Content-Type: application/json

{
  "event": "transaction.confirmed",
  "order_code": "INV20260416001",
  "amount": 500000,
  "bank": "MBBANK",
  "trans_id": "FT26105370000088",
  "account": "0368492618",
  "paid_at": 1776395400,
  "sign": "hmac_sha256(secret, ...)"
}

Verify Webhook Signature (PHP)

<?php
$secret = 'YOUR_SECRET';
$body = json_decode(
  file_get_contents('php://input'), true
);
$expected = hash_hmac('sha256',
  implode('|', [
    $body['order_code'],
    $body['amount'],
    $body['trans_id'],
    $body['paid_at'],
  ]),
  $secret
);
if (!hash_equals($expected, $body['sign'])) {
  http_response_code(403);
  die('Invalid signature');
}
echo json_encode(['received' => true]);
?>

Site Settings

curl https://client.apinganhang.net/api/v1/services/site-settings.php \
  -H "Authorization: Bearer <token>"

200

{
  "success": true,
  "data": {
    "title": "API Ngân hàng",
    "description": "Hệ thống API ngân hàng...",
    "logo": "https://client.apinganhang.net/public/assets/img/logo.png",
    "hotline": "0123456789",
    "link_facebook": "https://...",
    "link_zalo": ""
  }
}

Bank Packages

curl https://client.apinganhang.net/api/v1/services/packages.php \
  -H "Authorization: Bearer <token>"

200

{
  "success": true,
  "data": [
    {
      "id": 1,
      "bank_code": "MBBANK",
      "name": "MB Bank API",
      "price": 50000,
      "features": "Thông báo GD, lấy số dư",
      "active": 1
    }
  ]
}