# Spotify Ads API Reference

> This skill should be used when the user asks to "call the Spotify Ads API", "create a Spotify ad campaign", "manage Spotify ads", "pull Spotify ad reports", "set up ad sets or ads", "upload ad assets", "target audiences on Spotify", "check campaign status", "get ad account info", "look up API schema or fields", "check what targeting options exist", or asks about Spotify advertising endpoints, request/response formats, enum values, or authentication.

- Skill: `spotify/spotify-ads-api-reference` (Agent Skill, multi-file: 9 files)
- Install (CLI): `npx skillmds@latest add spotify/spotify-ads-api-reference`
- Raw SKILL.md: https://api.skillmd.com/api/skills/spotify/spotify-ads-api-reference/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: spotify (https://skillmd.com/u/spotify)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/spotify/spotify-ads-api-reference

---


# Spotify Ads API v3 Reference

## Overview

The Spotify Ads API v3 enables programmatic management of advertising campaigns on Spotify. It follows a strict resource hierarchy and uses OAuth 2.0 bearer token authentication.

## Base URL

`https://api-partner.spotify.com/ads/v3`

## Authentication

All requests require a Bearer token and tracking headers:

```
Authorization: Bearer <access_token>
X-Spotify-Ads-Sdk: <sdk-product>/<version>
X-Spotify-Ads-Skill: <skill-name>
```

The request wrapper script (`scripts/api-request.sh`) injects these headers automatically. Skills define a local `api()` function that delegates to the wrapper:

```bash
PLUGIN_ROOT="${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-.}}"
api() { "$PLUGIN_ROOT/scripts/api-request.sh" <skill-name> "$@"; }
```

To set up authentication, run the configure skill (`/spotify-ads-api:configure` on Claude/Codex, `/configure` on Antigravity), which supports OAuth 2.0 with automatic token refresh, manual OAuth, or direct token input.

## Current API Contract

Before answering a schema question or making an Ads API v3 call, read and follow
`references/live-openapi.md`. Fetch the public OpenAPI document once for the workflow and
use the relevant operation and component definitions as the source of truth for paths,
parameters, request bodies, responses, and enums.

## Resource Hierarchy

```
Business
  └── Ad Account
        ├── Campaign
        │     └── Ad Set
        │           └── Ad (references Assets)
        ├── Draft Campaign (staging — not live until published)
        │     └── Draft Ad Set
        │           └── Draft Ad
        ├── Audience
        ├── Asset
        └── Reports
```

Every CRUD operation on campaigns, ad sets, ads, assets, and audiences is scoped under an **ad account ID**.

**Draft workflow (default for campaign hierarchy writes):** Create drafts for new entities or from published entities → edit → validate → publish only after explicit confirmation. Use this flow for campaign, ad set, and ad creation or modification unless the user explicitly requests a direct live write.

For draft `VALIDATE` and `PUBLISH`, always fetch the draft campaign immediately before the action and use its current `draft_hierarchy_version`. `PUBLISH` creates live entities and always requires explicit user confirmation, even when automatic execution is enabled.

## Key Conventions

