API Reference
Programmatic read-only access to your treasury data. Requires an active Enterprise plan.
Generate an API key from the Billing page.
Authentication
All API requests require a Bearer token in the Authorization header. Generate an API key from the Billing page.
curl https://portfi.io/api/v1/balances \
-H "Authorization: Bearer tbops_xxxx"The organization is derived from the API key automatically. You do not need to pass an orgId parameter.
Endpoints
GET /api/v1/balances
Returns the latest token balance for each wallet/asset pair in your organization.
Query parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| limit | integer | No | 50 | Max results per page. Maximum: 100. |
| offset | integer | No | 0 | Pagination offset. |
Example request
curl https://portfi.io/api/v1/balances?limit=50 \
-H "Authorization: Bearer tbops_xxxx"Example response
{
"balances": [
{
"walletId": "abc123",
"walletName": "Primary Treasury",
"address": "0x1234...abcd",
"chain": "ETHEREUM",
"assetId": "ousg-ethereum",
"symbol": "OUSG",
"decimals": 18,
"rawBalance": "1000000000000000000000",
"formattedBalance": "1000.000000000000000000",
"usdValue": "1050.00",
"referencePrice": "1.05",
"fetchedAt": "2025-01-15T10:30:00.000Z"
}
],
"pagination": {
"limit": 50,
"offset": 0,
"count": 1,
"nextOffset": null
},
"generatedAt": "2025-01-15T10:30:00.000Z"
}GET /api/v1/transfers
Returns transfer events (inflows and outflows) for all wallets in your organization.
Query parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| limit | integer | No | 100 | Max results. Maximum: 500. |
| from | string | No | — | Start date filter (YYYY-MM-DD). |
| to | string | No | — | End date filter (YYYY-MM-DD, inclusive). |
Example request
curl "https://portfi.io/api/v1/transfers?from=2025-01-01&to=2025-01-31" \
-H "Authorization: Bearer tbops_xxxx"Example response
{
"transfers": [
{
"chain": "ETHEREUM",
"txHash": "0xabc123...",
"logIndex": 0,
"walletId": "abc123",
"walletName": "Primary Treasury",
"address": "0x1234...abcd",
"assetId": "ousg-ethereum",
"symbol": "OUSG",
"direction": "IN",
"rawAmount": "500000000000000000000",
"formattedAmount": "500.000000000000000000",
"blockNumber": 19500000,
"timestamp": "2025-01-10T14:22:00.000Z"
}
],
"count": 1,
"generatedAt": "2025-01-15T10:30:00.000Z"
}GET /api/v1/snapshots
Returns daily treasury snapshots showing aggregate balances and per-wallet breakdowns.
Query parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| limit | integer | No | 30 | Max results. Maximum: 90. |
| from | string | No | — | Start date (YYYY-MM-DD). |
| to | string | No | — | End date (YYYY-MM-DD, inclusive). |
Example request
curl "https://portfi.io/api/v1/snapshots?limit=7" \
-H "Authorization: Bearer tbops_xxxx"Example response
{
"snapshots": [
{
"date": "2025-01-15",
"totalsJson": {
"OUSG": {
"formatted": "1000.00",
"usdValue": "1050.00"
}
},
"perWalletJson": {},
"createdAt": "2025-01-15T01:00:00.000Z"
}
],
"count": 1,
"generatedAt": "2025-01-15T10:30:00.000Z"
}Error codes
| Status | Description |
|---|---|
| 401 | Missing or invalid API key. |
| 402 | Active Enterprise plan required. Upgrade your plan to access the API. |
| 403 | Access denied. Your key does not have permission for this resource. |
| 422 | Invalid query parameter (e.g. non-integer limit, malformed date). |
| 429 | Rate limit exceeded. See the Retry-After response header. |
| 500 | Internal server error. |
All error responses return a JSON body with an error string field describing the issue.
Rate limits
60 requests per minute per API key. Requests exceeding this limit receive HTTP 429 with a Retry-After response header indicating seconds until the next request is allowed.
Higher limits are available — contact us.
Code examples
curl
curl https://portfi.io/api/v1/balances?limit=50 \
-H "Authorization: Bearer tbops_xxxx"TypeScript / JavaScript
async function fetchBalances(offset = 0) {
const res = await fetch(
`https://portfi.io/api/v1/balances?limit=50&offset=${offset}`,
{
headers: {
Authorization: "Bearer tbops_xxxx",
},
}
);
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(`API error ${res.status}: ${err.error ?? "unknown"}`);
}
return res.json();
}
// Fetch first page
try {
const data = await fetchBalances();
console.log(data.balances);
// Paginate if there are more results
if (data.pagination.nextOffset !== null) {
const nextData = await fetchBalances(data.pagination.nextOffset);
console.log(nextData.balances);
}
} catch (err) {
console.error("Failed to fetch balances:", err);
}