Class: Tingee::Client
- Inherits:
-
Object
- Object
- Tingee::Client
- Defined in:
- lib/tingee/client.rb
Overview
HTTP + endpoint methods. Only live-verified endpoints are wrapped — no speculative "complete SDK". Responses use a uniform message, data envelope EXCEPT get-banks, which returns a bare array (verified live).
Instance Method Summary collapse
-
#confirm_delete_va(bank_bin:, confirm_id:, otp_number:) ⇒ Object
POST /v1/confirm-delete-va — finishes the unlink with the bank's OTP.
- #confirm_register_notify(bank_bin:, confirm_id:, otp_number:) ⇒ Object
-
#confirm_va(bank_bin:, confirm_id:, otp_number:) ⇒ Object
POST /v1/confirm-va — finishes the link with the bank's OTP.
-
#create_bank_link_session(merchant_id: nil, redirect_url: nil, allowed_banks: nil, bank_name: nil, shop_id: nil) ⇒ Object
POST /v1/create-bank-link-session — returns the SDK URL string (data).
-
#create_va(bank_bin:, webhook_url:, account_number: nil, account_name: nil, identity: nil, mobile: nil, account_type: "personal-account", is_notify_account_number: false, app_type: nil, redirect_url: nil, request_id: nil, merchant_id: nil, merchant_name: nil, merchant_address: nil, shop_id: nil, va_prefix: nil, va_suffix: nil) ⇒ Object
POST /v1/create-va — starts a bank link (the raw API chain, usable when Tingee's hosted JS SDK is unavailable or broken — docs/tingee-api-reference.md §create-va, live-verified).
-
#delete_va(bank_bin:, va_account_number:) ⇒ Object
POST /v1/delete-va — starts an unlink.
-
#get_banks ⇒ Object
GET /v1/get-banks — returns the bare bank array (the supported-bank/BIN map).
-
#get_transactions(start_time:, end_time:, filter: nil, skip_count: nil, max_result_count: nil, merchant_id: nil, shop_ids: nil, va_account_numbers: nil, bank_bin: nil) ⇒ Object
POST /v1/transaction/get-paging — transaction history.
-
#get_va_paging(merchant_id: nil) ⇒ Object
POST /v1/get-va-paging — returns items of linked virtual accounts.
-
#initialize(config = Tingee.config, read_timeout: 90) ⇒ Client
constructor
read_timeout: web requests keep the 90s default (stay under your proxy's response timeout); background jobs should pass a larger value — bank-side OTP verification on confirm_va can take minutes.
-
#register_notify(bank_bin:, va_account_number:) ⇒ Object
POST /v1/register-notify — ACB only, run once right after confirm_va succeeds.
Constructor Details
#initialize(config = Tingee.config, read_timeout: 90) ⇒ Client
read_timeout: web requests keep the 90s default (stay under your proxy's response timeout); background jobs should pass a larger value — bank-side OTP verification on confirm_va can take minutes.
13 14 15 16 17 |
# File 'lib/tingee/client.rb', line 13 def initialize(config = Tingee.config, read_timeout: 90) @config = config @read_timeout = read_timeout @config.validate! end |
Instance Method Details
#confirm_delete_va(bank_bin:, confirm_id:, otp_number:) ⇒ Object
POST /v1/confirm-delete-va — finishes the unlink with the bank's OTP. Params ride the BODY this time (unlike delete_va's query string above), and the bank is identified by bankBin here — bankName gets ignored and Tingee then fails with "Lỗi hệ thống phương thức xác thực" (seen live 2026-07-17).
136 137 138 |
# File 'lib/tingee/client.rb', line 136 def confirm_delete_va(bank_bin:, confirm_id:, otp_number:) post("/v1/confirm-delete-va", { bankBin: bank_bin, confirmId: confirm_id, otpNumber: otp_number }) end |
#confirm_register_notify(bank_bin:, confirm_id:, otp_number:) ⇒ Object
111 112 113 |
# File 'lib/tingee/client.rb', line 111 def confirm_register_notify(bank_bin:, confirm_id:, otp_number:) post("/v1/confirm-register-notify", { bankBin: bank_bin, confirmId: confirm_id, otpNumber: otp_number }) end |
#confirm_va(bank_bin:, confirm_id:, otp_number:) ⇒ Object
POST /v1/confirm-va — finishes the link with the bank's OTP. Returns accountType, accountNumber (real), vaAccountNumber (routing key), shopId.
101 102 103 |
# File 'lib/tingee/client.rb', line 101 def confirm_va(bank_bin:, confirm_id:, otp_number:) post("/v1/confirm-va", { bankBin: bank_bin, confirmId: confirm_id, otpNumber: otp_number }) end |
#create_bank_link_session(merchant_id: nil, redirect_url: nil, allowed_banks: nil, bank_name: nil, shop_id: nil) ⇒ Object
POST /v1/create-bank-link-session — returns the SDK URL string (data). No merchant_id is needed for the default merchant; pass one only for a sub-merchant.
26 27 28 29 30 31 32 33 34 |
# File 'lib/tingee/client.rb', line 26 def create_bank_link_session(merchant_id: nil, redirect_url: nil, allowed_banks: nil, bank_name: nil, shop_id: nil) payload = { type: "bank-link" } payload[:merchantId] = merchant_id if merchant_id payload[:redirectUrl] = redirect_url if redirect_url payload[:allowedBanks] = Array(allowed_banks) if allowed_banks payload[:bankName] = bank_name if bank_name payload[:shopId] = shop_id if shop_id post("/v1/create-bank-link-session", payload) end |
#create_va(bank_bin:, webhook_url:, account_number: nil, account_name: nil, identity: nil, mobile: nil, account_type: "personal-account", is_notify_account_number: false, app_type: nil, redirect_url: nil, request_id: nil, merchant_id: nil, merchant_name: nil, merchant_address: nil, shop_id: nil, va_prefix: nil, va_suffix: nil) ⇒ Object
POST /v1/create-va — starts a bank link (the raw API chain, usable when Tingee's hosted JS SDK is unavailable or broken — docs/tingee-api-reference.md §create-va, live-verified). ONE method serves all three bank shapes; which one you get is decided by the bank, not by a different endpoint:
OTP banks (STB, ACB, MBB, …) — pass account_number/account_name/identity/mobile.
The bank sends/pushes an OTP to `mobile`. Returns {confirmId, otpMethod};
finish with #confirm_va.
Redirect-authorize banks (VCB) — additionally pass app_type: "baas" +
redirect_url + request_id. Returns an authorizeLink/deepLink instead of
sending an OTP; the owner confirms in the bank's app and the result arrives
asynchronously on webhook_url as {status: "confirm-va-success"|"confirm-va-failed"}.
There is NO confirm_va step for these.
No-account-field banks (TPB, doc-sourced) — pass neither account nor identity
fields; the owner picks the account on the bank's own web. TPB returns NO
confirmId at all, so the request_id YOU send is the only key that can
correlate the settle webhook back to your pending request. Always pass and
STORE your own request_id for any redirect-authorize flow.
Every optional field is omitted from the payload when nil, so a bank only ever receives the params its contract actually defines (VCB tolerates and overrides what it doesn't use — verified live; TPB's contract has none of them).
is_notify_account_number: FALSE is the DEFAULT because it is the mode proved end-to-end — a real VietQR transfer to the linked real account fired the webhook on a notify=false link (2026-07-16). notify=true is documented as "watch the real account" and MAY also work, but was never confirmed to fire on a plain transfer; do not switch the default to true without a real-transfer test on a true link.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/tingee/client.rb', line 71 def create_va(bank_bin:, webhook_url:, account_number: nil, account_name: nil, identity: nil, mobile: nil, account_type: "personal-account", is_notify_account_number: false, app_type: nil, redirect_url: nil, request_id: nil, merchant_id: nil, merchant_name: nil, merchant_address: nil, shop_id: nil, va_prefix: nil, va_suffix: nil) payload = { accountType: account_type, bankBin: bank_bin, isNotifyAccountNumber: is_notify_account_number, webhookUrl: webhook_url } payload[:accountNumber] = account_number if account_number payload[:accountName] = account_name if account_name payload[:identity] = identity if identity payload[:mobile] = mobile if mobile payload[:appType] = app_type if app_type payload[:redirectUrl] = redirect_url if redirect_url payload[:requestId] = request_id if request_id payload[:merchantId] = merchant_id if merchant_id payload[:merchantName] = merchant_name if merchant_name payload[:merchantAddress] = merchant_address if merchant_address payload[:vaPrefix] = va_prefix if va_prefix payload[:vaSuffix] = va_suffix if va_suffix # One shop per project; an explicit arg wins over the configured default. shop_id ||= @config.shop_id payload[:shopId] = shop_id if shop_id post("/v1/create-va", payload) end |
#delete_va(bank_bin:, va_account_number:) ⇒ Object
POST /v1/delete-va — starts an unlink. Params ride the QUERY STRING (not the
JSON body); the bank is identified by bankBin, per the documented contract.
A bankName variant (Tingee's short bank CODE, e.g. "STB") also returns a
confirmId AND triggers the bank's OTP, so it looks like it worked — but the
session it creates cannot be confirmed: #confirm_delete_va then 400s with
"Lỗi hệ thống phương thức xác thực" (seen live 2026-07-17). Do not reintroduce
it. Unlink is the only way to stop Tingee's per-webhook billing, so an unlink
that silently cannot complete is expensive.
Returns confirmId (OTP banks). Bank-shape variations — TPB answers with an authorizeLink, VCB returns {} because it detaches immediately — are the caller's to branch on; see docs/tingee-api-reference.md §6.
128 129 130 |
# File 'lib/tingee/client.rb', line 128 def delete_va(bank_bin:, va_account_number:) request(:post, "/v1/delete-va", query: { bankBin: bank_bin, vaAccountNumber: va_account_number }) end |
#get_banks ⇒ Object
GET /v1/get-banks — returns the bare bank array (the supported-bank/BIN map).
20 21 22 |
# File 'lib/tingee/client.rb', line 20 def get_banks get("/v1/get-banks") end |
#get_transactions(start_time:, end_time:, filter: nil, skip_count: nil, max_result_count: nil, merchant_id: nil, shop_ids: nil, va_account_numbers: nil, bank_bin: nil) ⇒ Object
POST /v1/transaction/get-paging — transaction history. start_time/end_time
are required, format "yyyyMMddHHmmss" (UTC+7); Tingee caps each query at a
10-day window (over that it returns an error — not enforced here). Optional
params are only sent when given. Returns items.
144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/tingee/client.rb', line 144 def get_transactions(start_time:, end_time:, filter: nil, skip_count: nil, max_result_count: nil, merchant_id: nil, shop_ids: nil, va_account_numbers: nil, bank_bin: nil) payload = { startTime: start_time, endTime: end_time } payload[:filter] = filter if filter payload[:skipCount] = skip_count if skip_count payload[:maxResultCount] = max_result_count if max_result_count payload[:merchantId] = merchant_id if merchant_id payload[:shopIds] = Array(shop_ids) if shop_ids payload[:vaAccountNumbers] = Array(va_account_numbers) if va_account_numbers payload[:bankBin] = bank_bin if bank_bin post("/v1/transaction/get-paging", payload) end |
#get_va_paging(merchant_id: nil) ⇒ Object
POST /v1/get-va-paging — returns items of linked virtual accounts.
37 38 39 40 41 |
# File 'lib/tingee/client.rb', line 37 def get_va_paging(merchant_id: nil) payload = {} payload[:merchantId] = merchant_id if merchant_id post("/v1/get-va-paging", payload) end |
#register_notify(bank_bin:, va_account_number:) ⇒ Object
POST /v1/register-notify — ACB only, run once right after confirm_va succeeds. Returns confirmId for a second OTP round (see #confirm_register_notify).
107 108 109 |
# File 'lib/tingee/client.rb', line 107 def register_notify(bank_bin:, va_account_number:) post("/v1/register-notify", { vaAccountNumber: va_account_number, bankBin: bank_bin }) end |