Skip to content
Reference

REST API

The same account your assistant uses, over HTTPS. Every call sends an API key as a Bearer token; the dashboard, the connector, and the API all share one account model.

Updated
On this page

Base URL and keys

The API lives at https://api.adprimezero.com. Authenticate with an ak_... key from API keys in the dashboard, sent as authorization: Bearer ak_.... Store the key in your secret store only; never print it, commit it, or put it in a web page.

Send a normal User-Agent, for example your-agent-name/1.0. Cloudflare can reject anonymous runtime defaults such as Python's urllib fingerprint before the request reaches the API.

Environment
export ADP_ZERO_API_URL="https://api.adprimezero.com"
export ADP_ZERO_API_KEY="ak_..."   # from your secret store, never hard-coded

Discover the service

The API root returns a small discovery document. Assistants that connect over MCP read the full tool list from https://mcp.adprimezero.com/mcp; the tool reference lists every tool and its parameters.

Discovery
curl -sS "$ADP_ZERO_API_URL/" -H 'user-agent: your-agent-name/1.0'

# OAuth discovery for MCP clients (they read this after a 401 from /mcp):
curl -sS https://mcp.adprimezero.com/.well-known/oauth-protected-resource/mcp

Create or connect an account

The dashboard creates a buyer account and uses the same API-key permission model as the connector and direct API calls. Scripts do not need a dashboard session for ordinary API work; they authenticate with the key.

Connect an assistant instead

Most people never call the API by hand: they add the hosted connector to Claude, ChatGPT, Cursor, Claude Code, or VS Code, and the app opens a browser sign-in (OAuth with PKCE). The person signs in with an emailed code and clicks Allow, and the app receives its own key, revocable from the dashboard. Setup for each app is on Connect your assistant. Clients that cannot open a browser send a stored key as a Bearer header instead.

Hosted connector config
{
  "mcpServers": {
    "adprime-zero": { "url": "https://mcp.adprimezero.com/mcp" }
  }
}
Check it from a terminal
# Without a browser, send a key instead of signing in:
curl -s https://mcp.adprimezero.com/mcp \
  -H "authorization: Bearer $ADP_ZERO_API_KEY" \
  -H 'user-agent: your-agent-name/1.0' \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Add funds

Request a funding link and open it for the person. For external-agent keys the link opens Adprime Zero sign-in with the account email filled in; after the person verifies with an email code (or a password, if they set one), the browser continues to Stripe Checkout. Continue from the returned funding intent and the account balance once it completes. Wallet and billing explains the money side.

Request a payment link
# Connector tools: request_prepay_link, then get_funding_intent_status after the browser step.

curl -sS -X POST "$ADP_ZERO_API_URL/account/prepay-link" \
  -H "authorization: Bearer $ADP_ZERO_API_KEY" \
  -H 'user-agent: your-agent-name/1.0' \
  -H 'content-type: application/json' \
  -d '{"amount_cents":'"$ADP_ZERO_AMOUNT_CENTS"',"return_url":"'"$ADP_ZERO_RETURN_URL"'"}'

Target audiences

Search the audience catalog from our data providers before creating targeting. Use the returned id exactly as the segment key, not the display name, and show the estimated data CPM before launch. Unknown ids are refused rather than dropped.

Each segment carries a policy_tier. Segments whose names point at sensitive audiences (health, medication, political, financial hardship, gambling, adult, or weapons) are marked requires_review or restricted, and the API attaches them only when the request sets segment_policy_acknowledgment.acknowledged_sensitive_segments to true. Without it the request is refused and the response lists the flagged segments.

To target or leave out US states and Canadian provinces, use region codes in COUNTRY/REGION form, for example USA/CA for California. The full list is at /targeting/reference/regions. A targeting set can include regions or exclude them, not both.

Audiences and targeting
# Region codes come from /targeting/reference/regions, for example USA/CA (California).
# The connector exposes the same catalog as discover_segments.

curl -sS "$ADP_ZERO_API_URL/targeting/reference/segments?q=automotive&limit=5" \
  -H "authorization: Bearer $ADP_ZERO_API_KEY" \
  -H 'user-agent: your-agent-name/1.0'

curl -sS -X POST "$ADP_ZERO_API_URL/targeting" \
  -H "authorization: Bearer $ADP_ZERO_API_KEY" \
  -H 'user-agent: your-agent-name/1.0' \
  -H 'content-type: application/json' \
  -d '{"name":"US auto intenders","geo":{"include_countries":["USA"]},"audience_segments":{"include_segments":["alliant-167430"],"exclude_segments":[]}}'

Submit an ad and launch

