Skip to main content
The OnlyTraffic Studio API lets you read and act on your Studio data: subscribers, transactions, orders, campaigns and more. Use it to build integrations, dashboards and automated workflows.

Base URL

Authentication

Get your API key and start making requests.

Pagination

Page-based and cursor-based listings.

Rate Limits

Per-key, per-tier hourly and burst caps.

Authentication

All requests require the X-API-Key header. Create your API key in the Studio Dashboard.
See the Authentication page for error codes and detailed setup.

Rate Limits

Limits are per API key, rolling window, and tiered by request kind: Both windows are enforced together. The hour quota is the long-window cap; the per-minute cap is burst protection on top of it.

Response headers (on every response, success or error)

Example:

When you go over

429 Too Many Requests with the standard error envelope plus a Retry-After header (seconds to wait):
Best practice: read X-RateLimit-Remaining after each call and back off when it gets low, instead of waiting for the 429.

Pagination

The API uses two pagination styles depending on the dataset size and access pattern.

Page-based (default for orders / campaigns)

Endpoints with bounded result sets (cpl/orders, cpc/orders, revshare/campaigns, etc.) use page-based pagination. The default page size is 50, max 100. Pass ?page=N to navigate.

Cursor-based (high-volume feeds)

Endpoints over high-volume tables (subscribers, transactions) use cursor pagination. The first call returns the first page plus a next_cursor token; pass that token back as ?after= to continue.
Continue:
When has_next is false (or next_cursor is null), you’ve reached the end. Why cursor on these endpoints
  • Stable ordering even when new rows are inserted between calls (page-based would shift).
  • No total count: cursor feeds optimize for partial reads, not row counts.
  • O(1) per page regardless of how deep you’ve scrolled.
Treat the cursor as an opaque string, don’t parse it. Sort direction Pass ?sort=<field>_asc to walk oldest to newest. Default is <field>_desc (newest first). The cursor is bound to the direction it was issued for; switching mid-pagination requires restarting.

Retries & idempotency

Concurrent mutations

Some write endpoints are serialized per account: a second request hitting the same resource while the first is still in flight returns 429 action_in_progress. Wait for the original to complete, then re-poll the corresponding GET to see the result. Don’t blind-retry through the in-flight window.

Safe to retry

NOT safe to blind-retry

400, 404, 409, 422, 426 are deterministic. The same request will produce the same error. Investigate (read error and details), fix the input, and only then resubmit. Exponential, capped: 1s, 2s, 4s, 8s, 16s, 30s. If the response carries retry_after (body) or Retry-After (header), honour the server-suggested wait, it beats local back-off.

Example: handling 429

JavaScript

Response Format

All responses follow a consistent structure:

Write responses & schema evolution

Writes return id-only

Successful POST / PUT / PATCH / DELETE responses carry just the resource id (and success: true), not the full record:
To read the post-write state, call the matching GET endpoint. The list / detail endpoints are the single source of truth for the response shape. Two exceptions:
  • Image upload endpoints also return thumbnail_url (a 3-day signed URL) so you can render the just-saved image without a follow-up call. Originals stay behind the regular GET.
  • One-time secrets (the plaintext API key returned on key creation, verification tokens) appear in data for that single response and are documented as “shown once, never again”.

Schema evolution policy

We may add fields to existing responses without notice. Consumers MUST ignore unknown fields rather than fail-on-extra. v1 is still young and may change without warning as we fix and refine it. Keep an eye on this doc — if something breaks for you, check here first. Practically:
  • Configure your parser to allow extra fields rather than reject them.
  • Validate inputs strictly, treat outputs liberally.