Base URL
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 withads[]) that auto-launches on submit. - Ad Group —
context_hintsand abidding_config.max_bid_micros. Add ad groups to an existing campaign. - Ad — the copy (
cardorpoll) plus a requiredasset_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 theAuthorization 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.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.
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_microshas a minimum of990000($0.99) and no upper cap.bidding_config.max_bid_microsranges100–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, andcpm_micros(same micros scale) each paired with a*_displaystring ("$0.70"), plusctr_ratio(a 0–1 fraction) paired withctr_display("10.00%").
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:
Status and review
Each campaign, ad group, and ad exposes astatus, and campaigns and ads expose a read-only review_status.
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. Thelimit 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 chargingPOST /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.
