API
Rate limits
Five rate limit tiers in 60 second windows, the RateLimit headers on every response, Retry-After on 429, and how the SDKs back off for you.
Limits protect the service from abuse and keep a busy read loop from starving payments. Each operation belongs to a tier, and the limit is a separate bucket per tier and caller: anonymous callers are counted by IP address, token callers by token, signed-in sessions by account. Windows are fixed at 60 seconds.
| Tier | Operations | Anonymous | With a token |
|---|---|---|---|
read | 34 | 60/min per IP | 600/min per token |
write | 28 | not allowed | 120/min per token |
plan | 1 | 5/min per IP and 40/day | 20/min per token and 500/day |
discover | 1 | 5/min per IP and 40/day | 10/min per token and 300/day |
payments | 8 | not allowed | 30/min per token |
Daily caps apply to plan and discover because each call fans out to several outside sources: anonymous callers get 40 a day on both, token callers 500 plans and 300 discovery calls a day. Write and payments operations are not available anonymously (401 unauthorized).
Which operation is in which tier
Headers
Every response from a rate-limited operation carries:
| Header | Meaning |
|---|---|
RateLimit-Limit | The quota of the tier for this caller. |
RateLimit-Remaining | Requests left in the current window. |
RateLimit-Reset | Seconds until the window resets (a delta, not a timestamp). |
RateLimit-Policy | The policy as <quota>;w=<seconds>, for example 60;w=60. |
Real headers from an anonymous GET /api/v1/items:
ratelimit-limit: 60
ratelimit-policy: 60;w=60
ratelimit-remaining: 59
ratelimit-reset: 59When you are over the limit the answer is 429 with a Retry-After header (seconds) and a rate_limited problem that repeats it as retry_after:
HTTP/2 429
retry-after: 17
content-type: application/problem+json{
"type": "https://reuseforge.com/docs/api/errors/rate_limited",
"title": "Rate limited",
"status": 429,
"detail": "Rate limit of 60 requests per 60 seconds for the \"read\" tier exceeded. Retry in 17 seconds.",
"code": "rate_limited",
"request_id": "req_...",
"retry_after": 17
}Failed authentication also counts: repeated bad tokens spend the anonymous read budget of your address.
Checking without spending
get_rate_limits reports every tier's state for the caller without consuming allowance, so a client can look before it starts a batch.
curl
curl https://reuseforge.com/api/v1/rate-limit -H "Authorization: Bearer $REUSEFORGE_TOKEN"Python
import reuseforge
print(reuseforge.Client().get_rate_limits())JavaScript
import { ReuseForge } from '@reuseforge/sdk';
console.log(await new ReuseForge().getRateLimits());CLI
rf api rate-limitBeing a good client
- Read the headers, do not hard-code the numbers. The values are initial and may change in a minor release;
GET /api/v1/andget_rate_limitsreport them. - On
429, waitRetry-Afterseconds, then retry. Do not retry in a tight loop. - Spread bulk work out and prefer
limit=100pages to many small requests; use conditional requests so repeat reads are cheap. - Send a descriptive
User-Agentthat names your tool and a contact, for examplemy-tool/1.0 (+https://example.com). The SDKs sendreuseforge-python/<version>andreuseforge-js/<version>. - Public GET responses are cacheable for a short time (
Cache-Control: public, max-age=15, s-maxage=30, stale-while-revalidate=60); a shared cache in front of your own service saves quota.
The SDKs and the CLI do this for you: they retry 429 after Retry-After (up to 60 seconds, longer is raised as RateLimitError) and back off with jitter on other transient failures. Higher quotas for organizations and verified publishers are arranged by agreement and are not part of the contract.
Last updated: