Skip to main content
Pull the same metrics you see in the advertiser dashboard — and create, update, and archive campaigns and ad units — from scripts, cron jobs, or custom integrations.

Base URL

Authentication

Every request must include your Gravity advertiser API key in the X-API-Key header. Grab the key from your dashboard under Settings → API Key.
This is the same API key shown on your advertiser settings page. You can regenerate it at any time.

Endpoints

GET /advertiser-dashboard/info

Advertiser profile.
string
required
Your advertiser API key.
Response

GET /advertiser-dashboard/campaigns

List all campaigns with lifetime stats (impressions, clicks, spend, conversions).
string
Filter by campaign status (e.g. active, paused, draft).
Response

GET /advertiser-dashboard/campaigns/{campaign_id}

Single campaign detail with full stats and targeting config.
string
required
The campaign ID.
Response

GET /advertiser-dashboard/metrics

Daily time-series performance metrics.
integer
default:"30"
Number of days to look back (1–365).
string
Start date (YYYY-MM-DD). Overrides days when paired with end_date.
string
End date (YYYY-MM-DD).
string
Filter to a single campaign. Omit for aggregate metrics across all campaigns.
string
default:"UTC"
IANA timezone (e.g. America/New_York) used to bucket days. Defaults to UTC. Set this to your ad account’s reporting timezone so daily rows line up with the Gravity Dashboard and, for ChatGPT/OpenAI campaigns, with OpenAI’s reporting (OpenAI ad accounts currently report in America/New_York).
Days are bucketed by the timezone you pass in tz, not the timezone of the machine calling the API. A calendar day in UTC and the same day in America/New_York cover different hours, so the totals will differ — pick one timezone and use it consistently as your source of truth.
Response

GET /advertiser-dashboard/ad-unit-metrics

Daily time-series metrics broken down per ad unit — the same numbers shown under Ad units on a campaign’s detail page. Use this for creative-level reporting and optimization, where campaign-level /metrics isn’t granular enough. Returns one series per (campaign, ad unit) link, each tagged with a data_source. Series built from real per-ad-unit stats are "ad_unit_stats". A campaign with a single linked ad unit and no per-ad-unit rows yet falls back to the campaign’s own daily totals (data_source: "campaign_fallback") so the numbers stay consistent with the dashboard.
This endpoint reports impressions, clicks, spend, CTR, CPC, and CPM per ad unit. Conversions/CPA/ROAS are attributed at the campaign level — use /metrics or /conversions for those.
integer
default:"30"
Number of days to look back (1–365).
string
Start date (YYYY-MM-DD). Overrides days when paired with end_date.
string
End date (YYYY-MM-DD).
string
Filter to a single campaign.
string
Filter to a single ad unit. Returns 404 if the ad unit isn’t found in your account.
string
default:"UTC"
IANA timezone (e.g. America/New_York) used to bucket days. Same behavior as /metrics — set it to your ad account’s reporting timezone.
Response

GET /advertiser-dashboard/conversions

Recent conversions with pagination. Returns attributed and unattributed conversions.
integer
default:"50"
Page size (1–100).
string
Opaque pagination cursor (pass next_cursor from a previous response).
string
Filter to a single campaign.
string
Filter by conversion event type (e.g. purchase, lead).
Response

GET /advertiser-dashboard/billing

Billing summary — total spend, billed, unbilled, credits.
Response

GET /advertiser-dashboard/events/analytics

Pixel event analytics — domain breakdowns, time-series, and event type counts from your tracking pixel.
integer
default:"30"
Number of days to look back (1–365).
string
Start date (YYYY-MM-DD). Overrides days when paired with end_date.
string
End date (YYYY-MM-DD).
string
Filter by domain (partial match).
string
Filter by event type (e.g. page_view, form_submit, click).
Response

GET /advertiser-dashboard/events/conversion-stats

Conversion time-series from conversion_stats_hourly — daily totals and per-event-type breakdowns.
integer
default:"30"
Number of days to look back (1–365).
string
Start date (YYYY-MM-DD). Overrides days when paired with end_date.
string
End date (YYYY-MM-DD).
string
Filter by conversion event type (e.g. purchase, lead).
Response

GET /advertiser-dashboard/integrations

Connected Shopify stores. See Integrations for how to connect one.
Response

Managing campaigns

These endpoints let you create, edit, pause, and archive advertiser campaigns from the same API key surface.

