Google Ads

Overview

The Google Ads Core API exposes Google Ads API reads and the three campaign mutations — accounts, campaign insights, Search impression share, hourly metrics, and Performance Max asset groups.

Base path/api/core/google-ads
Auththe calling organization's own stored Google OAuth credentials, resolved from its google_ads integration, plus Analify's server-side developer token. You never pass either yourself
Every requestrequires ?organizationId=<uuid>

This surface is shaped differently from Meta and Shopify. Google Ads has no REST resource per object — everything is a GAQL query against googleAds:searchStream. Each read route below therefore mirrors one specific, named GAQL query, not an arbitrary endpoint. There is deliberately no "run any GAQL" route: an open query surface would let a caller select fields the response contract never promised.

Choosing an account. Calls default to the customer id stored on the integration. An org whose OAuth grant reaches several customers can target any of them with ?customerId= (no dashes). Discover the reachable set with GET /api/core/google-ads/accounts.

Money is in micros, not piasters. Google Ads reports cost as micro-units of the account currency — divide by 1,000,000. campaigns/budget likewise takes amountMicros.

API Endpoints

EndpointGoogle Real Endpoint / GAQLDescription
GET /accountsGET /customers:listAccessibleCustomersCustomer ids the OAuth grant can reach
GET /accounts/infoGAQL customerAccount name, currency, timezone
GET /campaigns/insightsGAQL campaign + metricsDaily campaign metrics
GET /campaigns/impression-shareGAQL Search impression shareImpression share (SEARCH campaigns only)
GET /insights/hourlyGAQL segments.hourHour-of-day metric rows
GET /asset-groups/assetsGAQL asset thumbnailsPMax asset thumbnails (account-wide, no date filter)
GET /asset-groups/strengthGAQL asset-group ad strengthPMax asset-group ad strength
GET /asset-groups/asset-insightsGAQL per-asset metricsPer-asset impressions
POST /campaigns/pausegoogleAds:mutate (status → PAUSED)Pause a campaign
POST /campaigns/resumegoogleAds:mutate (status → ENABLED)Resume a campaign
POST /campaigns/budgetgoogleAds:mutate (amount_micros)Change a campaign budget

Accounts

GET /api/core/google-ads/accounts

The raw listAccessibleCustomers response — every customer id the organization's OAuth grant can reach. Use one of these as ?customerId= on the routes below.

curl "https://analify.scalyax.ai/api/core/google-ads/accounts?organizationId={organizationId}" \
  -H "Authorization: Bearer {anlfy_token}"

Reads

All date-scoped reads take date_from and date_to (YYYY-MM-DD).

curl -G "https://analify.scalyax.ai/api/core/google-ads/campaigns/insights" \
  -H "Authorization: Bearer {anlfy_token}" \
  --data-urlencode "organizationId={organizationId}" \
  --data-urlencode "date_from=2026-08-01" \
  --data-urlencode "date_to=2026-08-16"

Targeting a specific customer:

curl -G "https://analify.scalyax.ai/api/core/google-ads/campaigns/insights" \
  -H "Authorization: Bearer {anlfy_token}" \
  --data-urlencode "organizationId={organizationId}" \
  --data-urlencode "customerId=1234567890" \
  --data-urlencode "date_from=2026-08-01" \
  --data-urlencode "date_to=2026-08-16"

Each read returns the raw GAQL result rows, exactly as searchStream produced them — nested under Google's own field names (campaign.id, metrics.costMicros, segments.date, …).

Two reads with their own rules

  • impression-share covers SEARCH campaigns only. Google does not expose impression-share metrics for Performance Max or Display, so those campaigns are absent from the result rather than returned as zero.
  • asset-groups/assets is account-wide and takes no date filter — it returns asset thumbnails as they currently exist, not a windowed report. Passing date_from/date_to has no effect.

GET /api/core/google-ads/insights/hourly

Mirrors the segments.hour GAQL — one row per hour of day, for day-parting analysis.

Mutations

All three take a resource name, not a bare id — Google's own identifier form, as returned by the reads above.

# Pause a campaign
curl -X POST "https://analify.scalyax.ai/api/core/google-ads/campaigns/pause?organizationId={organizationId}" \
  -H "Authorization: Bearer {anlfy_token}" -H "Content-Type: application/json" \
  -d '{ "campaignResourceName": "customers/1234567890/campaigns/9876543210" }'

# Change a budget — amountMicros, NOT piasters and NOT major units
curl -X POST "https://analify.scalyax.ai/api/core/google-ads/campaigns/budget?organizationId={organizationId}" \
  -H "Authorization: Bearer {anlfy_token}" -H "Content-Type: application/json" \
  -d '{
    "campaignBudgetResourceName": "customers/1234567890/campaignBudgets/5555555555",
    "amountMicros": 10000000
  }'

amountMicros: 10000000 is 10 units of the account currency (10,000,000 ÷ 1,000,000). Getting this wrong by a factor of a million is the single most expensive mistake available on this page. Budget, pause and resume all change a live account immediately and require an API token with the write scope.

A budget is a separate object from the campaign, and budgets can be shared across campaigns. Changing one may affect more than the campaign you started from — read campaign.campaignBudget first.


Error Shape

CodeStatusMeaning
GOOGLE_ADS_NOT_CONNECTED400The organization has no connected Google Ads integration
GOOGLE_ADS_RECONNECT_REQUIRED401The stored OAuth grant is dead — the user must reconnect
GOOGLE_ADS_CREDENTIALS_ERROR400Credential resolution failed for another reason
GOOGLE_ADS_API_ERROR502Any failure reported by the Google Ads API, carrying Google's own message
GOOGLE_ADS_UNKNOWN_ERROR500A non-platform failure inside the route
{
  "success": false,
  "error": {
    "message": "The customer account can't be accessed because it is not yet enabled or has been deactivated.",
    "code": "GOOGLE_ADS_API_ERROR"
  }
}

Did this page help you?