Rate Limits, Pagination & Idempotency
TokPortal API rate limits (120 req/min), pagination with cursor-based offsets, and idempotency best practices.
Rate Limits & Pagination
Rate Limits
The TokPortal API allows 120 requests per minute per API key. The limit uses a token bucket algorithm that refills continuously, so you do not need to wait for a fixed window to reset.
Authenticated responses include rate limit headers:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 119
X-RateLimit-Reset: 1779724800
X-RateLimit-Reset is a Unix timestamp estimating when the token bucket will be full again.
Rate Limit Response
When you exceed the limit, the API returns a 429 Too Many Requests response:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1779724800
Retry-After: 1
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please slow down.",
"details": {
"retry_after_seconds": 2
}
}
}
Best Practices
- Read
Retry-Afterfirst on 429 responses. It is the canonical wait time before retrying. - Check
retry_after_secondsin the error response and wait before retrying. - Track
X-RateLimit-Remainingto smooth bursts before you hit the limit. - Use exponential backoff — if you receive consecutive 429s, increase the wait time between retries.
- Spread requests evenly rather than sending them in bursts. The token bucket refills at approximately 2 tokens per second, so a steady rate of 2 req/s is sustainable.
- Use separate API keys for independent services to isolate rate limits.
Pagination
All list endpoints support pagination via query parameters.
Query Parameters
| Parameter | Default | Max | Description |
|---|---|---|---|
page | 1 | — | The page number to retrieve (1-indexed). |
per_page | 25 | 100 | Number of items per page. |
Example Request
curl -X GET "https://app.tokportal.com/api/ext/bundles?page=2&per_page=50" \
-H "X-API-Key: sk_xxx"
Response Format
Paginated responses include a pagination object alongside data:
{
"data": [
{ "id": "bnd_abc123", "status": "published" },
{ "id": "bnd_def456", "status": "configuring" }
],
"pagination": {
"page": 2,
"per_page": 50,
"total": 137,
"total_pages": 3
}
}
Iterating Through All Pages
async function fetchAllBundles(apiKey: string) {
const results = [];
let page = 1;
while (true) {
const res = await fetch(
`https://app.tokportal.com/api/ext/bundles?page=${page}&per_page=100`,
{ headers: { "X-API-Key": apiKey } }
);
const { data, pagination } = await res.json();
results.push(...data);
if (page >= pagination.total_pages) break;
page++;
}
return results;
}
Idempotency
For mutating requests (POST, PUT, PATCH, and DELETE), you can include an Idempotency-Key header to safely retry requests without creating duplicate resources or double-charging credits.
Usage
curl -X POST https://app.tokportal.com/api/ext/bundles \
-H "X-API-Key: sk_xxx" \
-H "Idempotency-Key: my-unique-request-id-12345" \
-H "Content-Type: application/json" \
-d '{ "platform": "tiktok", "country": "US", "videos": 10 }'
How It Works
- The first request with a given
Idempotency-Keyis processed normally and the response is stored. - Subsequent requests with the same key, method, path, and request body return the original response without executing the operation again.
- Replayed responses include the
Idempotent-Replayed: trueheader. - Reusing the same key with a different request body returns
IDEMPOTENCY_KEY_REUSED. - Retrying while the first request is still running returns
IDEMPOTENCY_KEY_IN_PROGRESS; retry after a short delay. - Idempotency keys are scoped to your API key and expire after 24 hours.
- Use a unique value per logical operation (e.g., a UUID or a meaningful identifier from your system).
When to Use Idempotency Keys
Idempotency keys are recommended for any operation that:
- Creates a resource (bundles, video slots, edit slots)
- Debits credits
- Publishes, deletes, or updates state
- Could be retried due to network timeouts or uncertain responses
This prevents accidental double-charges or duplicate resource creation.
Idempotency Errors
| Code | HTTP Status | Meaning |
|---|---|---|
IDEMPOTENCY_KEY_TOO_LONG | 400 | The key is longer than 255 characters. |
IDEMPOTENCY_KEY_REUSED | 409 | The key already exists for a different request body. |
IDEMPOTENCY_KEY_IN_PROGRESS | 409 | The first request is still processing. Retry the exact same request shortly. |