API Reference
Base URL
Section titled “Base URL”https://limiter.tinyscale.ioPOST /v1/check
Section titled “POST /v1/check”Check and consume a rate limit. Returns whether the request is allowed and the remaining quota.
Request
Section titled “Request”POST /v1/checkAuthorization: Bearer ts_limiter_{mode}_{key}Content-Type: application/jsonRequest Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
namespace | string | Yes | Group for rate limits (e.g., "api", "auth") |
identifier | string | Yes | Unique ID within namespace (e.g., user ID, IP) |
limit | number | Yes | Maximum requests allowed in window |
window | number | Yes | Time window in milliseconds |
Example Request
Section titled “Example Request”curl -X POST https://limiter.tinyscale.io/v1/check \ -H "Authorization: Bearer ts_limiter_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "namespace": "api", "identifier": "user_123", "limit": 100, "window": 60000 }'const response = await fetch('https://limiter.tinyscale.io/v1/check', { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ namespace: 'api', identifier: 'user_123', limit: 100, window: 60000, }),});
const { data } = await response.json();import requests
response = requests.post( 'https://limiter.tinyscale.io/v1/check', headers={ 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json', }, json={ 'namespace': 'api', 'identifier': 'user_123', 'limit': 100, 'window': 60000, },)
data = response.json()['data']Response
Section titled “Response”{ "data": { "allowed": true, "remaining": 95, "limit": 100, "reset_at": 1703980800000, "namespace": "api", "identifier": "user_123" }}Response Fields
Section titled “Response Fields”| Field | Type | Description |
|---|---|---|
allowed | boolean | Whether the request is within the rate limit |
remaining | number | Requests remaining in current window |
limit | number | Maximum requests allowed (echoed from request) |
reset_at | number | Unix timestamp (ms) when window resets |
namespace | string | Namespace (echoed from request) |
identifier | string | Identifier (echoed from request) |
Namespaces
Section titled “Namespaces”Namespaces let you create separate rate limit buckets. Common patterns:
| Namespace | Use Case | Example Config |
|---|---|---|
api | General API calls | 100 req/min |
auth | Login attempts | 5 req/min |
ai | Expensive operations | 10 req/hour |
export | Data exports | 5 req/day |
upload | File uploads | 20 req/hour |
Each (namespace, identifier) pair has its own counter:
// These are separate rate limitsawait check({ namespace: 'api', identifier: 'user_1', limit: 100, window: 60000 });await check({ namespace: 'auth', identifier: 'user_1', limit: 5, window: 60000 });Common Window Values
Section titled “Common Window Values”| Duration | Milliseconds |
|---|---|
| 1 second | 1000 |
| 10 seconds | 10000 |
| 1 minute | 60000 |
| 5 minutes | 300000 |
| 1 hour | 3600000 |
| 1 day | 86400000 |
Rate Limit Headers
Section titled “Rate Limit Headers”Consider adding these headers to your API responses:
res.set({ 'X-RateLimit-Limit': data.limit, 'X-RateLimit-Remaining': data.remaining, 'X-RateLimit-Reset': data.reset_at,});Health Check
Section titled “Health Check”GET /v1/healthReturns service status. No authentication required.
{ "data": { "status": "healthy", "product": "limiter", "version": "v1", "timestamp": "2024-12-25T10:00:00.000Z" }}Request IDs
Section titled “Request IDs”Every response includes an X-Request-Id header for debugging:
X-Request-Id: req_a1b2c3d4e5f6g7h8i9j0k1l2Include this ID when contacting support.