← all adapters

apple-searchads-style

simulates Apple Search Ads API v4

restadapter v0.1.012 routes

verification

VMVM tier — no SDK suite yet· surface 12 · not implemented 4 · differs 5

use it

# add to stunt.yaml
services:
  apple-searchads:
    adapter: embedded:apple-searchads-style

# then
$ stunt up

The embedded: source extracts this adapter from the binary — no git clone, fully offline.

how to mock the Apple Search Ads API locally

Install stunt, paste the service block above into stunt.yaml, run stunt up — then point your client at localhost instead of Apple Search Ads API. It works offline, keeps state across requests and restarts, and every response is synthetic: the route shapes, status codes, pagination, and webhook delivery follow the real Apple Search Ads API v4 surface — the data is fake, the behavior is real.

backing stores

campaignsadskeywords

api surface (12)

generated from the adapter manifest — exactly what boots, nothing more

12 routes
POST/api/oauth2/token
POST/api/v4/campaigns/find
POST/api/v4/campaigns
POST/api/v4/reports/campaigns
GET/api/v4/campaigns/{campaign_id}
PUT/api/v4/campaigns/{campaign_id}
POST/api/v4/campaigns/{campaign_id}/ads
POST/api/v4/campaigns/{campaign_id}/keywords/targeting/find
PUT/api/v4/campaigns/{campaign_id}/keywords/targeting/bulk
POST/api/v4/campaigns/{campaign_id}/keywords/targeting
PUT/api/v4/campaigns/{campaign_id}/keywords/targeting/{keyword_id}
DELETE/api/v4/campaigns/{campaign_id}/keywords/targeting/{keyword_id}

VM-verified behaviors (23)

  • a missing, malformed or unknown bearer is a 401 in the Search Ads envelope
  • the seeded static test token passes the gate
  • a client_credentials exchange mints a bearer valid for exactly one hour
  • malformed grants and client secrets are oauth-shaped 400s
  • campaign create assigns a numeric id and fills the v4 defaults
  • create without a name is a 400
  • the campaign reads back by numeric id; unknown ids are 404s
  • update merges fields, maps status onto servingStatus, and bumps only modificationTime
  • an invalid status is a 400 that writes nothing
  • ad groups create under a campaign; unknown campaigns are 404s
  • find lists the seed with default pagination and clock-derived stamps
  • conditions filter with EQUALS, CONTAINS and amount ranges
  • values within one condition are OR'd; multi-value NOT_EQUALS excludes all
  • orderBy sorts and pagination slices with totalResults before the slice
  • first touch seeds three keywords scoped to the campaign
  • keyword find speaks the same selector (conditions, orderBy, pagination)
  • create takes a single keyword or a batch body
  • single update merges partial fields and validates them
  • bulk update takes id-addressed rows; an unknown id 404s the batch
  • delete removes the keyword and find no longer sees it
  • startTime, endTime and groupBy are validated
  • one row per campaign with deterministic metrics and summed grandTotals
  • the report selector filters rows and grandTotals follow

Not implemented (4)

  • No ad group find or update — only POST campaigns/{id}/ads create
  • No negative keywords endpoints (keywords/negative find/create/update)
  • No search-terms, keyword, or ads reports — only /reports/campaigns
  • No audience targeting, geo/demographic dimensions, or bid adjustments

Differs from the real API (5)

  • ES256 client-secret JWT is not signature-verified — structural checks only
  • Reports group by campaign only; any other groupBy key returns 400
  • Selector conditions cover a fixed field set per resource (id, name, budget, status, times)
  • Bulk keyword update is non-atomic: rows before an unknown id persist though the batch 404s
  • Unknown selector condition fields are silently ignored; real find/report 400s
want more of the Apple Search Ads API surface? adapters are YAML + Starlark — the authoring guide covers adding routes, fixtures, and state machines. Open an issue for anything big first, or just file a PR — merged routes ship in the next release.