- **Budgets use micro-amounts**: Multiply values by 1,000,000 (amounts are in the ad account's billing currency). A $50 budget = `50000000` micro-amount.
- **Timestamps**: ISO 8601 in UTC (e.g., `2025-09-23T04:56:07Z`).
- **IDs**: UUID format (e.g., `ce4ff15e-f04d-48b9-9ddf-fb3c85fbd57a`).
- **Pagination**: All list endpoints support `limit` (1-50, default 50) and `offset` (default 0).
- **Sorting**: Most list endpoints support `sort_direction` (ASC/DESC) and entity-specific sort fields.
- **Updates use PATCH**: Partial updates with minimum 1 property required. For campaign, ad set, and ad changes, PATCH the draft endpoint by default.
- **No DELETE on live campaigns/ad sets/ads**: Use status changes (ARCHIVED, PAUSED) instead. Draft entities _can_ be deleted.

## Public Endpoint Groups

### Campaigns
- `POST /ad_accounts/{id}/campaigns` — Create a live campaign (required: name and deprecated `objective`; prefer drafts with `delivery_goal_group`)
- `GET /ad_accounts/{id}/campaigns` — List campaigns (filterable by status, name, IDs)
- `GET /ad_accounts/{id}/campaigns/{campaign_id}` — Get campaign by ID
- `PATCH /ad_accounts/{id}/campaigns/{campaign_id}` — Update campaign (name, status)

### Ad Sets
- `POST /ad_accounts/{id}/ad_sets` — Create ad set (required: name, start_time, budget, asset_format, targets, bid_strategy)
- `GET /ad_accounts/{id}/ad_sets/{ad_set_id}` — Get ad set by ID
- `PATCH /ad_accounts/{id}/ad_sets/{ad_set_id}` — Update ad set

### Ads
- `POST /ad_accounts/{id}/ads` — Create ad (required: name, assets; also needs tagline, advertiser_name, ad_set_id, call_to_action)
- `GET /ad_accounts/{id}/ads` — List ads (filterable by ad_set_ids, campaign_ids, statuses)
- `GET /ad_accounts/{id}/ads/{ad_id}` — Get ad by ID
- `PATCH /ad_accounts/{id}/ads/{ad_id}` — Update ad

### Assets
- `POST /ad_accounts/{id}/assets` — Create asset (image, audio, or video)
- `GET /ad_accounts/{id}/assets` — List assets
- `GET /ad_accounts/{id}/assets/{asset_id}` — Get asset by ID
- `PATCH /ad_accounts/{id}/assets/{asset_id}` — Update asset
- `PATCH /ad_accounts/{id}/assets` — Bulk archive/unarchive

### Audiences
- `POST /ad_accounts/{id}/audiences` — Create audience (CUSTOM or LOOKALIKE)
- `GET /ad_accounts/{id}/audiences` — List audiences
- `GET/PATCH /ad_accounts/{id}/audiences/{audience_id}` — Get or edit an audience
- `DELETE /ad_accounts/{id}/audiences/{audience_id}` — Delete audience
- `POST /ad_accounts/{id}/audiences/upload_url` — Get a signed customer-list upload URL
- `POST /ad_accounts/{id}/audiences/upload_url/{audience_id}` — Replace an audience file
- `GET /ad_accounts/{id}/audiences/datasets` — List datasets eligible for custom audiences

### Measurement Setup
- `GET/POST /businesses/{id}/mobile_apps` — List or register mobile apps
- `GET/PATCH /businesses/{id}/mobile_apps/{mobile_app_id}` — Get or update a mobile app
- `POST/DELETE /businesses/{id}/mobile_apps/{mobile_app_id}/ad_accounts/{ad_account_id}` — Share or unshare an app
- `GET/POST /businesses/{id}/pixels` — List or create Pixels
- `GET/PATCH /businesses/{id}/pixels/{pixel_id}` — Get or update a Pixel
- `POST /businesses/{id}/capi` — Create a CAPI integration
- `GET/PATCH /businesses/{id}/capi/{connection_id}` — Get or update CAPI
- `POST/GET/DELETE /businesses/{id}/capi/{connection_id}/tokens[...]` — Manage CAPI auth tokens
- `GET/POST /businesses/{id}/datasets` — List or create datasets
- `GET/PATCH /businesses/{id}/datasets/{dataset_id}` — Get or update a dataset
- `GET /businesses/{id}/datasets/{dataset_id}/diagnostics` — Inspect received events
- `POST/DELETE /businesses/{id}/datasets/{dataset_id}/ad_accounts/{ad_account_id}` — Share or unshare a dataset

### Account Administration
- `GET/POST /businesses` — List or create businesses
- `GET/PATCH /businesses/{id}` — Get or update a business
- `GET /businesses/{id}/members` — List members and invited users
- `GET/PATCH/DELETE /businesses/{id}/members/{member_id}` — Inspect, edit, or remove a member
- `PATCH /businesses/{id}/members/{member_id}/role` — Update a business role
- `GET/POST /businesses/{id}/invitations` — List or create invitations
- `DELETE /businesses/{id}/invitations/{invitation_id}` — Cancel an invitation
- `GET/POST /businesses/{id}/ad_accounts` — List or create ad accounts
- `GET/PATCH /ad_accounts/{id}` — Get or update supported ad-account fields
- `GET/POST /ad_accounts/{id}/members` — List or add ad-account members
- `PATCH/DELETE /ad_accounts/{id}/members/{member_id}` — Update a role or remove access

### Reports
- `GET /ad_accounts/{id}/aggregate_reports` — Aggregated metrics by entity
- `GET /ad_accounts/{id}/insight_reports` — Audience insight breakdowns
- `POST /ad_accounts/{id}/async_reports` — Create async CSV report
- `GET /ad_accounts/{id}/async_reports/{report_id}` — Check async report status

### Drafts (Default for Campaign Hierarchy Writes)

Draft entities are staging versions that are not live until explicitly published. The full lifecycle:
create drafts → edit → validate → publish.

For changes to published campaigns, ad sets, or ads, first check whether a same-ID draft already exists. Reuse and disclose an existing draft rather than recreating or overwriting pending work. If none exists, use the create-from-published endpoint, PATCH the draft endpoint, and validate the parent draft campaign. A denied direct write does not by itself mean the credentials are read-only; draft staging may still be available.

**Campaign drafts:**
- `POST /ad_accounts/{id}/drafts/campaigns` — Create draft campaign
- `GET /ad_accounts/{id}/drafts/campaigns` — List draft campaigns
- `GET /ad_accounts/{id}/drafts/campaigns/{draft_id}` — Get draft campaign
- `PATCH /ad_accounts/{id}/drafts/campaigns/{draft_id}` — Update draft campaign
- `POST /ad_accounts/{id}/drafts/campaigns/{draft_id}` — Publish or validate (body: `{"action": "PUBLISH"|"VALIDATE", "draft_hierarchy_version": N}`)
- `DELETE /ad_accounts/{id}/drafts/campaigns/{draft_id}` — Delete draft campaign

**Ad set drafts:**
- `POST /ad_accounts/{id}/drafts/ad_sets` — Create draft ad set (requires `campaign_id` referencing a draft campaign)
- `GET /ad_accounts/{id}/drafts/ad_sets` — List draft ad sets
- `GET /ad_accounts/{id}/drafts/ad_sets/{draft_id}` — Get draft ad set
- `PATCH /ad_accounts/{id}/drafts/ad_sets/{draft_id}` — Update draft ad set
- `DELETE /ad_accounts/{id}/drafts/ad_sets/{draft_id}` — Delete draft ad set

**Ad drafts:**
- `POST /ad_accounts/{id}/drafts/ads` — Create draft ad (requires `ad_set_id` referencing a draft ad set)
- `GET /ad_accounts/{id}/drafts/ads` — List draft ads
- `GET /ad_accounts/{id}/drafts/ads/{draft_id}` — Get draft ad
- `PATCH /ad_accounts/{id}/drafts/ads/{draft_id}` — Update draft ad
- `DELETE /ad_accounts/{id}/drafts/ads/{draft_id}` — Delete draft ad

**Create draft from published entity:**
- `POST /ad_accounts/{id}/campaigns/{campaign_id}/drafts` — Draft from live campaign
- `POST /ad_accounts/{id}/ad_sets/{ad_set_id}/drafts` — Draft from live ad set
- `POST /ad_accounts/{id}/ads/{ad_id}/drafts` — Draft from live ad

### Other Public Endpoints
- `GET/PATCH /ad_accounts/{id}` — Get/update ad account
- `POST/GET /businesses` — Create/list businesses
- `GET /businesses/{id}` — Get business by ID
- `GET /targets/artists` — Search artist targets
- `GET /ad_categories` — List ad categories
- `GET /ad_product_catalog` — Get live product-specific validation rules for AUCTION, CONTENT, and FPMNG. Fetch once per create or update workflow and do not retain a timed cross-operation cache. Follow `references/ad-product-validation.md` before mutating campaigns, ad sets, or ads.
- `POST /estimates/audience` — Estimate audience size for targeting parameters (recommended before creating ad sets to validate reach)
- `POST /estimates/bid` — Get bid recommendations
- `POST /ad_accounts/{id}/reserved_prices` — Get pricing for reserved ad products (fCPM)
- `GET /ad_accounts/{id}/experiment_availability` — Check which experiment types can be created

## Making API Calls

All skills use the request wrapper script (`scripts/api-request.sh`) which handles settings discovery, authentication, and tracking headers automatically:

```bash
PLUGIN_ROOT="${CODEX_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-.}}"
api() { "$PLUGIN_ROOT/scripts/api-request.sh" <skill-name> "$@"; }

# GET
api GET "ad_accounts/{ad_account_id}/campaigns?limit=50"

# Draft-first POST with JSON body
api POST "ad_accounts/{ad_account_id}/drafts/campaigns" '{"name":"...","delivery_goal_group":"AWARENESS"}'

# Retrieve settings values for use outside API calls
eval $(api --env)
```

The wrapper reads the user's plugin settings from the active platform settings file (with platform-ordered fallback), reads the plugin version from the platform manifest, and injects `Authorization`, `X-Spotify-Ads-Sdk`, and `X-Spotify-Ads-Skill` headers. It appends `\nHTTP_STATUS:<code>` to every response. Paths use `{ad_account_id}` as a placeholder (auto-substituted from settings).

If the settings file does not exist, the wrapper exits with an error. Instruct the user to run the configure skill first (`/spotify-ads-api:configure` on Claude/Codex, `/configure` on Gemini).

<details>
<summary>Raw curl equivalent (for debugging or non-standard requests)</summary>

```bash
curl -s -w "\nHTTP_STATUS:%{http_code}" -X GET \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "X-Spotify-Ads-Sdk: <sdk-product>/<version>" \
  -H "X-Spotify-Ads-Skill: <skill-name>" \
  "https://api-partner.spotify.com/ads/v3/ad_accounts/$AD_ACCOUNT_ID/campaigns?limit=50"
```

</details>

For error response format and common HTTP status codes, see `references/endpoints.md` (Error Responses section).

## Additional Resources

### Reference Files

For detailed request/response schemas and field definitions, consult:
- **`references/live-openapi.md`** — Mandatory workflow for fetching and inspecting the current public OpenAPI document
- **`references/endpoints.md`** — Complete endpoint details with all parameters and response schemas
- **`references/schemas.md`** — Request/response body schemas with field types, constraints, and required fields
- **`references/enums.md`** — All enum values for status fields, asset formats, targeting options, report dimensions/metrics
- **`references/ad-product-validation.md`** — Mandatory catalog-validation procedure for campaign, ad set, and ad mutations

### Example Files

Working examples with complete curl commands and expected responses:
- **`examples/full-campaign-flow.md`** — End-to-end: create campaign, ad set, and ad with targeting
- **`examples/aggregate-report.md`** — Pull aggregate metrics and create async CSV reports

