> ## 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.

# Assets

> Browse the reusable asset catalog — the images and destination URLs your ads reference by asset_id.

An **asset** is a reusable creative record on your ad account: an image, a destination URL, and (for catalog items) product metadata like brand, price, and availability. Every [ad](https://docs.thrad.ai/advertisers/api-reference/ads.md) references exactly one asset by `asset_id`, and the asset supplies the ad's **image** and **destination URL**.

> [!WARNING]
>
> Assets are **read-only over `/v1/`**. There is no create, update, or delete endpoint, and no inline image upload — the API accepts no image bytes and no image URL anywhere. Create assets in the Thrad Platform dashboard, or let a [product feed](https://docs.thrad.ai/advertisers/feeds/overview.md) populate them for you. Then reference them here by `asset_id`.

> [!NOTE]
>
> All paths are relative to the base URL `https://api.thrad.ai/v1`. Authenticate every request with `Authorization: Bearer ak_...`. See [Authentication](https://docs.thrad.ai/advertisers/api-reference/authentication.md).

## The asset object

**id** `string`

The asset's unique identifier (UUID). This is the value you pass as an ad's `asset_id`.

**name** `string`

Display name. May be an empty string.

**description** `string | null`

Free-text description, or `null`.

**url** `string | null`

The asset's destination URL — where a user lands after clicking. `null` if unset.

> [!NOTE]
>
> A **poll** ad requires an asset that has a `url`; attaching one without it returns `400 invalid_value`. A **card** ad reads its destination from this field too, surfaced on the ad as the read-only `creative.target_url`.

**image\_url** `string | null`

The primary creative image, as a resolved storage URL. For a feed asset whose image has not been ingested yet, this falls back to the merchant-hosted image URL.

**additional\_image\_urls** `string[]`

Any secondary images, as resolved storage URLs. Empty array when there are none.

**tags** `string[]`

Free-form tags on the asset. Empty array when there are none.

**brand** `string | null`

Brand name, or `null`.

**availability** `string | null`

Stock status for a catalog item (e.g. `"in stock"`), or `null`.

**price** `object | null`

The item price as `{ "amount": "49.99", "currency": "USD" }`, or `null` when unpriced. `amount` is a **decimal string**, not micros.

**sale\_price** `object | null`

The discounted price, same shape as `price`, or `null`.

**source** `string`

Where the asset came from: `feed` (synced from a product feed) or `manual` (created in the dashboard).

**created\_at** `string`

Creation time, as an ISO 8601 timestamp in UTC.

**updated\_at** `string`

Last-modified time, as an ISO 8601 timestamp in UTC.

***

## List assets

Returns the asset catalog for your organization, newest first by default.

```
GET /v1/assets
```

**limit** `integer` (default: 20)

Number of assets to return, `1`–`500`.

**order** `string` (default: desc)

Sort direction by creation time: `asc` or `desc`.

**before** `string`

Cursor for the previous page — pass a prior response's `first_id`. Mutually exclusive with `after`.

**after** `string`

Cursor for the next page — pass a prior response's `last_id`. Mutually exclusive with `before`.

```bash cURL theme={null}
curl "https://api.thrad.ai/v1/assets?limit=20" \
  -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": 20},
)
resp.raise_for_status()
for asset in resp.json()["data"]:
    print(asset["id"], asset["name"])
```

```json 200 - List theme={null}
{
  "object": "list",
  "data": [
    {
      "id": "3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83",
      "name": "Pro Racer — Volt",
      "description": "Lightweight racing shoe",
      "url": "https://acme.example.com/products/pro-racer",
      "image_url": "https://cdn.thrad.ai/uploads/2026/04/pro-racer.png",
      "additional_image_urls": [],
      "tags": ["running", "footwear"],
      "brand": "Acme",
      "availability": "in stock",
      "price": { "amount": "149.99", "currency": "USD" },
      "sale_price": { "amount": "119.99", "currency": "USD" },
      "source": "feed",
      "created_at": "2026-03-31T00:00:00.000000Z",
      "updated_at": "2026-04-01T00:00:00.000000Z"
    }
  ],
  "count": 1,
  "first_id": "3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83",
  "last_id": "3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83",
  "has_more": false
}
```

***

## Retrieve an asset

Fetches a single asset by ID.

```
GET /v1/assets/{asset_id}
```

**asset\_id** `string` *required*

The asset UUID. An unknown or cross-organization ID returns `404`.

```bash cURL theme={null}
curl https://api.thrad.ai/v1/assets/3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83 \
  -H "Authorization: Bearer $THRAD_ADS_API_KEY"
```

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

asset_id = "3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83"
resp = requests.get(
    f"https://api.thrad.ai/v1/assets/{asset_id}",
    headers={"Authorization": f"Bearer {os.environ['THRAD_ADS_API_KEY']}"},
)
resp.raise_for_status()
print(resp.json())
```

```json 200 - Asset theme={null}
{
  "id": "3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83",
  "name": "Pro Racer — Volt",
  "description": "Lightweight racing shoe",
  "url": "https://acme.example.com/products/pro-racer",
  "image_url": "https://cdn.thrad.ai/uploads/2026/04/pro-racer.png",
  "additional_image_urls": [],
  "tags": ["running", "footwear"],
  "brand": "Acme",
  "availability": "in stock",
  "price": { "amount": "149.99", "currency": "USD" },
  "sale_price": null,
  "source": "manual",
  "created_at": "2026-03-31T00:00:00.000000Z",
  "updated_at": "2026-04-01T00:00:00.000000Z"
}
```

## Using an asset on an ad

Pass the asset's `id` as `asset_id` when creating an ad — the creative itself carries copy only:

```json theme={null}
{
  "ad_group_id": "9a1f2c3d-4e5f-6789-abcd-ef0123456789",
  "asset_id": "3d9e7b21-5c4a-4f8e-b1d6-7a2c9e0f4b83",
  "creative": {
    "type": "card",
    "title": "Premium Running Shoes",
    "body": "Lightweight and built for marathon pace.",
    "cta": "Shop now"
  }
}
```

> [!TIP]
>
> Re-pointing an ad's `asset_id` moves the creative with it: a poll's destination always re-derives from the new asset, and a card's image re-derives when the image it was showing came from the asset being replaced (so a custom image or a logo fallback survives the swap).

## Errors

Errors use the bare shape `{ "error": { "message", "type", "param", "code" } }`.

| Status | `code` | When |
| - | - | - |
| `400` | `invalid_value` | An ad body's `asset_id` does not match an asset in this account, or (for a poll) the asset has no `url`. |
| `400` | `required` | An ad body omitted `asset_id`. |
| `401` | `auth_required` | The `Authorization` header is missing. |
| `401` | `invalid_api_key` | The key is malformed, unknown, or revoked. |
| `404` | `not_found` | The `asset_id` is unknown or belongs to another organization. |
| `429` | `rate_limit_exceeded` | Exceeded the per-key limit of 1000 requests/hour. |


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