> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thrad.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Create your API key, pick a creative asset, launch a campaign in one nested call, and read performance — end to end with cURL.

This guide takes you from zero to a live campaign on the Thrad Advertiser API. You'll create a key, confirm access, pick a creative asset, launch a campaign in a single nested call, manage delivery, and read performance.

All paths are relative to the base URL:

```
https://api.thrad.ai/v1
```

Every request is authenticated with your organization's API key as a Bearer token:

```
Authorization: Bearer ak_...
```

> [!NOTE]
>
> Every amount in this API — budgets, bids, and insights spend — is in **integer micros** (`$1 = 1,000,000`). Insights additionally pair each `*_micros` value with a formatted `*_display` string. Every timestamp is an **ISO 8601 string** in UTC (`2026-04-02T00:00:00Z`), never a Unix integer.

> [!TIP]
>
> Selling physical products? Connect a **[product feed](https://docs.thrad.ai/advertisers/feeds/overview.md)** in the Thrad Platform so your catalog becomes ad-ready assets — and out-of-stock items pause themselves.

**1. Create your API key**

In the Thrad Platform dashboard, go to **Settings → API keys** and create a key. Your organization has **one active key**; the secret (`ak_...`) is shown **once** at creation — copy it immediately.

Export it so the cURL examples below can reuse it:

```bash theme={null}
export THRAD_ADS_API_KEY="ak_your_key_here"
```

> [!WARNING]
>
> Treat the key like a password. If it leaks, rotate it from **Settings → API keys** — rotation keeps the previous key valid for a short grace period, then it stops working.

**2. Confirm access**

Fetch your organization's default ad account. A `200` confirms the key works and shows the account your campaigns will live under.

```bash cURL theme={null}
curl https://api.thrad.ai/v1/ad_account \
  -H "Authorization: Bearer $THRAD_ADS_API_KEY"
```

```python Python theme={null}
import os, requests

resp = requests.get(
    "https://api.thrad.ai/v1/ad_account",
    headers={"Authorization": f"Bearer {os.environ['THRAD_ADS_API_KEY']}"},
)
resp.raise_for_status()
print(resp.json())
```

```json 200 OK theme={null}
{
  "id": "8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
  "name": "Acme Inc.",
  "url": "https://acme.example.com",
  "timezone": "UTC",
  "currency": "usd"
}
```

If the key is missing or invalid, you get a bare `401`:

```json 401 Unauthorized theme={null}
{
  "error": {
    "message": "Invalid API key.",
    "type": "authentication_error",
    "param": null,
    "code": "invalid_api_key"
  }
}
```

**3. Pick a creative asset**

Ads don't carry images — they reference an **asset**, which supplies the image and the destination URL. List your account's assets and copy the `id` of the one you want.

```bash cURL theme={null}
curl "https://api.thrad.ai/v1/assets?limit=5" \
  -H "Authorization: Bearer $THRAD_ADS_API_KEY"
```

```python Python theme={null}
import os, requests

resp = requests.get(
    "https://api.thrad.ai/v1/assets",
    headers={"Authorization": f"Bearer {os.environ['THRAD_ADS_API_KEY']}"},
    params={"limit": 5},
)
resp.raise_for_status()
for asset in resp.json()["data"]:
    print(asset["id"], asset["name"], asset["image_url"])
```

```json 200 OK theme={null}
{
  "object": "list",
  "data": [
    {
      "id": "3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83",
      "name": "Pro Racer — Volt",
      "url": "https://acme.example.com/products/pro-racer",
      "image_url": "https://cdn.thrad.ai/uploads/2026/04/pro-racer.png",
      "source": "feed"
    }
  ],
  "count": 1,
  "has_more": false
}
```

> [!WARNING]
>
> The API is **read-only** on assets — there is no upload endpoint and no inline image anywhere. Create assets in the Thrad Platform dashboard, or connect a [product feed](https://docs.thrad.ai/advertisers/feeds/overview.md) to populate them automatically.

> [!NOTE]
>
> Billing must be set up before the next step. Your campaign launch charges a deposit on the organization's **default card** — add one in the Platform dashboard first, or the create call returns `400 billing_not_configured` (with no charge).

**4. Create and launch a campaign**

Create the whole campaign tree — campaign, one ad group, one card ad — in a **single nested call**. Use the `asset_id` from Step 3 on the ad.

This call:

* requires a **default card** on the org (else `400 billing_not_configured`, no charge),
* atomically creates the campaign, ad group, and ad,
* **charges a \$10 deposit off-session** on the default card,
* submits the campaign to review.

Budgets and bids are **integer micros** (`$1 = 1,000,000`). The example below sets a `$25.00` budget (`25000000`) with `period: "lifetime"` — a single cumulative cap — and a `$2.00` max bid (`2000000`). The minimum budget is `990000` (`$0.99`); `max_bid_micros` accepts `100`–`100000000` (`$0.0001`–`$100`).

> [!WARNING]
>
> `budget.period` is required, and it decides how the amount is enforced. `"lifetime"` is a one-time cap. Any other value (`daily`, `weekly`, `monthly`, `quarterly`, `yearly`) means the budget **resets every window with no cumulative ceiling** — a `weekly` $25 campaign spends up to $25 every week until you stop it.

Pass an `Idempotency-Key` header so a retried request never charges twice.

```bash cURL theme={null}
curl https://api.thrad.ai/v1/campaigns \
  -H "Authorization: Bearer $THRAD_ADS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3f6c1a90-1d2e-4b8a-9c7f-0a1b2c3d4e5f" \
  -d '{
    "name": "Summer launch",
    "description": "Q3 awareness push",
    "budget": { "amount_micros": 25000000, "period": "lifetime" },
    "targeting": { "locations": { "include": [ { "country_code": "US" } ] } },
    "ad_groups": [
      {
        "name": "Core audience",
        "context_hints": ["running shoes", "marathon training"],
        "bidding_config": { "max_bid_micros": 2000000 },
        "ads": [
          {
            "name": "Hero card",
            "asset_id": "3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83",
            "creative": {
              "type": "card",
              "title": "Premium Running Shoes",
              "body": "Lightweight and built for the long run."
            }
          }
        ]
      }
    ]
  }'
```

```python Python theme={null}
import os, requests

resp = requests.post(
    "https://api.thrad.ai/v1/campaigns",
    headers={
        "Authorization": f"Bearer {os.environ['THRAD_ADS_API_KEY']}",
        "Idempotency-Key": "3f6c1a90-1d2e-4b8a-9c7f-0a1b2c3d4e5f",
    },
    json={
        "name": "Summer launch",
        "description": "Q3 awareness push",
        "budget": {"amount_micros": 25000000, "period": "lifetime"},
        "targeting": {"locations": {"include": [{"country_code": "US"}]}},
        "ad_groups": [
            {
                "name": "Core audience",
                "context_hints": ["running shoes", "marathon training"],
                "bidding_config": {"max_bid_micros": 2000000},
                "ads": [
                    {
                        "name": "Hero card",
                        "asset_id": "3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83",
                        "creative": {
                            "type": "card",
                            "title": "Premium Running Shoes",
                            "body": "Lightweight and built for the long run.",
                        },
                    }
                ],
            }
        ],
    },
)
resp.raise_for_status()
print(resp.json())
```

```json 201 Created theme={null}
{
  "id": "c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6a7b",
  "name": "Summer launch",
  "description": "Q3 awareness push",
  "status": "paused",
  "review_status": "in_review",
  "budget": {
    "amount_micros": 25000000,
    "period": "lifetime",
    "display": "$25.00 lifetime"
  },
  "targeting": {
    "locations": {
      "include": [ { "id": "US", "type": "country", "country_code": "US" } ]
    }
  },
  "pricing_model": "cpm",
  "start_time": "2026-04-04T00:00:00.000000Z",
  "end_time": null,
  "archived_at": null,
  "created_at": "2026-04-02T00:00:00.000000Z",
  "updated_at": "2026-04-02T00:00:00.000000Z"
}
```

The campaign is now **submitted to review**: it reads back as `status: "paused"` with `review_status: "in_review"`. The \$10 deposit has been charged. There is no draft state — if the card is declined, the call returns `402 card_declined` and the campaign is removed.

The ad group and ad created by this call read `status: "paused"` too, so nothing serves before approval. They flip back to `active` on their own once the campaign is approved — you don't need to activate them.

The request omitted `start_time`, so it defaults to **\~2 days in the future** (the earliest allowed launch window) — the response shows that computed timestamp. Omitting `end_time` leaves it `null`, so this lifetime budget simply spends until it is exhausted.

> [!WARNING]
>
> A second `POST /v1/campaigns` with the **same** `Idempotency-Key` replays the original response (there is no expiry window). The same key with a **different** body returns `409 idempotency_key_reused`.

**5. Manage delivery once approved**

Thrad reviews the campaign. Once it's approved (`review_status` becomes `approved`), you control delivery with the status actions. Sending `status` in an update body is rejected (`400 use_status_action`) — always use these endpoints.

Pause a running campaign:

```bash theme={null}
curl -X POST https://api.thrad.ai/v1/campaigns/c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6a7b/pause \
  -H "Authorization: Bearer $THRAD_ADS_API_KEY"
```

Resume a paused campaign:

```bash theme={null}
curl -X POST https://api.thrad.ai/v1/campaigns/c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6a7b/activate \
  -H "Authorization: Bearer $THRAD_ADS_API_KEY"
```

```json 200 OK theme={null}
{
  "id": "c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6a7b",
  "name": "Summer launch",
  "status": "active",
  "review_status": "approved",
  "updated_at": "2026-04-02T01:00:00.000000Z"
}
```

> [!NOTE]
>
> `/activate` only **resumes** a paused, approved campaign — it never launches one. Calling it on a campaign still in review returns `400 campaign_not_approved`. Calling `/pause` on a campaign that isn't running returns `400 campaign_not_running`. `/archive` ends a running or paused campaign.

**6. Read performance**

Fetch metrics for the campaign. Insights default to the trailing 30-day window and combine **Thrad + ChatGPT (OpenAI Ads)** supply.

```bash theme={null}
curl "https://api.thrad.ai/v1/campaigns/c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6a7b/insights?fields[]=impressions&fields[]=clicks&fields[]=spend_micros&fields[]=ctr_ratio&fields[]=cpc_micros&fields[]=cpm_micros" \
  -H "Authorization: Bearer $THRAD_ADS_API_KEY"
```

```json 200 OK theme={null}
{
  "object": "list",
  "data": [
    {
      "id": "start=1775088000:end=1775174400:entity_id=c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6a7b",
      "start_time": "2026-04-02T00:00:00.000000Z",
      "end_time": "2026-04-03T00:00:00.000000Z",
      "readable_time": "2026-04-02",
      "timezone": "UTC",
      "currency": "usd",
      "campaign_id": "c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6a7b",
      "campaign_name": "Summer launch",
      "impressions": 500,
      "clicks": 50,
      "spend_micros": 700000,
      "spend_display": "$0.70",
      "ctr_ratio": 0.1,
      "ctr_display": "10.00%",
      "cpc_micros": 14000,
      "cpc_display": "$0.014",
      "cpm_micros": 1400000,
      "cpm_display": "$1.40"
    }
  ],
  "count": 1,
  "first_id": "start=1775088000:end=1775174400:entity_id=c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6a7b",
  "last_id": "start=1775088000:end=1775174400:entity_id=c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6a7b",
  "has_more": false
}
```

> [!NOTE]
>
> Ask for metrics by their **output field name** — `spend_micros`, `cpc_micros`, `cpm_micros`, `ctr_ratio` — the same names you get back and the same ones you use in `filters[]` and `sort[]`. Each arrives with a formatted `*_display` companion for showing to people; parse the `*_micros` integer.

## Next steps

> [card] [Authentication](https://docs.thrad.ai/advertisers/api-reference/authentication.md)
>
> Bearer keys, one active key per org, rotation, and error shapes.

> [card] [Campaigns](https://docs.thrad.ai/advertisers/api-reference/campaigns.md)
>
> Full nested-create schema, updates, and status actions.

> [card] [Insights](https://docs.thrad.ai/advertisers/api-reference/insights.md)
>
> Granularity, aggregation levels, fields, filters, segments, and supply splits.

> [card] [Product feeds](https://docs.thrad.ai/advertisers/feeds/overview.md)
>
> Sync your catalog over SFTP so products become ad assets that pause and resume with stock.

## Rate limits

| Limit | Scope |
| - | - |
| `1000` requests / hour | Per API key, across all `/v1/` endpoints |
| `60` requests / hour | Additional limit on the charging `POST /v1/campaigns` |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.