POST /advertiser-dashboard/campaigns

Create a campaign with inline ad groups (recommended) or legacy ad-unit links.
string
required
Campaign name.
string
required
Destination URL for the campaign.
number
required
Daily budget in dollars.
string
Campaign status. Use draft, active, or paused.
string
Campaign objective.
string
Billing model.
string
Bid strategy.
boolean
Whether the campaign is active.
string
Optional start timestamp.
string
Optional end timestamp.
integer
Optional click goal.
number
Optional max cost-per-click bid in dollars. When set, OpenAI-network ad groups place a fixed per-click bid at this amount (on a conversions-objective campaign this is oCPC: conversion-optimized, billed per click at your bid). When omitted, conversions campaigns use OpenAI’s maximize_conversions auto-bidding — no bid is required — and other objectives use per-impression bidding. 0 is treated as unset.
integer
Optional impression goal.
number
Optional max CPM.
string
Optional conversion type.
number
Optional max CPA.
object
Optional demographics configuration.
array
Optional UTM parameters as key/value pairs.
array
Optional country targeting.
array
Optional device targeting.
object
Optional lead-form configuration.
array
Ad groups to create inline with the campaign. Each entry uses the same shape as POST /advertiser-dashboard/ad-groups minus campaign_id (it is set from the new campaign). Manual groups may include authored ads; generative groups generate their own ads and reject authored ads.
array
Legacy: one or more existing ad-unit IDs to link. Still supported, but ad groups are the current model.
Provide at least one of ad_groups or ad_unit_ids — the router returns 422 if both are missing or empty. Network selection is server-managed and always uses Gravity. keywords is not accepted here, and network_type / network_config return 422 if included.
Response
Ad-group response objects also include targeting and budget fields (context, landing_page, daily_budget, max_cpc, allowed_countries, allowed_devices, etc.) — see Managing ad groups & ads.

PATCH /advertiser-dashboard/campaigns/{campaign_id}

Edit a campaign or pause/unpause it.
string
required
The campaign ID.
string
Optional campaign name.
string
Optional landing page URL.
number
Optional daily budget.
string
Optional campaign objective.
number
Optional max cost-per-click bid in dollars. When set, OpenAI-network ad groups place a fixed per-click bid at this amount; editing it re-syncs live ad groups with the new bid. Send null (or 0) to clear it — conversions campaigns then use OpenAI’s maximize_conversions auto-bidding.
string
Optional status. Use active, paused, or draft.
string
Optional start timestamp.
string
Optional end timestamp.
array
Optional country targeting.
array
Optional device targeting.
array
Optional UTM parameters as key/value pairs.
string
Optional favicon URL.
object
Optional lead-form configuration.
Response
Activating a campaign runs the billing gate and can return 402. Budget or network changes can force the Gravity-only fallback, and activation can resubmit the campaign for review and enqueue background sync.

PATCH /advertiser-dashboard/campaigns/{campaign_id}/archive

Toggle a campaign’s archived state.
string
required
The campaign ID.
Response
Archiving also sets is_active = false and status = "paused".

Managing ad groups & ads

Campaigns are now structured as campaign → ad groups → ads. An ad group is either:
  • generative (default) — Gravity generates ads for the group from your context / ad_prompt. Authored ads are rejected with 422.
  • manual — you author the ads yourself via the ads array or the ads endpoints below. Generated ads are read-only; only manual ads can be edited or archived.
These endpoints share the same implementation and ownership checks as the Gravity dashboard, scoped to your API key’s account.

GET /advertiser-dashboard/ad-groups

List your ad groups, each with its ads embedded (up to 100 per group; ads_total carries the full count).
string
Filter to a single campaign.
boolean
default:"false"
Include archived groups.
Response

POST /advertiser-dashboard/ad-groups

Create an ad group under one of your campaigns.
string
required
The campaign to attach the group to. Must be owned by your account.
string
required
Ad-group name.
string
default:"generative"
generative or manual.
string
default:"active"
active, paused, or archived.
string
Targeting context used to match conversations (and to generate ads for generative groups).
string
Conversations to avoid.
string
Optional prompt guiding ad generation (generative groups).
string
Default landing page for the group’s ads.
integer
Optional group-level daily budget. auto_optimize_budget (default true) lets Gravity allocate budget across groups; min_daily_budget / max_daily_budget bound it.
number
Optional group-level max CPC.
array
Optional country targeting override.
array
Optional device targeting override.
array
Authored ads (manual groups only). Each ad supports name, headline (≤80 chars), copy (≤500 chars), cta (≤80 chars), description, landing_page, image_url, and status.
Returns 201 with the created group and its ads (same shape as the list response). 422 if authored ads are sent to a generative group.

