Skip to main content
The Thrad Advertiser API lets you build and run ad campaigns end-to-end from your own code — create the campaign tree, launch it, manage its lifecycle, and read back performance — without touching the Thrad Platform dashboard. It is a plain REST surface: predictable resource paths, JSON in and out, one Bearer key. Responses are bare objects and lists rather than a wrapper envelope, money is in integer micros, and timestamps are ISO 8601 strings. Read Conventions once and every endpoint on this site behaves the way you expect. Insights numbers combine Thrad and ChatGPT (OpenAI Ads) supply by default, so a single read gives you the full picture across both surfaces.

Base URL

Every endpoint path below is relative to this base URL. Paths use underscores, public UUID ids, and no trailing slash.

Resource hierarchy

Resources nest four levels deep. A campaign owns its ad groups, and each ad group owns its ads. The ad account is the top scope — it is the advertiser organization itself.
  • Ad Account — the org’s default ad account. Read-only; it is the root scope for account-level insights.
  • Campaign — name, budget, schedule, and targeting. Created as one nested call (campaign + ad_groups[], each with ads[]) that auto-launches on submit.
  • Ad Group — context_hints and a bidding_config.max_bid_micros. Add ad groups to an existing campaign.
  • Ad — the copy (card or poll) plus a required asset_id. The referenced asset supplies the image and the destination URL.

Two surfaces

The API is split into two surfaces that share authentication but differ in shape and purpose.

Resources

Write surface. CRUD over campaigns, ad groups, and ads, plus /activate /pause /archive lifecycle actions, and read-only access to the ad account and the asset catalog. Returns bare list/object shapes. Resource money is in integer micros.

Insights

Read-only analytics across the four resource levels. Combines Thrad + ChatGPT supply by default. Returns a bare list of metric rows where money is an integer *_micros value paired with a formatted *_display string.

Endpoints at a glance

Conventions

Authentication

Every request is authenticated with an org-bound Bearer key on the Authorization header.
string
required
Bearer ak_.... There is one active key per organization. Create the key in the Thrad Platform dashboard under Settings → API keys. Store it as the environment variable THRAD_ADS_API_KEY and never commit it to source control.
A missing or invalid key is rejected with a uniform 401 — see Authentication.

Response shapes

Resource and insights responses are bare — a single object, or a list object. There is no { success, data, error, meta } wrapper. A list response wraps its rows and carries "object": "list". Single-object responses (a campaign, ad group, ad, asset, or ad account) are returned bare — they do not include an object field.
An error response carries a single error object:
type is one of invalid_request_error, authentication_error, rate_limit_error, or server_error.

Money — one scale, two shapes

Every money amount on /v1/ is in integer micros, where $1 = 1,000,000. Resources take and return the raw integer; insights pair each integer with a formatted string.
  • Resource bodies. budget.amount_micros has a minimum of 990000 ($0.99) and no upper cap. bidding_config.max_bid_micros ranges 100–100000000 ($0.0001–$100).
  • Resource reads add a display string. A campaign reads back budget.display — the amount and its period resolved into one string, e.g. "$1,000.00 per week".
  • Insights rows carry spend_micros, cpc_micros, and cpm_micros (same micros scale) each paired with a *_display string ("$0.70"), plus ctr_ratio (a 0–1 fraction) paired with ctr_display ("10.00%").
The *_micros integer is the canonical, parseable value. *_display is for humans — its formatting may change, so never parse it.

Currency

Currency is an account-level invariant: every campaign, ad group, and ad under an account is denominated in the same currency, and writes carry no per-entity currency. GET /ad_account exposes a lowercase ISO currency ("usd"); child resources inherit it. Insights rows carry a per-row currency because they travel as a flat list with no account object to reference.

Timestamps

All /v1/ timestamps — start_time, end_time, created_at, updated_at, archived_at, and the insights time_ranges[] bounds — are ISO 8601 / RFC 3339 strings in UTC, in and out:
No endpoint accepts a Unix integer anywhere. On input, a timestamp must carry a UTC offset or trailing Z — a bare wall-clock time is ambiguous and is rejected with 400 invalid_value rather than assumed to be UTC.

Status and review

Each campaign, ad group, and ad exposes a status, and campaigns and ads expose a read-only review_status.
status is never writable through an update body — not on campaigns, and not on ad groups or ads. Sending status in any update body returns 400 use_status_action. Status moves only through the /activate, /pause, and /archive sub-actions, which validate the transition.
Thrad ad groups and ads have no separate archived state, so /archive on a child deactivates it and it reads back as paused — the same result as /pause.

Pagination

List endpoints are cursor-paginated. The limit range depends on the surface: resource list endpoints (campaigns, ad groups, ads) accept 1–500, while insights list endpoints accept 1–2000. Both default to 20.
integer
default:"20"
Number of items per page. Resource lists: 1–500. Insights lists: 1–2000.
string
Return items before this cursor. Echo a prior response’s first_id. Mutually exclusive with after.
string
Return items after this cursor. Echo a prior response’s last_id. Mutually exclusive with before.
string
default:"desc"
Sort direction: asc or desc.

Rate limits

The API is throttled to 1000 requests per hour per key. The charging POST /v1/campaigns create call is additionally limited to 60 per hour.

Idempotency

POST /v1/campaigns accepts an Idempotency-Key header so a retried create never charges twice.
string
A client-generated key. The same key replays the original response indefinitely — there is no expiry window. The same key with a different body returns 409 idempotency_key_reused; re-sending while the first request is still in flight returns 409 idempotency_key_in_use.

Next steps

Quickstart

Mint a key and create, launch, and read insights for your first campaign with cURL.

Authentication

How the Bearer key works, where to create it, and how to rotate or revoke it.