Data Flow Limiting
Overview
Vaultody applies two types of limits to API usage: rate limits (how many requests you can make per time window) and pagination limits (how many items are returned per API response). Both are determined by your subscription plan.
Rate Limiting
Each API is subject to a request rate limit. When you exceed the limit, the API returns:
HTTP 429 Too Many Requests
{
"requestId": "601c1710034ed6d407996b30",
"error": {
"code": "request_limit_reached",
"message": "The request limit has been reached. There can be maximum {requests} requests per {seconds} second(s) made. Please contact our team via email if you need more or upgrade your plan."
}
}
Handling 429 Responses
When you receive a 429, back off and retry with increasing delays. Do not retry immediately — this will continue to be rate-limited.
Python — exponential backoff:
import time
def request_with_retry(method, path, body=None, max_retries=4):
for attempt in range(max_retries):
response = signed_request(method, path, body)
if response.status_code == 429:
wait_seconds = 2 ** attempt # 1s → 2s → 4s → 8s
print(f"Rate limited. Retrying in {wait_seconds}s...")
time.sleep(wait_seconds)
continue
return response
raise Exception("Max retries exceeded after rate limiting")
Node.js — exponential backoff:
async function requestWithRetry(method, path, body = null, maxRetries = 4) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await signedRequest(method, path, body);
if (response.status === 429) {
const wait = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s, 8s
console.log(`Rate limited. Retrying in ${wait / 1000}s...`);
await new Promise(r => setTimeout(r, wait));
continue;
}
return response;
}
throw new Error('Max retries exceeded after rate limiting');
}
Best practice: Spread your API calls over time where possible. If you are syncing large amounts of data, use pagination and process pages sequentially rather than in parallel.
Pagination
Vaultody uses cursor-based pagination for all list endpoints. Pages are navigated using the ID of the last item you received, not a page number. This approach stays consistent and reliable even when new records are added between requests.
Pagination Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 50 | Number of items to return per page. Each endpoint declares its own maximum — 50 unless its reference page states otherwise. Exceeding it returns 409 naming the allowed maximum |
startingAfter |
string | — | The id (or equivalent ID field) of the last item from the previous page. Omit for the first page |
How It Works
On the first request, omit startingAfter:
GET /vaults/{vaultId}/vault-accounts/details?limit=50
The response includes a hasMore field:
{
"apiVersion": "2026-03-20",
"requestId": "601c1710034ed6d407996b30",
"data": {
"limit": 50,
"hasMore": true,
"items": [
{
"vaultAccountId": "68dfaeae39a4b80007c4f707",
"vaultAccountName": "User Alice"
}
]
}
}
If hasMore is true, take the vaultAccountId (or the relevant ID field) of the last item in the
array and pass it as startingAfter on the next request:
GET /vaults/{vaultId}/vault-accounts/details?limit=50&startingAfter=68dfaeae39a4b80007c4f707
Repeat until hasMore is false.
Full Pagination Example
Python — fetch all Vault Accounts:
def get_all_vault_accounts(vault_id):
all_accounts = []
starting_after = None
while True:
params = {'limit': 50}
if starting_after:
params['startingAfter'] = starting_after
resp = signed_request('GET', f'/vaults/{vault_id}/vault-accounts/details', params=params)
data = resp.json()['data']
all_accounts.extend(data['items'])
if not data['hasMore'] or not data['items']:
break
# Use the last item's ID as the next cursor
starting_after = data['items'][-1]['vaultAccountId']
return all_accounts
Node.js — fetch all Vault Accounts:
async function getAllVaultAccounts(vaultId) {
const allAccounts = [];
let startingAfter = null;
do {
const params = { limit: 50 };
if (startingAfter) params.startingAfter = startingAfter;
const resp = await signedRequest('GET', `/vaults/${vaultId}/vault-accounts/details`, null, params);
const { items, hasMore } = resp.data.data;
allAccounts.push(...items);
startingAfter = hasMore && items.length ? items[items.length - 1].vaultAccountId : null;
} while (startingAfter !== null);
return allAccounts;
}
Subscription Tiers
API data flow limits and feature availability are determined by your subscription tier. Higher tiers provide increased rate limits and higher Vault Account caps.
For details on what is included in each plan, visit the Vaultody pricing page or contact us through the Help Center.
Mainnet access is not available on free plans.
feature_mainnets_not_allowed_for_planmeans your plan is restricted to testnet — upgrade to enable mainnet access.mainnet_not_allowed_for_keymeans your plan allows mainnet but you used a test API key; create a main API key in the Dashboard.