Rate Limits

Rate limit tiers for all Dual API endpoint groups, with response headers and SDK handling guidance.

Rate limits protect platform stability and ensure fair usage across all organisations. Limits are applied per API key and reset on a rolling window.

Response Headers

Every API response includes rate limit headers so you can track your usage:

Code
X-RateLimit-Limit: 300 # Maximum requests in the window
X-RateLimit-Remaining: 287 # Requests remaining
X-RateLimit-Reset: 1711036800 # Unix timestamp when the window resets
Retry-After: 12 # Seconds until next request (only on 429)

Limits by Endpoint Group

Read operations, 300 req/min · burst: 50 req/s

Applies to: GET /objects, GET /templates, GET /wallets, GET /indexer/*


Write operations, 60 req/min · burst: 10 req/s

Applies to: POST /objects, PUT /objects/*, POST /templates


Event Bus, 2,000 actions/sec per org

Applies to: POST /ebus/actions, POST /ebus/actions/batch


Search / Indexer, 120 req/min · burst: 20 req/s

Applies to: GET /indexer/search, GET /indexer/query


Storage uploads, 30 req/min · burst: 5 req/s

Applies to: POST /storage/upload


Webhooks management, 30 req/min · burst: 5 req/s

Applies to: POST /webhooks, PUT /webhooks/*

Handling Rate Limits in the SDK

The TypeScript SDK automatically retries on 429 responses with exponential backoff when you configure the retry option:

typescript
import { DualClient, DualRateLimitError } from "dual-sdk";
const client = new DualClient({
token: process.env.DUAL_API_KEY,
authMode: "api_key",
retry: { maxAttempts: 3 }, // auto-retries on 429 with backoff
});
try {
const objects = await client.objects.list({ limit: 50 });
} catch (err) {
if (err instanceof DualRateLimitError) {
console.log(`Rate limited. Retry after ${err.retryAfter}s`);
}
}

Need higher limits? Contact support to discuss enterprise rate limit tiers. See also the Error Reference for handling all error types.