Skip to main content

Getting started

https://api.qbank.cl/platform — every endpoint in this documentation hangs from it (for example https://api.qbank.cl/platform/v1/balances).
No. The API runs directly in production. To test your integration use small real amounts: deposit a few USDT, run a minimal payout and verify the full cycle (debit → webhook → final state). If anything fails, the debit is refunded automatically — a data mistake cannot “lose” your balance.
Two ways: (1) deposit USDT on-chain — create a wallet with POST /v1/crypto/wallets and send USDT to that address (TRON or Ethereum); (2) collect fiat with a payin (QR, announced transfer, etc.). Either way the balance is credited automatically and a webhook notifies you.
Yes: every account must approve its identity verification (person = KYC, company = KYB) before moving money out. Meanwhile you can fund (payins, crypto deposits, incoming transfers) and read; other actions answer 403 verification_required. Request your link with POST /v1/me/verification/link and complete the wizard — full guide. If anything returns 403 account_blocked, contact the CBPay team.
That service is not enabled for your account (services are enabled per account according to your commercial agreement). Check GET /v1/services for the full map of what you can use — also handy to decide what to show in your UI — and contact the CBPay team if you need something enabled. Reads and money already in flight are never blocked.
For server-to-server processes always use an API key (pk_…, never expires). JWT sessions (24 h) are for front-ends with users who log in. Both travel in Authorization: Bearer <token> (or X-API-Key).

Money and rates

Only USDT with 6 decimals. Every fiat operation (payouts in CLP, collections in BOB…) converts to/from USDT at your account’s rates at execution time (rate for payouts, payin_rate for payins). See the money model.
Query GET /v1/rates (returns your rate per country) and compute:
The payout object returns the exact server-computed values (fx_rate, usdt_amount, fee, total_debit).
It is not a frozen quote: the payout uses the rate in force at creation time and the payin the one in force at credit time, which can drift slightly from the one you fetched. The applied rate is recorded in each operation’s fx_rate field for audit.
The API imposes no technical minimums; with very small amounts the fixed fee can exceed the amount (you’ll get invalid_amount or an uneconomic debit). Maximums depend on your configuration with CBPay.
CBPay defines them for your account: per service (payout, payin, funding, withdrawal, KYC, wallet creation), per country, with % and/or fixed components. GET /v1/rates returns your effective list in the fees field (FX percentages are already baked into the quoted rate). Details in fees.

Payouts

It depends on the corridor: several are synchronous or near-instant (Yape, Pago Móvil, Bolivia QR) and others process within minutes through the local banking rail (SPEI, transfers). Design your integration around the payout_status_changed webhook: don’t assume fixed timings or poll.
The full debit (amount + fee) is refunded to your available balance automatically, and the webhook arrives with status: failed and a status_code explaining the cause. Fix the data and retry with a new idempotency_key.
Yes — that is what the idempotency_key is for: repeating the same key returns the original payout (idempotency_hit: true) without creating or debiting anything new. Use a different key only when you truly want another payment. See idempotency.
Examples by country has a field table and a complete example per country and method, and GET /v1/payouts/banks?country=XX returns the current bank codes where they apply.
No: each scan provider_reference admits a single confirm. Retries with the same idempotency_key return the original payout.
No. Once a payout is processing the banking rail already has it; there is no API cancellation. Wait for the final state: if the rail rejects it, the full refund is automatic. Verify the beneficiary data before creating (the free qr/scan exists precisely to confirm the recipient before paying a QR).
The API imposes no technical minimums (with tiny amounts the fixed fee may exceed the amount). Maximums and operational limits depend on your commercial agreement and the corridor — to raise limits, contact your CBPay administrator with the country, expected volume and average ticket.

Payins and deposits

When the provider confirms the payment: QRs and active collections usually credit within seconds; bank transfers when the deposit arrives and is matched. You always receive the payin_credited webhook with the net credited amount.
No. The deposit lands as unassigned and the CBPay team routes it to your account manually (once assigned it is credited with your normal rate and fees). Meanwhile it does not show in your balance — if you are expecting a deposit that never arrives, tell your administrator the amount, currency and approximate time to speed up the assignment. To avoid it, use the dedicated CLABE account in Mexico, the payment page in Chile, or make sure the reference travels in the transfer description.
Detection is near-instant and the credit lands when the network confirms: TRON ~1 minute (19 confirmations), Ethereum a few minutes depending on congestion. The crypto_deposit_credited webhook closes the cycle with the tx_id so you can verify it on the explorer.
With the statement: one endpoint that consolidates every movement of the period (payouts, payins, crypto, transfers and fees) with an exact accounting reconciliation. Request format=pdf or format=xlsx to download the CBPay-branded document, or json to render it in your web.
No. Banking money lives in your real bank accounts (USD or other enabled currencies) and is queried with GET /v1/banking/accounts/{id}/balance. Your CBPay balance is USDT and is only touched to charge the fixed banking fees (refunded if the operation fails).
No: a payin is a fiat collection (local currency → USDT); a crypto deposit is on-chain USDT arriving at your wallet (funding). Both end up in the same USDT balance, with different webhooks (payin_credited vs crypto_deposit_credited).

Webhooks and errors

No, but strongly recommended: final states arrive by webhook with no polling. You can still fetch any object by API (GET /v1/payouts/{id}, GET /v1/payins/{id}…) at any time.
Local URLs are rejected for security. Use a free HTTPS tunnel (Cloudflare Tunnel or ngrok) and subscribe that public URL — step-by-step recipe in environment and testing.
They read the same ledger: movements is the paginated programmatic view (for automatic reconciliation and your UI); the statement is the period snapshot with totals, breakdowns and a guaranteed balance (for accounting closes). They never disagree. Details in movements and reconciliation.
Deliveries are at-least-once: timeouts trigger retries (up to 5). Deduplicate with the X-Webhook-Event-ID header, unique per event.
It is transient: retry with backoff using the same idempotency_key (so you never duplicate). If it persists, contact the CBPay team with the payout_id/payin_id and the time.
Last modified on July 10, 2026