Rate Limits & Pagination
Understanding request limits and navigating large result sets.
Rate Limits
Rate limits are per API key and measured as requests per minute. Different plan tiers have different limits. Rate limits apply to all API endpoints uniformly — there are no per-endpoint limits.
Limits by Plan
| Plan | Requests/minute | Monthly Credits | Price |
|---|---|---|---|
| Free | 10 | 25 | Free |
| Starter | 60 | 1,000 | €29/mo |
| Pro | 200 | 2,000 | €79/mo |
| Growth | 500 | 10,000 | €199/mo |
| Business | 1,000 | 35,000 | €499/mo |
Need Higher Limits?
Contact us for a custom Enterprise plan with higher rate limits and dedicated infrastructure.
Rate Limit Headers
Every API response includes headers that tell you about your current rate limit status:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Your rate limit (requests per minute) |
| X-RateLimit-Remaining | Requests remaining in current window |
| X-RateLimit-Reset | Unix timestamp when the window resets |
| Retry-After | Seconds to wait (only present on 429 responses) |
Example response with rate limit headers:
HTTP/1.1 200 OK
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 198
X-RateLimit-Reset: 1705312800
Content-Type: application/json
Handling Rate Limits
When you receive a 429 response, stop sending requests and wait for the duration specified in the
Retry-After header. Implement exponential backoff in your client to gracefully handle
rate limits without hammering the API. For high-throughput use cases, distribute requests evenly
across the minute rather than bursting them all at once.
Python Retry Pattern
import time
import requests
def api_request_with_retry(url, headers, json_data, max_retries=3):
for attempt in range(max_retries):
response = requests.post(url, headers=headers, json=json_data)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
time.sleep(retry_after)
continue
return response
raise Exception("Max retries exceeded")
Pagination
The job listing endpoint (GET /v1/jobs) uses cursor-based pagination for efficient
traversal of large result sets.
How Cursor Pagination Works
Your first request returns the first page of results plus a next_cursor value. Pass
this cursor as a query parameter to get the next page. Continue until has_more is
false, which indicates you’ve reached the end of the result set.
Cursor-based pagination is more reliable than offset pagination because it handles data changes (new or deleted items) gracefully. With offset pagination, inserting a new row can cause you to see duplicates or skip items. Cursors also perform consistently regardless of how deep you paginate — fetching page 1,000 is just as fast as fetching page 1.
Example
First request:
curl "https://videoconduit.com/v1/jobs?limit=10" \
-H "Authorization: Bearer vc_your_api_key"
Response:
{
"items": ["...10 jobs..."],
"next_cursor": "eyJjcmVhdGVkX2F0IjogIjIwMjUtMDEtMTRUMTI6MDA6MDBaIn0=",
"has_more": true
}
Next page — pass next_cursor as the cursor parameter:
curl "https://videoconduit.com/v1/jobs?limit=10&cursor=eyJjcmVhdGVkX2F0IjogIjIwMjUtMDEtMTRUMTI6MDA6MDBaIn0=" \
-H "Authorization: Bearer vc_your_api_key"
Pagination Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| cursor | string | null | Opaque cursor from previous response’s next_cursor |
| limit | int | 20 | Results per page (1–100) |
| status | string | null | Filter by job status: pending, processing, completed, failed |
| job_type | string | null | Filter by job type: download, transcribe, translate, preview, fingerprint, comments |
Paginating Through All Jobs
import requests
headers = {"Authorization": "Bearer vc_your_api_key"}
cursor = None
all_jobs = []
while True:
params = {"limit": 50}
if cursor:
params["cursor"] = cursor
response = requests.get(
"https://videoconduit.com/v1/jobs",
headers=headers,
params=params,
)
data = response.json()
all_jobs.extend(data["items"])
if not data["has_more"]:
break
cursor = data["next_cursor"]
print(f"Total jobs: {len(all_jobs)}")