Skip to content
AdCrunch
Esc
navigateopen⌘Jpreview

List ad groups

Lists the ad groups of every ad account your organization connects, across the providers, newest first.

One concept, three words

An ad group is a Meta ad set, a TikTok ad group and a Google Ads ad group. This path reads all three at once, and every row keeps the word its own provider writes, in type. AdCrunch renames nothing: a Meta adset and a Google ad_group are not the same object, and a caller that must speak to the provider needs the provider’s word.

Narrowing

Send campaignId to read one campaign’s ad groups, and provider to read one platform. limit and offset page the answer itself, not each advertiser.

Budget

An ad group that carries its own budget answers it in budget, in whole units of its currency, and a budgetLevel of ad_group. One whose campaign carries the budget answers a null budget and a budgetLevel of campaign: read the campaign for the amount. Every Google Ads ad group is the second kind, because Google Ads keeps every budget on the campaign.

What is not here

Performance Max campaigns have no ad groups. Google’s automation delivers them through an asset group instead, which is a child of the campaign and a sibling of an ad group — so a Performance Max campaign answers nothing here, and that is not a fault. Read /observe/asset-groups for those.

GET/observe/ad-groups
Authorization
AuthorizationBearer token · headerrequired

Send Authorization: Bearer <credential>. Two credentials work.

An API key (acr_…) is what a server integration uses. Create one in the AdCrunch console under Settings → API keys — see https://docs.adcrunch.dev/account/api-keys. A key is bound to the organization that was active when you created it, and it keeps acting on that organization whatever you do later. It carries the permissions of the member who created it.

A session issued by the AdCrunch sign-in flow also works, which is how the console calls this service from the browser.

Either way the organization comes from the credential. There is no organization parameter.

Query parameters
idsstring
limitinteger
min 1 · max 500 · default: 500
offsetinteger
min 0 · max 9007199254740991 · default: 0
statusstring
Allowed:ACTIVEPAUSEDDELETEDARCHIVED
providerstring
campaignIdstring
matches ^\d+$
Responses
200

The matching ad groups, and how many there are in all. Each row keeps its provider’s own type: adset, adgroup or ad_group.

dataobject[]required

The matching rows, newest first by the provider’s own created time. An empty array means nothing matched, which is a normal answer and not a failure.

Show properties
Array of object
adGroupIdstring | nullrequired

The ad group that holds it, as the bare id its provider gives. Null on everything an ad group does not hold: a campaign, an ad group itself, an asset group, and a creative.

advertiserIdstringrequired

The ad account that owns it, prefixed acc_.

budgetnumber | nullrequired

The budget this entity carries itself, in whole units of currency: 50 is 50.00, never 50 cents. It is the unit of spend on an Insight, so a budget and a spend compare directly. AdCrunch converts each provider’s own unit — Meta’s minor unit, TikTok’s whole units and Google Ads’ micros — so every provider answers the same unit here.

Null when the entity carries no budget of its own: budgetLevel then says where its budget lives. A campaign answers a budget only when its budgetLevel is campaign, so a budget always paces delivery at the level that answers it. Null also when AdCrunch does not know the account currency yet, because nobody can read a budget with no currency.

At Google Ads one budget may be shared by several campaigns, and each of them answers the whole shared amount.

A stored budget can be older than the rest of the row. Meta does not mark a campaign changed when only its budget changes, and AdCrunch does not yet follow a Google Ads budget change, so the ingestion can miss a budget edited in the provider’s own interface. Send fresh=true on an account-scoped listing to read the budget the provider holds now.

The Mutation API takes a Meta budget in integer minor units, not in whole units. Convert a budget you read here before you write it back.

budgetLevelstring | nullrequired

Where the budget of this entity’s campaign lives. campaign when the campaign carries it — Meta Advantage campaign budget, TikTok Campaign Budget Optimization, and every Google Ads campaign. ad_group when each ad group carries its own. It answers on campaigns and on everything the ad-groups and asset-groups listings read; it is null on ads and creatives, and on a TikTok campaign whose payload does not say.

Allowed:campaignad_group
budgetTypestring | nullrequired

daily for a budget spent each day, lifetime for one spent over the whole life of the entity. Null exactly when budget has no provider value to describe.

