Skip to main content
The Thrad Advertiser API authenticates every request with an organization-bound secret key passed as a Bearer token. Each request carries the access of exactly one organization — there are no user logins, OAuth flows, or session cookies on this API.
Authorization
string
required
Your secret key as a Bearer token: Authorization: Bearer ak_…. Keys are prefixed ak_. There is one active key per organization.
All endpoints are relative to the base URL:
https://api.thrad.ai/v1
Store your key as an environment variable (THRAD_ADS_API_KEY in these docs) and never commit it to source control. The full secret is shown only once, at the moment you create or rotate it.

Making an authenticated request

Send the key in the Authorization header on every call. The canonical check is GET /v1/ad_account, which returns the organization’s default ad account.
curl https://api.thrad.ai/v1/ad_account \
  -H "Authorization: Bearer $THRAD_ADS_API_KEY"
{
  "id": "8f3a1c20-3d2e-4a9b-bf5e-1a2b3c4d5e6f",
  "name": "Acme Inc.",
  "url": "https://acme.example.com",
  "timezone": "UTC",
  "currency_code": "USD"
}
The Advertiser API returns bare OpenAI-style shapes — a single object, or a list as { "object": "list", "data": [...], "count": N, "first_id": "...", "last_id": "...", "has_more": false }. It does not use the { success, data, error, meta } envelope. The only exception is the JWT-side key-management endpoints documented below.

Authentication errors

A missing Authorization header, a malformed header, or an unknown / expired / revoked key all return 401 with the bare error shape. The response is intentionally uniform — the API never reveals why a key was rejected, so it cannot be used as an oracle to distinguish an unknown key from an expired or revoked one.
{
  "error": {
    "message": "Authentication credentials were not provided.",
    "type": "authentication_error",
    "param": null,
    "code": "auth_required"
  }
}
StatusCodeWhen
401 Unauthorizedauth_requiredNo Authorization header was sent.
401 Unauthorizedinvalid_api_keyThe header is malformed, or the key is unknown, expired, or revoked. Also returned once the owning organization is deleted.
A JWT (dashboard session token) can never reach /v1/, and an ak_ key can never reach the internal /api/ surface. Use the ak_ key only against https://api.thrad.ai/v1.

Rate limits

Throttling is per key (not per IP and not per organization), so the two keys that briefly coexist during a rotation each get their own budget.
ScopeLimit
All /v1/ requests1000 / hour per key
POST /v1/campaigns (charging endpoint)60 / hour per key, on top of the 1000/hour bucket
Exceeding a limit returns 429 with type: "rate_limit_error" and code rate_limit_exceeded.
429 Too Many Requests
{
  "error": {
    "message": "Request was throttled.",
    "type": "rate_limit_error",
    "param": null,
    "code": "rate_limit_exceeded"
  }
}

Managing keys

API keys are created and managed from the Thrad Platform dashboard under Settings → API keys. Only organization owners and admins can mint, rotate, or revoke a key.

Create

Mint the organization’s one active key. The secret is shown once.

Rotate

Mint a replacement. The previous key stays valid for a 30-minute grace window.

Revoke

Disable a key immediately, with no grace period.
The management endpoints live outside /v1/, under the internal Platform API at https://api.thrad.ai/api/organizations/{org_public_id}/api-keys/. They are JWT/dashboard-gated (an ak_ key cannot call them) and they speak the platform { success, data, error, meta } envelope — unlike the bare /v1/ surface. Most advertisers never call these directly; the dashboard does it for you.
1

Create or rotate

A POST mints a new key. If an active key already exists, it is rotated: the prior key is kept valid for the grace window, and the new key’s secret is returned once in the response. Copy it immediately — it is never shown again.
2

Store the secret

Save the secret as THRAD_ADS_API_KEY. Subsequent list calls only ever return the masked key_preview, never the full secret.
3

Revoke when done

A DELETE revokes a key immediately. There is no grace period on an explicit revoke — the key stops working that instant.

Create / rotate a key

POST /api/organizations/{org_public_id}/api-keys/
org_public_id
string
required
The organization’s public UUID.
Authorization
string
required
A dashboard JWT (Bearer <jwt>). Owner or admin role required.
name
string
Optional human-readable label for the key (100 characters or fewer).
curl -X POST https://api.thrad.ai/api/organizations/$ORG_ID/api-keys/ \
  -H "Authorization: Bearer $THRAD_JWT" \
  -H "Content-Type: application/json" \
  -d '{ "name": "production" }'
{
  "success": true,
  "data": {
    "api_key": {
      "public_id": "2c9f0a44-7b1e-4d3a-9f02-aa11bb22cc33",
      "name": "production",
      "is_active": true,
      "key_preview": "ak_9bj…7f3c",
      "secret": "ak_9b3a2c8e1f047a5d63b9e0214c7a8f3d5Kio_pQ2zR8vL0pZ6kH1s",
      "last_used": null,
      "expires_at": null,
      "created_at": "2026-04-02T12:00:00Z"
    }
  },
  "error": null,
  "meta": {}
}
secret is returned only on this create/rotate response. After this, list calls expose key_preview only. If you lose the secret, rotate to mint a new one.

List keys

GET /api/organizations/{org_public_id}/api-keys/ Returns the organization’s active key with the secret masked.
curl https://api.thrad.ai/api/organizations/$ORG_ID/api-keys/ \
  -H "Authorization: Bearer $THRAD_JWT"
{
  "success": true,
  "data": {
    "api_keys": [
      {
        "public_id": "2c9f0a44-7b1e-4d3a-9f02-aa11bb22cc33",
        "name": "production",
        "is_active": true,
        "key_preview": "ak_9bj…7f3c",
        "last_used": "2026-04-02T13:00:00Z",
        "expires_at": null,
        "created_at": "2026-04-02T12:00:00Z"
      }
    ]
  },
  "error": null,
  "meta": {}
}

Revoke a key

DELETE /api/organizations/{org_public_id}/api-keys/{key_public_id}/
org_public_id
string
required
The organization’s public UUID.
key_public_id
string
required
The public_id of the key to revoke.
curl -X DELETE \
  https://api.thrad.ai/api/organizations/$ORG_ID/api-keys/$KEY_ID/ \
  -H "Authorization: Bearer $THRAD_JWT"
{
  "success": true,
  "data": {
    "public_id": "2c9f0a44-7b1e-4d3a-9f02-aa11bb22cc33",
    "revoked": true
  },
  "error": null,
  "meta": {}
}
Rotation keeps the old key alive for a 30-minute grace window so an accidental rotation does not break a live integration outright. Revocation is immediate — use it the moment a key is compromised.

Response fields

public_id
string
The key’s public UUID. Use this as {key_public_id} when revoking.
name
string
The label given at creation (may be empty).
is_active
boolean
Whether the key is currently active. A rotated-out key reads false during its grace window; a revoked key reads false immediately.
key_preview
string
Masked preview of the key for display — the first 6 characters, an ellipsis, then the last 4 (e.g. ak_9bj…7f3c). Never the full secret.
secret
string
The full ak_… secret. Returned only on the create/rotate response, never again.
last_used
string
ISO 8601 timestamp (e.g. "2026-04-02T12:00:00Z") of the key’s last authenticated request, or null if never used.
expires_at
string
ISO 8601 timestamp at which the key expires. null for an active key; set to the end of the grace window after a rotation, or to the moment of revocation.
created_at
string
ISO 8601 timestamp when the key was created.