0Pools API
Approved partner 0Pools discovery, quote, transact, status, trade, funding, ledger, and balance operation groups.
0Pools is the approved-partner API for headless pool liquidity workflows. It lets an entitled partner discover the pools available to its account, request firm or indicative quotes, execute exactly once against a firm quote, poll or read trade state, and reconcile balance movements.
This reference is OpenAPI-backed and public-safe. It explains the contract partners can build against without exposing liquidity sources, routing internals, reserve allocation, treasury balances, provider names, market-maker terms, or runbooks.
OpenAPI-backed, gated partner contract
The machine-readable OpenAPI 3.1 contract for 0Pools is available at /openapi/pools-v1.yaml. Use it for client generation and schema validation. Use these pages for lifecycle rules, public boundaries, examples, and production decisions.
Contract snapshot
| Item | Current shape |
|---|---|
| OpenAPI title | 0Pools Partner API |
| OpenAPI version | 2026-05-25 |
| Published operations | 12 partner-facing operations |
| Main production host | https://pools-api.0bit.app/v1 |
| Main sandbox host | https://pools-api-sandbox.0bit.app/v1 |
| Discovery credential | Publishable key for GET /pools only |
| Money-moving credential | Secret key from your server |
| Availability | Gated early access, provisioned per partner |
The API is not self-serve. A valid key does not mean every pool, side, rail, balance gate, or environment is enabled. Your account entitlement decides which pools appear and which operations succeed.
What this API covers
- Entitled pool discovery and current partner-visible availability.
- Per-pool capabilities: sides, networks, limits, fees, spreads, tier, and balance gates.
- Firm quotes for executable short-lived locks.
- Indicative quotes for price-only previews.
- One-time idempotent execution against firm quotes.
- Status polling that can advance settlement.
- Pure trade reads for display, support, and reconciliation.
- Partner-visible balance and funding views.
- Partner-scoped ledger entries for balance reconciliation.
Public boundary
This reference covers partner-visible discovery, quote, transact, status, trade, funding, ledger, and balance behavior. It does not expose liquidity sources, provider names, route priority, market-maker terms, reserve levels, treasury account balances, top-up runbooks, or settlement worker internals.
Authentication map
| Credential | Where it belongs | Allowed Pools use | Not allowed |
|---|---|---|---|
pk_test_* / pk_live_* | Browser/mobile where approved | GET /pools discovery only | Quotes, transacts, balance, funding, ledger, trade reads |
sk_test_* / sk_live_* | Your server only | Capabilities, quote, transact, status, trades, balance, funding, ledger | Browser/mobile client code |
Idempotency-Key | Your server-generated write header | Required for POST /pools/{id}/transact | Reusing across different quote executions |
X-Request-Id | Response header | Support correlation | Business logic branching |
Discovery is not execution approval
GET /pools can show an entitled pool, but quote and transact calls still enforce account status, KYC/KYB state, tier, balance, side, route availability, and environment gates.
Operation map
| Area | Operation | Method and path | Auth boundary | Use it for |
|---|---|---|---|---|
| Discovery | listPools | GET /pools | Publishable key | List pools visible to your account. |
| Discovery | getPoolCapabilities | GET /pools/{id}/capabilities | Secret key + entitlement | Read supported sides, networks, order bounds, fees, spread caps, tier, and balance gates. |
| Quotes | createQuote | POST /pools/{id}/quote | Secret key + entitlement | Request a firm executable quote or indicative price. |
| Transactions | transact | POST /pools/{id}/transact | Secret key + idempotency + entitlement | Execute exactly once against a firm quote. |
| Transactions | getTransactionStatus | GET /pools/transactions/{quoteId} | Secret key | Poll by quote id; this poll can advance settlement. |
| Reconciliation | listTrades | GET /pools/trades | Secret key | Cursor-paginated trade history for support and reconciliation. |
| Reconciliation | getTrade | GET /pools/trades/{transactId} | Secret key | Pure read of one trade; does not advance settlement. |
| Quotes | getQuote | GET /pools/quotes/{quoteId} | Secret key | Retrieve quote state without consuming it. |
| Quotes | rejectQuote | POST /pools/quotes/{quoteId}/reject | Secret key | Decline an active quote so it cannot be executed. |
| Discovery | getPoolBalance | GET /pools/{id}/balance | Secret key + entitlement | Read partner-visible balance and entitlement context. |
| Reconciliation | getFundingInstructions | GET /pools/funding | Secret key | Read dedicated funding instructions where enabled. |
| Reconciliation | listLedgerEntries | GET /pools/ledger | Secret key | Reconcile balance credits and debits. |
End-to-end lifecycle
The important split is between driver reads and display reads. GET /pools/transactions/{quoteId} can progress a reserved trade. GET /pools/trades and GET /pools/trades/{transactId} are pure reads for dashboards, support, and reconciliation.
Quote outcomes
| Outcome | HTTP status | Fields | What your app should do |
|---|---|---|---|
| Firm executable quote | 200 | available: true, executable: true, quoteId, expiresAt | Show a short accept window and execute once before expiry. |
| Indicative quote | 200 | available: true, executable: false, no quoteId | Show price-only preview; never pass it to transact. |
| Fail-soft unavailable | 200 | available: false, unavailableReason, no quoteId | Show unavailable state, try another pool, or back off. |
| Validation failure | 400 | Error envelope | Fix request body or user input. |
| Entitlement denied | 403 | Error envelope with denial code | Confirm account access; do not retry in a loop. |
| Unknown scoped object | 404 | Error envelope | Treat as not found for this partner/environment. |
Fail-soft 200 responses are intentional. Branch on available and executable, not just HTTP status.
Example: quote then execute
curl -X POST https://pools-api-sandbox.0bit.app/v1/pools/EUR-USDT/quote \
-H "Authorization: Bearer sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"side": "on_ramp",
"fiatCurrency": "EUR",
"cryptoCurrency": "USDT",
"amount": "100.00",
"cryptoNetwork": "tron",
"type": "firm",
"destAddress": "0x52908400098527886E0F7030069857D2E4169EE7",
"destNetwork": "arbitrum"
}'
curl -X POST https://pools-api-sandbox.0bit.app/v1/pools/EUR-USDT/transact \
-H "Authorization: Bearer sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 00000000-0000-4000-8000-000000000456" \
-d '{ "quoteId": "pq_test_8f3c000000000123" }'const quoteResponse = await fetch('https://pools-api-sandbox.0bit.app/v1/pools/EUR-USDT/quote', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.OBIT_POOLS_SECRET_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
side: 'on_ramp',
fiatCurrency: 'EUR',
cryptoCurrency: 'USDT',
amount: '100.00',
cryptoNetwork: 'tron',
type: 'firm',
destAddress: '0x52908400098527886E0F7030069857D2E4169EE7',
destNetwork: 'arbitrum',
}),
});
const quote = await quoteResponse.json();
if (!quote.available || !quote.executable) {
throw new Error(`Pool unavailable: ${quote.unavailableReason ?? 'not executable'}`);
}
const tradeResponse = await fetch('https://pools-api-sandbox.0bit.app/v1/pools/EUR-USDT/transact', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.OBIT_POOLS_SECRET_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({ quoteId: quote.quoteId }),
});
const trade = await tradeResponse.json();import os
import uuid
import requests
quote = requests.post(
"https://pools-api-sandbox.0bit.app/v1/pools/EUR-USDT/quote",
headers={
"Authorization": f"Bearer {os.environ['OBIT_POOLS_SECRET_KEY']}",
"Content-Type": "application/json",
},
json={
"side": "on_ramp",
"fiatCurrency": "EUR",
"cryptoCurrency": "USDT",
"amount": "100.00",
"cryptoNetwork": "tron",
"type": "firm",
"destAddress": "0x52908400098527886E0F7030069857D2E4169EE7",
"destNetwork": "arbitrum",
},
).json()
if not quote.get("available") or not quote.get("executable"):
raise RuntimeError(f"Pool unavailable: {quote.get('unavailableReason')}")
trade = requests.post(
"https://pools-api-sandbox.0bit.app/v1/pools/EUR-USDT/transact",
headers={
"Authorization": f"Bearer {os.environ['OBIT_POOLS_SECRET_KEY']}",
"Content-Type": "application/json",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"quoteId": quote["quoteId"]},
).json()Object model
On-ramp and off-ramp behavior
| Side | Meaning | Amount role | Public status |
|---|---|---|---|
on_ramp | Buy crypto with fiat | amount is the fiat amount paid in | Supported flow for approved partners. |
off_ramp | Sell crypto for fiat | amount is the crypto amount sold | Account-gated and not publicly enabled by default. |
For on-ramp delivery, the destination address is locked on the quote and copied to the trade. Do not collect a new destination address at transact time. For off-ramp, build only after your account has explicit enablement and the crypto-receipt path is confirmed.
Status model
| Status | Meaning | Developer rule |
|---|---|---|
quoted | Quote exists but has not been executed | Execute before expiry or reject it. |
reserved | Trade is accepted and waiting for settlement progress | Poll GET /pools/transactions/{quoteId}. |
settled | Trade reached successful settlement state | Reconcile trade and ledger. |
released | Reserved funds or lock were released | Stop polling and reconcile. |
failed | Trade failed terminally | Show recoverable support path and reconcile. |
returned | A previously settled value was reversed and credited back | Reconcile the ledger credit; webhooks alone are not enough. |
The returned state is why a webhook-only integration is incomplete. Continue polling after settlement where your flow requires reversal detection, or reconcile the ledger on a schedule.
Reconciliation model
| Read | Advances settlement? | Use it for |
|---|---|---|
GET /pools/transactions/{quoteId} | Yes | Move a reserved trade toward terminal state and catch returned state. |
GET /pools/trades | No | Back-office history, filters, export, support. |
GET /pools/trades/{transactId} | No | One trade display or support lookup. |
GET /pools/{id}/balance | No | Balance and entitlement context. |
GET /pools/ledger | No | Credits, debits, refunds, and balance reconciliation. |
Store your own order id, pool id, quote id, trade id, idempotency key, request id, status, amount/rate strings, fee/spread bps, and timestamps. Those records let support investigate without any private route details.
Error and retry model
| Outcome | What to do |
|---|---|
200 with available: false | Do not transact. Show unavailable state or try another entitled pool. |
400 validation error | Fix request body, address, network, side, or amount. |
401 auth error | Check key and environment. |
402 insufficient balance | Fund the balance where enabled, then retry from a fresh quote if needed. |
403 entitlement or key-mode error | Confirm account access, KYC/KYB state, side enablement, pool entitlement, and key type. |
404 scoped object missing | Treat as not found for this partner/environment. |
409 quote conflict | Retrieve quote/trade state; do not blindly retry. |
429 rate limit | Back off with jitter. |
5xx or timeout | Retry with bounded backoff; writes must use idempotency. |
501 off-ramp not enabled | Stop the flow and request enablement. |
Production checklist
- Account has explicit 0Pools approval.
- Pool appears in
GET /poolsfor the active environment. - Your server reads capabilities before quoting.
- Browser code never uses
sk_*. - Amounts and rates are strings, never floats.
- Firm quote expiry is enforced in your UI.
- Transact uses a durable idempotency key.
- Status polling uses
quoteIdand recognizes terminal states. - Trade reads are used for display and reconciliation.
- Ledger reconciliation runs after settlement and on a schedule.
- Support tooling can search by your order id, quote id, trade id, and request id.
- The UI never exposes source/provider/route internals.
Related pages
List entitled pools
Discover the pool set visible to your account.
Read pool capabilities
Load supported sides, networks, limits, fees, and balance gates.
Create a quote
Request a firm or indicative quote.
Execute a quote
Transact exactly once with idempotency.
Read pool ledger
Reconcile balance movements and returned trades.
0Gate API
Use the hosted integration path for most partner flows.