Allowed:dailylifetime
campaignIdstring | nullrequired

The campaign it belongs to, as the bare id its provider gives. Null on a campaign itself, and on a creative, which belongs to the advertiser rather than to any one campaign.

createdAtnumber | nullrequired

When AdCrunch first stored this row. Null when the row was read livesource is then provider, and AdCrunch holds no copy of it. createdAt, updatedAt and deletedAt are AdCrunch’s own times, so all three are null together on a live row.

createdTimenumber | nullrequired

When the provider created the entity. This is the provider’s own time, so a live row carries it. Null where the provider reports none.

currencystring | nullrequired

The account currency, ISO 4217 — the currency budget is in. Every row of one advertiser carries the same one. Null when AdCrunch does not know it yet.

deletedAtnumber | nullrequired

When AdCrunch marked the row deleted. A listing never carries a deleted row, so this is null.

idstringrequired

The id the provider gives, with no prefix. It is unique for one provider and one type, and it may legitimately recur across two types or two providers.

namestringrequired

The name at the provider.

objectivestring | nullrequired

The campaign’s objective, kept as the provider writes it: Meta OUTCOME_SALES, TikTok TRAFFIC. It is the provider’s word, for the same reason type is. Null on everything that is not a campaign, and on every Google Ads campaign, because Google Ads has no objective.

pathstringrequired

The ancestors and this entity, ids joined by /, oldest first. This is what makes a subtree one string comparison.

providerstringrequired

The ad platform: meta, tiktok, gads, snapchat or dv360.

statusstringrequired

The status, normalized across the providers. TikTok ENABLE and DISABLE read here as ACTIVE and PAUSED.

Allowed:ACTIVEPAUSEDDELETEDARCHIVED
typestringrequired

The type the provider uses, kept as the provider writes it: campaign, adset at Meta, ad_group at TikTok and Google Ads, asset_group, ad, creative. The path names the concept; the row keeps the provider’s own word, because a Meta adset and a Google ad_group are not the same object.

updatedAtnumber | nullrequired

When AdCrunch last rewrote this row. Null if it never changed.

updatedTimenumber | nullrequired

When the provider last edited the entity. Null where the provider reports none.

paginationobjectrequired
Show properties
limitnumberrequired

The greatest number of rows this answer can carry.

offsetnumberrequired

The number of rows skipped before the first.

totalnumber | nullrequired

How many rows match, over every advertiser read. It counts the whole match and not this page, so offset + limit reaching total means there is no more to read. Null on a live page whose provider reports no count — Google Ads never does — and a number everywhere else.

sourcestringrequired

Which side answered. store is what AdCrunch holds, which its ingestion refreshes. provider is a live read of the provider itself, which an account-scoped listing answers when you send fresh=true.

Allowed:storeprovider
401

No credential, or one that does not resolve. Send an API key or a session. See the security scheme. error is unauthorized.

errorstringrequired

A stable code for the failure. This is the field to branch on. It does not change for a given failure.

Allowed:unauthorized
messagestringrequired

A sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.

403

The caller does not hold observe:read. error is forbidden.

errorstringrequired

A stable code for the failure. This is the field to branch on. It does not change for a given failure.

Allowed:forbidden
messagestringrequired

A sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.

422

The request did not match this operation’s schema. This is the framework’s own shape, not the error/message one.

errorsobject[]required

One entry per failing field.

foundanyrequired

What was sent.

messagestringrequired
onstringrequired

Which part of the request failed: body, query or params.

propertystringrequired

The field that failed.

typestringrequired
Allowed:validation
Request
curl -X GET "https://api.adcrunch.dev/observe/ad-groups" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "data": [
    {
      "adGroupId": "string",
      "advertiserId": "string",
      "budget": 0,
      "budgetLevel": "campaign",
      "budgetType": "daily",
      "campaignId": "string",
      "createdAt": 0,
      "createdTime": 0,
      "currency": "string",
      "deletedAt": 0,
      "id": "string",
      "name": "string",
      "objective": "string",
      "path": "string",
      "provider": "string",
      "status": "ACTIVE",
      "type": "string",
      "updatedAt": 0,
      "updatedTime": 0
    }
  ],
  "pagination": {
    "limit": 0,
    "offset": 0,
    "total": 0
  },
  "source": "store"
}