chat_card— an in-chat sponsored message (title, body, CTA, image).poll— a Thrad-only sponsored poll (question + 2–4 options + click-through URL).
All paths are relative to the base URL
https://api.thrad.ai/v1. Authenticate every request with Authorization: Bearer ak_.... See Authentication.The ad object
The ad’s unique identifier (UUID).
The UUID of the ad group this ad belongs to.
Human-readable ad name. When omitted on create, it defaults to the creative title (card headline or poll question).
One of
active, paused, or archived. Change it through /activate, /pause, and /archive, or by sending status in an update body.Thrad ads have no separate archived state. Sending
status: archived (or calling /archive) deactivates the ad, so it reads back as paused. A newly created ad is active.Read-only review state inherited from the parent campaign:
approved, in_review, or rejected. You cannot set this — it reflects where the campaign sits in Thrad’s approval flow.The ad creative. Shape depends on
type.List ads
GET /v1/ads
Lists the ads in a single ad group. ad_group_id is required — there is no all-ads listing.
The UUID of the ad group whose ads to list.
Number of ads to return,
1–500.Cursor for the previous page — pass a prior response’s
first_id. Mutually exclusive with after.Cursor for the next page — pass a prior response’s
last_id. Mutually exclusive with before.Sort order by creation time:
asc or desc.Create an ad
POST /v1/ads
Adds an ad to an existing ad group. The creative type must match the ad group’s type, or the request is rejected with 400 invalid_value on creative.type.
The UUID of the ad group to add this ad to.
Ad name. Defaults to the creative title (card headline or poll question) when omitted.
Chat cards only. When
true, Thrad’s AI generates the card copy, so creative.title and creative.body become optional. Setting auto_generate on a poll creative is rejected with poll_cannot_be_ai.The ad creative. Its
type must match the ad group.Retrieve an ad
GET /v1/ads/{ad_id}
The UUID of the ad to retrieve.
Update an ad
POST /v1/ads/{ad_id}
Patches the ad’s name, creative, and/or status. Only the fields you send are changed.
The UUID of the ad to update.
New ad name.
A replacement creative. It must match the ad group’s type and follow the same field rules as on create (card
title ≤ 30; poll title ≤ 120 with 2–4 options and a target_url). For card creatives, send a new file_id or image_url to swap the image.Activate an ad
POST /v1/ads/{ad_id}/activate
Reactivates a paused ad. The parent campaign must be approved.
The UUID of the ad to activate.
Pause an ad
POST /v1/ads/{ad_id}/pause
Deactivates the ad.
The UUID of the ad to pause.
Archive an ad
POST /v1/ads/{ad_id}/archive
Thrad ads have no distinct archived state, so
/archive deactivates the ad and it reads back as paused — the same result as /pause. This is a deliberate divergence from OpenAI’s surface.The UUID of the ad to archive.
Errors
Errors use the bare shape{ "error": { "message", "type", "param", "code" } }.
| Code | HTTP | When |
|---|---|---|
required | 400 | A required field is missing (e.g. card title when not auto-generated, poll title / target_url). |
invalid_value | 400 | creative.type doesn’t match the ad group’s type, a missing or non-object creative, an unknown creative.type, or poll options not a list of 2–4. |
string_too_long | 400 | Card title over 30 characters, or poll title over 120 characters. |
poll_cannot_be_ai | 400 | auto_generate set on a poll creative — AI polls are not supported. |
not_found | 404 | The ad or ad group doesn’t exist or belongs to another organization. |
rate_limit_exceeded | 429 | Over the 1000-requests/hour per-key limit. |