GET /advertiser-dashboard/ad-groups/{ad_group_id}

Fetch a single ad group with its ads.

PATCH /advertiser-dashboard/ad-groups/{ad_group_id}

Update any of the fields above (send only what changes). Converting a manual group to generative returns 422 while it still has live manual ads.

DELETE /advertiser-dashboard/ad-groups/{ad_group_id}

Archive an ad group (and its ads). Returns 204.

POST /advertiser-dashboard/ad-groups/{ad_group_id}/ads

Author an ad in a manual group. Returns 201 with the created ad; 422 on generative groups.
Response

PATCH /advertiser-dashboard/ads/{ad_id}

Edit a manual ad (headline, copy, cta, landing_page, status, etc.). Generated ads are read-only and return 422.

DELETE /advertiser-dashboard/ads/{ad_id}

Archive a manual ad. Returns 204.

Legacy: ad units (deprecated)

Ad units are the legacy creative model. They keep working for existing integrations — nothing breaks — but new integrations should use ad groups & ads instead. Campaigns are now structured as campaign → ad group → ad.

POST /advertiser-dashboard/ad-units

Create an ad unit owned by your advertiser account.
string
required
Ad-unit name.
string
Optional headline.
string
required
Required at submit time.
string
required
Required at submit time.
string
required
Required at submit time.
string
required
Required at submit time.
string
Optional favicon URL.
string
Optional image URL.
string
Optional brand name.
array
Optional UTM parameters as key/value pairs.
ad_text_mode is not accepted here. The router also rejects source, status, review_status, review_reason, metadata, and generate_static_text because those fields are server-managed.
Response

POST /advertiser-dashboard/campaigns/{campaign_id}/ad-units/generate

Generate draft ad units from a landing page URL.
string
required
The campaign ID.
string
required
Landing page URL to scrape.
integer
Number of draft ad units to generate, from 1 to 5.
Response

POST /advertiser-dashboard/campaigns/{campaign_id}/ad-units

Add ad units to a campaign without replacing the existing set.
string
required
The campaign ID.
array
required
One or more ad-unit IDs. Duplicate IDs are deduped before write.
Response
The router marks linked units for review when needed, resubmits already-approved campaigns that now contain unreviewed ad units, and schedules the campaign ad-unit sync task in the background.

PUT /advertiser-dashboard/campaigns/{campaign_id}/ad-units

Replace the campaign’s ad-unit set.
string
required
The campaign ID.
array
required
Replacement ad-unit IDs. Duplicate IDs are deduped before write.
Response
This route has the same ownership checks and review/sync behavior as the POST variant, but it replaces the existing linked set before returning.

PATCH /advertiser-dashboard/ad-units/{ad_unit_id}/archive

Toggle an ad unit’s archived state.
string
required
The ad unit ID.
Response
Unarchiving restores status = "draft".

Managing pixels

POST /advertiser-dashboard/pixels

Create a conversion pixel for a site. Verification of the pixel installation runs in the background after creation.
string
required
The site URL the pixel will be installed on. https:// is prepended if no scheme is given.
string
Display name for the pixel. Defaults to Untitled Pixel.
Response (201)
is_functional starts as null and flips to true/false once background verification confirms whether the pixel script is installed on the URL. Returns 409 if a pixel already exists for the URL, and 422 if the URL is invalid.

GET /advertiser-dashboard/pixels

List all pixels on your account.
Response

MCP server

The reporting endpoints above are also exposed as an MCP server, so AI agents and MCP-capable clients can query your account directly.
  • Endpoint: POST https://platform.trygravity.ai/mcp (JSON-RPC 2.0 over HTTP)
  • Auth: X-API-Key header (or Authorization: Bearer <key>)
An advertiser API key unlocks read-only tools mirroring this API: advertiser_get_info, advertiser_list_campaigns, advertiser_get_campaign, advertiser_get_metrics, advertiser_get_conversions, advertiser_get_billing, advertiser_get_events_analytics, advertiser_get_conversion_stats, and advertiser_get_integrations.

Code examples

Errors

Questions

Email support@trygravity.ai for anything API-related. We read it.