Skip to main content

Rate Limiting

The API enforces rate limits to ensure fair usage and platform stability. Limits are applied per tenant using a sliding-window algorithm.

Default Limits

ScopeLimitWindow
General API100 requests1 minute
Authentication (/auth/login, /auth/register)10 requests1 minute
Token refresh (/auth/refresh)30 requests1 minute
Batch operations (/batch)20 requests1 minute

Response Headers

Every response includes rate-limit headers so your application can adjust dynamically:

HeaderDescriptionExample
X-RateLimit-LimitMax requests allowed in the window100
X-RateLimit-RemainingRequests remaining in current window87
X-RateLimit-ResetUnix timestamp (seconds) when the window resets1718234567
Retry-AfterSeconds to wait before retrying (only on 429)12
X-RateLimit-PolicyHuman-readable policy description100;w=60

429 Error Response

When you exceed the limit, the API returns HTTP 429:

{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Try again in 12 seconds.",
"status": 429
}
}

SDK — Automatic Backoff

The SDK handles 429 responses automatically with exponential backoff:

import { Urblock } from "@urblock/sdk";

// Built-in retry on 429/5xx with exponential backoff + jitter (up to 3 retries by default)
const urblock = new Urblock(process.env.URBLOCK_API_KEY!, {
maxRetries: 3, // default — set 0 to disable
});

// You can also handle it manually for bulk operations
async function mintBatch(recipients: string[], tokenId: string) {
for (const to of recipients) {
try {
await urblock.tokens.mint(tokenId, {
to,
amount: "1000000000000000000",
});
} catch (err) {
if (err.status === 429) {
const waitMs = (err.retryAfter || 10) * 1000;
console.log(`Rate limited — waiting ${waitMs}ms`);
await new Promise(r => setTimeout(r, waitMs));
// Retry the same item
await urblock.tokens.mint(tokenId, {
to,
amount: "1000000000000000000",
});
} else {
throw err;
}
}
}
}

curl — Checking Headers

curl -i https://api.urblock.io/tokens \
-H "Authorization: Bearer $TOKEN"

# Response headers:
# X-RateLimit-Limit: 100
# X-RateLimit-Remaining: 99
# X-RateLimit-Reset: 1718234567

Monitoring Rate Limits

Build a simple monitor to log your usage:

const response = await fetch("https://api.urblock.io/tokens", {
headers: { Authorization: `Bearer ${token}` },
});

const remaining = parseInt(response.headers.get("x-ratelimit-remaining") || "0");
const limit = parseInt(response.headers.get("x-ratelimit-limit") || "100");
const usage = ((limit - remaining) / limit * 100).toFixed(1);

console.log(`Rate limit usage: ${usage}% (${remaining}/${limit} remaining)`);

if (remaining < 10) {
console.warn("⚠️ Approaching rate limit — consider throttling requests");
}

Best Practices

  1. Read Retry-After — always respect the header instead of using a fixed wait
  2. Use batch endpoints/batch processes multiple operations in one request
  3. Cache responsesGET /networks and GET /tokens/:id rarely change
  4. Spread bulk work — distribute requests evenly across the window instead of bursting
  5. Monitor headers — track X-RateLimit-Remaining to preemptively throttle
  6. Use webhooks over polling — webhooks don't count toward your rate limit
Batch Operations

A single batch request counts as one request regardless of how many operations it contains. Use Batch Operations to minimize rate-limit consumption.

Next Steps