API Reference

Read and optimize Apple Ads accounts over HTTP.

The REST API exposes the same capabilities as the MCP server over plain HTTP, for the callers MCP can't reach: cron jobs, backend services, automation platforms, and curl.

Base URL: /api/v1. Authenticate with a key from Workspace → Settings → API keys.

curl https://your-app.example.com/api/v1/accounts \
  -H "Authorization: Bearer tsk_your_key"

Four things that will surprise you

Read these before you write any code against this API. Each one is a real property of Apple Ads, not a quirk of ours.

1. Every write is a proposal, not a mutation

A POST to an action endpoint does not change your account. It creates a decision row, and the safe-apply policy then either applies it immediately or queues it for a human:

{
  "actionId": "9f2c…",
  "kind": "budget_change",
  "mode": "queued",
  "riskTier": "review",
  "policyReasons": ["Budget raises above 30% are review-tier."]
}

Both auto_applied and queued are successes. And mode is a snapshot, not an outcome — the apply worker re-runs the policy before touching Apple and can still demote an auto-approved action back to proposed. Poll GET /accounts/{projectId}/actions for terminal state.

See Policy states.

2. We only see what we sync

Apple has no change-events API and no webhooks. Everything this API returns comes from our warehouse, refreshed by a nightly full pull and a six-hourly incremental. So:

  • Changes made in the Apple Ads UI are invisible here until the next sync.
  • The action ledger is our record of our own changes, not an account history.
  • GET /accounts/{projectId}/syncs should be the first call in any automation.

Account-scoped reads carry a dataFreshness object. If it has a warning, relay it — don't act through it.

3. Apple's vocabulary, not Google's

Taps, not clicks. Installs, not conversions. TTR, CPT, CPA. There is no ROAS, quality score, impression share, ad copy, audience or experiment anywhere in this API, because Apple doesn't have them.

Status enums split by entity: campaigns, ad groups and ads are ENABLED|PAUSED, but keywords are ACTIVE|PAUSED. Filtering keywords on ENABLED returns zero rows with no error — a silent bug worth knowing about.

Keywords are EXACT or BROAD only; there is no PHRASE. A storefront is a country.

4. projectId is not Apple's org id

Every account-scoped path takes {projectId} — the project UUID from GET /accounts. Apple's own asaOrgId is returned alongside it but is not addressable. With an account-scoped key you can write the literal current instead:

curl .../api/v1/accounts/current/campaigns -H "Authorization: Bearer tsk_…"

Money is in micros

Any field whose name ends in Micros is in micros: 1,000,000 micros = 1 unit of the account currency, rounded to Apple's 10,000-micro minimum. Every response that carries money also carries the account currency.

What this API can't do

Stated plainly so you don't go looking:

  • Connect an account. There is no Apple Ads OAuth flow and no consent screen. Credentials must be pasted into the dashboard by a person. GET /connection tells you whether that's been done.
  • Mint API keys. A key cannot create keys.
  • Dry-run a change. Apple has no validate_only endpoint and no sandbox. Validation runs locally at propose time and rejects with 422.
  • Bid modifiers. Targeting is set membership; to bid differently on a segment, split it into its own ad group.

Next

On this page