API keys & wallet login
Two ways to access the API: API keys for your servers, and wallet sessions (message signature) for actions on behalf of a wallet.
Base URL & format
https://banipool.com/api/v1- Successful response:
{ "data": …, "meta": { "requestId", "asOf", "nextCursor"?, "partial"? } }. - Token amounts and money values are strings (full precision); unavailable metrics are
null, never invented. - IDs use CAIP standards: network
eip155:8453, accounteip155:8453:0x…, tokeneip155:8453/erc20:0x….
API key
Create a key in Developer Portal → API keys (wallet login required). The key is bound to its owner wallet, shown only once, and can be revoked at any time. Store it in your server environment, never in frontend code.
# Header x-api-key (atau Authorization: Bearer <key>)
curl -s "https://banipool.com/api/v1/pools?chain=base&limit=5" \
-H "x-api-key: $BANIPOOL_API_KEY"| Scopes | Access |
|---|---|
data:read | Public data: networks, pools, tokens, account balances & positions, status, SSE. |
quotes:create | Transaction quotes & Zap plans (simulated on behalf of the key owner wallet). |
plans:create | Unsigned transaction plans and tracking for the key owner wallet. |
strategies:read / write | Paper/notify automation rules of the key owner wallet. |
Quotas & rate limits
- Cost per request: regular read 1 unit; history, balances, account positions 5; quote/plan 10; tracking 5.
- Remaining quota is shown in the
X-Quota-LimitandX-Quota-Remainingheaders; HTTP 429 includesRetry-After. - Public reads carry an
ETag; sendIf-None-Matchto get a 304 without a body when data is unchanged.
Wallet login (session)
Transaction and private-data endpoints (/v1/me/*) use a wallet session. Create a challenge, sign its message verbatim with personal_sign, then verify. Non-browser clients receive a 7-day session token for the Authorization: Bearer header; browsers receive an HttpOnly cookie.
import { privateKeyToAccount } from 'viem/accounts';
const API = 'https://banipool.com/api/v1';
const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
// 1) Challenge
const ch = await fetch(`${API}/auth/challenges`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ address: account.address, chainId: 8453 }),
}).then((r) => r.json());
// 2) Tanda tangani pesan apa adanya (personal_sign)
const signature = await account.signMessage({ message: ch.data.message });
// 3) Verifikasi → token sesi 7 hari
const v = await fetch(`${API}/auth/verify`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ challengeId: ch.data.id, signature }),
}).then((r) => r.json());
const session = v.data.token; // Authorization: Bearer <session>The login signature grants no transaction permission. Browser mutations must send the x-banipool-csrf: 1 header.
TypeScript SDK
The @defi/api-client workspace contains a typed client generated from the OpenAPI contract. Download the contract at /api/v1/openapi.json to generate clients in other languages (openapi-generator, oapi-codegen, etc.).
import { createDefiClient } from '@defi/api-client';
const client = createDefiClient({
baseUrl: 'https://banipool.com/api',
apiKey: process.env.BANIPOOL_API_KEY!,
});
const { data, error, response } = await client.GET('/v1/pools', {
params: { query: { chain: 'base', limit: 50 } },
});
if (!response.ok) throw new Error(JSON.stringify(error));
console.log(data?.data.length, data?.meta.nextCursor);import os, requests
API = "https://banipool.com/api/v1"
r = requests.get(f"{API}/pools", params={"chain": "base", "limit": 50},
headers={"x-api-key": os.environ["BANIPOOL_API_KEY"]}, timeout=20)
r.raise_for_status()
body = r.json()
for pool in body["data"]:
print(pool["id"], pool.get("tvlUsd"))
print("cursor berikutnya:", body["meta"].get("nextCursor"))