After the payment completes, check the funding intent or the balance before continuing. Your scripts can prepare and iterate on their own; activation still needs prepaid balance, the daily cap, an approved ad, an approved landing page, and the other launch checks. Review covers what is checked.

Funding check and ad submission
curl -sS "$ADP_ZERO_API_URL/account/funding-intents/$ADP_ZERO_FUNDING_INTENT_ID" \
  -H "authorization: Bearer $ADP_ZERO_API_KEY" \
  -H 'user-agent: your-agent-name/1.0'

curl -sS -X POST "$ADP_ZERO_API_URL/creative" \
  -H "authorization: Bearer $ADP_ZERO_API_KEY" \
  -H 'user-agent: your-agent-name/1.0' \
  -H 'content-type: application/json' \
  -d @"$ADP_ZERO_CREATIVE_JSON_PATH"

Rotate ads

Once a campaign exists, change its ads through the same API the dashboard and connector use: add approved variants, replace the main ad, pause or resume one ad, remove one, or copy the campaign. The API will not pause or remove the last active ad, and every ad still needs its approvals.

Ad rotation
curl -sS "$ADP_ZERO_API_URL/campaign/$ADP_ZERO_CAMPAIGN_ID/creatives" \
  -H "authorization: Bearer $ADP_ZERO_API_KEY" \
  -H 'user-agent: your-agent-name/1.0'

# Connector tools: list_campaign_creatives, add_campaign_creative, replace_campaign_creative,
# pause_campaign_creative, resume_campaign_creative, remove_campaign_creative, copy_campaign

Measure delivery and conversions

Delivery reporting covers spend, impressions, and clicks. Conversion events add conversions, cost per conversion, and ROAS, through browser pixels and server postbacks on /conversion-events. Use the install snippets the API returns; never put an API key in a browser tag.

generated_at is when Adprime Zero answered, not when delivery was last reported. Reporting freshness comes from freshness_status, metric_sources, and the reporting sync timestamps. Delivery reporting runs about two hours behind, so if spend or impressions exist but clicks are zero, check freshness before concluding the campaign had no clicks.

Measurement
# Connector tools: create_conversion_event, get_conversion_event_install,
# link_conversion_event_to_campaign, send_test_conversion,
# list_campaign_performance, get_campaign_performance (read freshness_status first)

# ADP_ZERO_START_AT and ADP_ZERO_END_AT are ISO 8601 UTC timestamps for the window to read.
curl -sS -X POST "$ADP_ZERO_API_URL/performance/query" \
  -H "authorization: Bearer $ADP_ZERO_API_KEY" \
  -H 'user-agent: your-agent-name/1.0' \
  -H 'content-type: application/json' \
  -d '{"campaign_id":"'"$ADP_ZERO_CAMPAIGN_ID"'","start_at":"'"$ADP_ZERO_START_AT"'","end_at":"'"$ADP_ZERO_END_AT"'","dimensions":["day"],"metrics":["impressions","clicks","spend_cents","conversions","cvr_bps","cpa_cents","roas_bps"]}'

Work as a team

An account is a workspace several people can share. Owners and admins invite people by email, group campaigns into teams, and give each person Read or Edit on a team. The wallet, ads, and targeting stay shared across the workspace, and moving a campaign between teams never changes its delivery.

A key always carries its own person's access, so a script running on a teammate's key sees and changes only that teammate's teams. When a campaign seems to be missing or a call is refused, check access first instead of retrying.

Team tools
# Connector tools: get_my_workspace_access, list_teams, create_team,
# invite_teammate, list_workspace_members, move_campaign_to_team

Errors and refusals

Every error has the same shape: an error object with a machine-readable code, a plain message, and sometimes details (for a rejected ad, the reasons). Each response also carries an X-AdpZero-Request-Id header. A refusal names its cause; fix that cause rather than retrying the same call:

  • 401. The key is missing, revoked, or the connector sign-in never finished. Sign in again or create a new key.
  • Prepaid balance. A wallet problem, not an ad problem: request a payment link.
  • Activation or resume refused. The response lists what is missing: the ad's approval, the landing page's approval, balance, budget, or targeting. Readiness is a read, not a tight retry loop.
  • Targeting refused. An unknown segment or region id, a sensitive segment without the acknowledgment, or included and excluded regions in one set.
  • Last active ad. Pausing or removing the only active ad on a campaign is refused; pause the campaign instead.
  • Access refused for a teammate's key. The key only reaches its person's teams.
  • Rejected before the API. A request with no User-Agent can be blocked at the edge; send one.
Error response
{
  "error": {
    "code": "unauthorized",
    "message": "<what went wrong, in plain words>",
    "request_id": "<the same id as the X-AdpZero-Request-Id header>"
  }
}