Accounts & Labels
Read the Google Ads manager (MCC) hierarchy behind a connection, invite, accept, decline and end manager links, and organize campaigns, ad groups, ads and keywords with Google Ads labels.
When you finish this page you can see every Google Ads account a connection reaches and how they nest under manager (MCC) accounts, manage the links between managers and clients, and tag campaigns, ad groups, ads and keywords with labels. You need a googleads account.
Manager hierarchy
GET /v1/ads/accounts/hierarchy reads the manager and client tree live from Google. It starts from every customer the Google user behind the connection can access directly and walks each tree to any depth, so every client carries its direct parent, the link id and the link status.
curl "https://zernio.com/api/v1/ads/accounts/hierarchy?accountId=66b2e19d8c3f5a7e9d0b1c2d" \
-H "Authorization: Bearer $ZERNIO_API_KEY"Response (200), trimmed to one tree:
{
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"roots": [
{
"customerId": "9876543210",
"name": "Acme Agency MCC",
"currency": "USD",
"timeZone": "America/New_York",
"manager": true,
"testAccount": false,
"status": "ENABLED",
"managerLinks": [],
"clients": [
{
"customerId": "1234567890",
"name": "Acme Search",
"currency": "USD",
"timeZone": "America/New_York",
"manager": false,
"testAccount": false,
"hidden": false,
"level": 1,
"status": "ENABLED",
"parentCustomerId": "9876543210",
"managerLinkId": "345678901",
"linkStatus": "ACTIVE"
},
{
"customerId": "5550001111",
"name": null,
"currency": null,
"timeZone": null,
"manager": false,
"testAccount": false,
"hidden": false,
"level": 1,
"status": null,
"parentCustomerId": "9876543210",
"managerLinkId": "345678902",
"linkStatus": "PENDING"
}
]
}
],
"directCustomers": [
{ "customerId": "9876543210", "manager": true, "pendingInvitations": [] }
],
"unavailable": [],
"truncated": false,
"cachedAt": null,
"stale": false
}rootshas one entry per tree.clientslists every account under the root at any depth, withlevel(1 is a direct client of the root) andparentCustomerId, followed by invitations the manager sent that the client has not accepted yet (linkStatus: "PENDING"; Google returns no name or currency for them). Refused, canceled and ended links are history and are left out.managerLinkson a root lists the managers linked to that account, including invitations it can still accept.directCustomerslists every account the Google user accesses directly, the ones this connection can accept or decline invitations for, with theirpendingInvitations.- Customers Google refuses to read (for example a cancelled account) are listed in
unavailablewith Google's reason instead of failing the call. Up to 50 roots and 50 managers per root are read, andtruncatedistruewhen more exist. adAccountIdnarrows the read to the tree rooted at one directly accessible customer.- When the connection is scoped to specific ad accounts, client accounts outside that scope are hidden; managers stay visible.
The read is cached for 10 minutes per connection and carries cachedAt and stale.
Manager links
A manager link connects a manager account to a client. Invite a client with POST /v1/ads/accounts/manager-links:
curl -X POST "https://zernio.com/api/v1/ads/accounts/manager-links" \
-H "Authorization: Bearer $ZERNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"managerCustomerId": "9876543210",
"clientCustomerId": "5550001111"
}'Response (201):
{
"managerCustomerId": "9876543210",
"clientCustomerId": "5550001111",
"managerLinkId": "345678902",
"status": "PENDING"
}The manager must be one the connection's Google user reaches, directly or under another manager; the client can be any Google Ads account. The link stays PENDING until someone with access to the client accepts it, in Google Ads or through the call below. The invitation is not idempotent: Google refuses a second invitation while one is pending. validateOnly: true has Google check the request without sending anything (200, with managerLinkId: null).
PATCH /v1/ads/accounts/manager-links changes one link, identified by managerCustomerId, clientCustomerId and managerLinkId (all from the hierarchy read), with an action:
action | Acts as | What it does |
|---|---|---|
accept | The client | Accepts a pending invitation. The connection's Google user needs direct access to the client account; access through a manager is not enough, because the link does not exist yet. |
decline | The client | Declines a pending invitation, with the same access rule. |
cancel | The manager | Withdraws a pending invitation. |
unlink | The manager | Ends an active link. |
curl -X PATCH "https://zernio.com/api/v1/ads/accounts/manager-links" \
-H "Authorization: Bearer $ZERNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"managerCustomerId": "9876543210",
"clientCustomerId": "5550001111",
"managerLinkId": "345678902",
"action": "accept"
}'The response has the same shape, with the status the link has after the call (ACTIVE, REFUSED, CANCELED or INACTIVE). validateOnly: true checks the change without applying it.
Labels
Google Ads labels are free-form tags you attach to campaigns, ad groups, ads and keywords to group them in reports and in the Google Ads UI. Every label call takes accountId, plus adAccountId (the customer id) when the connection has several Google customers.
POST /v1/ads/labels creates one. name (up to 80 characters) is unique per customer, so a duplicate returns 400; backgroundColor (#RRGGBB) and description (up to 200 characters) are optional.
curl -X POST "https://zernio.com/api/v1/ads/labels" \
-H "Authorization: Bearer $ZERNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"adAccountId": "1234567890",
"name": "Q1 launch",
"backgroundColor": "#1A73E8"
}'Response (201): { "customerId": "1234567890", "id": "22334455", "resourceName": "customers/1234567890/labels/22334455" }.
Attach it with POST /v1/ads/labels/{labelId}/assignments, sending up to 1,000 ids in each target list:
curl -X POST "https://zernio.com/api/v1/ads/labels/22334455/assignments" \
-H "Authorization: Bearer $ZERNIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"adAccountId": "1234567890",
"campaignIds": ["21874563210"],
"adSetIds": ["165489732105"],
"adIds": ["165489732105~735198246013"],
"keywordIds": ["165489732105~987654321"]
}'Response (200): { "customerId": "1234567890", "labelId": "22334455", "attached": 3, "unchanged": 1 }.
All ids are Google's own. Campaigns and ad groups take their numeric ids; ads and keywords take the composite ids Google puts in their resource names, {adGroupId}~{adId} and {adGroupId}~{criterionId} (the keyword form is the tail of resourceName on GET /v1/ads/keywords). Attaching is idempotent: a target that already carries the label is counted in unchanged instead of failing the call. DELETE on the same path takes the same body and removes the label from those targets, reporting detached and unchanged.
The rest of the lifecycle:
GET /v1/ads/labelslists every non-removed label in one page, withid,name,status,backgroundColoranddescription. It is cached for 10 minutes and served withstale: truewhen Google's quota runs out. On a Meta ad account the same endpoint lists Meta's ad labels.PATCH /v1/ads/labels/{labelId}changes the name, color or description; only the fields you send are written, anddescription: ""clears it.DELETE /v1/ads/labels/{labelId}removes the label, and Google drops it from everything it was attached to.
Creating, editing and assigning labels is Google-only; those calls return 501 on other platforms.
Related
- Keywords: where the keyword ids for
keywordIdscome from. - Limits and errors: quotas and what the API cannot do.
- Get manager account hierarchy and Attach a Google Ads label: every field.
Recommendations
Read Google's optimization recommendations for a Google Ads account with their estimated impact, apply them with Google's suggested values or your own, and dismiss the ones you do not want.
Limits and errors
The per-user burst limit and Google quota on live Google Ads calls, what the Google Ads API and Zernio's integration do not expose, and the errors Google returns most often.