Getting Started

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-After first on 429 responses. It is the canonical wait time before retrying.
  • Check retry_after_seconds in the error response and wait before retrying.
  • Track X-RateLimit-Remaining to 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

ParameterDefaultMaxDescription
page1The page number to retrieve (1-indexed).
per_page25100Number 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-Key is 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: true header.
  • 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

CodeHTTP StatusMeaning
IDEMPOTENCY_KEY_TOO_LONG400The key is longer than 255 characters.
IDEMPOTENCY_KEY_REUSED409The key already exists for a different request body.
IDEMPOTENCY_KEY_IN_PROGRESS409The first request is still processing. Retry the exact same request shortly.