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:
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 =
50000000micro-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) andoffset(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 deprecatedobjective; prefer drafts withdelivery_goal_group)GET /ad_accounts/{id}/campaigns— List campaigns (filterable by status, name, IDs)GET /ad_accounts/{id}/campaigns/{campaign_id}— Get campaign by IDPATCH /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 IDPATCH /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 IDPATCH /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 assetsGET /ad_accounts/{id}/assets/{asset_id}— Get asset by IDPATCH /ad_accounts/{id}/assets/{asset_id}— Update assetPATCH /ad_accounts/{id}/assets— Bulk archive/unarchive
Audiences
POST /ad_accounts/{id}/audiences— Create audience (CUSTOM or LOOKALIKE)GET /ad_accounts/{id}/audiences— List audiencesGET/PATCH /ad_accounts/{id}/audiences/{audience_id}— Get or edit an audienceDELETE /ad_accounts/{id}/audiences/{audience_id}— Delete audiencePOST /ad_accounts/{id}/audiences/upload_url— Get a signed customer-list upload URLPOST /ad_accounts/{id}/audiences/upload_url/{audience_id}— Replace an audience fileGET /ad_accounts/{id}/audiences/datasets— List datasets eligible for custom audiences
Measurement Setup
GET/POST /businesses/{id}/mobile_apps— List or register mobile appsGET/PATCH /businesses/{id}/mobile_apps/{mobile_app_id}— Get or update a mobile appPOST/DELETE /businesses/{id}/mobile_apps/{mobile_app_id}/ad_accounts/{ad_account_id}— Share or unshare an appGET/POST /businesses/{id}/pixels— List or create PixelsGET/PATCH /businesses/{id}/pixels/{pixel_id}— Get or update a PixelPOST /businesses/{id}/capi— Create a CAPI integrationGET/PATCH /businesses/{id}/capi/{connection_id}— Get or update CAPIPOST/GET/DELETE /businesses/{id}/capi/{connection_id}/tokens[...]— Manage CAPI auth tokensGET/POST /businesses/{id}/datasets— List or create datasetsGET/PATCH /businesses/{id}/datasets/{dataset_id}— Get or update a datasetGET /businesses/{id}/datasets/{dataset_id}/diagnostics— Inspect received eventsPOST/DELETE /businesses/{id}/datasets/{dataset_id}/ad_accounts/{ad_account_id}— Share or unshare a dataset
Account Administration
GET/POST /businesses— List or create businessesGET/PATCH /businesses/{id}— Get or update a businessGET /businesses/{id}/members— List members and invited usersGET/PATCH/DELETE /businesses/{id}/members/{member_id}— Inspect, edit, or remove a memberPATCH /businesses/{id}/members/{member_id}/role— Update a business roleGET/POST /businesses/{id}/invitations— List or create invitationsDELETE /businesses/{id}/invitations/{invitation_id}— Cancel an invitationGET/POST /businesses/{id}/ad_accounts— List or create ad accountsGET/PATCH /ad_accounts/{id}— Get or update supported ad-account fieldsGET/POST /ad_accounts/{id}/members— List or add ad-account membersPATCH/DELETE /ad_accounts/{id}/members/{member_id}— Update a role or remove access
Reports
GET /ad_accounts/{id}/aggregate_reports— Aggregated metrics by entityGET /ad_accounts/{id}/insight_reports— Audience insight breakdownsPOST /ad_accounts/{id}/async_reports— Create async CSV reportGET /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 campaignGET /ad_accounts/{id}/drafts/campaigns— List draft campaignsGET /ad_accounts/{id}/drafts/campaigns/{draft_id}— Get draft campaignPATCH /ad_accounts/{id}/drafts/campaigns/{draft_id}— Update draft campaignPOST /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 (requirescampaign_idreferencing a draft campaign)GET /ad_accounts/{id}/drafts/ad_sets— List draft ad setsGET /ad_accounts/{id}/drafts/ad_sets/{draft_id}— Get draft ad setPATCH /ad_accounts/{id}/drafts/ad_sets/{draft_id}— Update draft ad setDELETE /ad_accounts/{id}/drafts/ad_sets/{draft_id}— Delete draft ad set
Ad drafts:
POST /ad_accounts/{id}/drafts/ads— Create draft ad (requiresad_set_idreferencing a draft ad set)GET /ad_accounts/{id}/drafts/ads— List draft adsGET /ad_accounts/{id}/drafts/ads/{draft_id}— Get draft adPATCH /ad_accounts/{id}/drafts/ads/{draft_id}— Update draft adDELETE /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 campaignPOST /ad_accounts/{id}/ad_sets/{ad_set_id}/drafts— Draft from live ad setPOST /ad_accounts/{id}/ads/{ad_id}/drafts— Draft from live ad
Other Public Endpoints
GET/PATCH /ad_accounts/{id}— Get/update ad accountPOST/GET /businesses— Create/list businessesGET /businesses/{id}— Get business by IDGET /targets/artists— Search artist targetsGET /ad_categories— List ad categoriesGET /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. Followreferences/ad-product-validation.mdbefore 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 recommendationsPOST /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:
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).
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"
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 documentreferences/endpoints.md— Complete endpoint details with all parameters and response schemasreferences/schemas.md— Request/response body schemas with field types, constraints, and required fieldsreferences/enums.md— All enum values for status fields, asset formats, targeting options, report dimensions/metricsreferences/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 targetingexamples/aggregate-report.md— Pull aggregate metrics and create async CSV reports