tva
← Artigos

Google Ads API: configuração, autenticação, operações de leitura e escrita

Um guia técnico para configurar o acesso programático ao Google Ads — da arquitetura à primeira chamada de API. Abrange configuração de MCC, OAuth 2.0, níveis de Developer Token, a biblioteca Python google-ads, consultas de leitura em GAQL e o padrão de escrita validate_only.

Atualização (outubro de 2026): O Google descontinuou os tokens de desenvolvedor em 9 de setembro de 2026. Os níveis de acesso à API agora são atribuídos por projeto do Google Cloud e gerenciados na página de visão geral da Google Ads API no Cloud Console; o cabeçalho developer-token é opcional e ignorado, e o API Center não gerencia mais o cadastro nem as alterações de acesso. O Google informa que o código existente continua funcionando. As etapas sobre tokens de desenvolvedor e API Center abaixo descrevem a configuração publicada em junho de 2026. A configuração atual está no nosso artigo de continuação, Acesso à API do Google Ads em 2026: projetos do Cloud substituem os Developer Tokens.

Arquitetura

São necessárias três entidades separadas antes que uma única chamada de API funcione:

EntidadeFinalidadeExemplo
Conta de administrador (MCC)Emite o Developer Tokenlogin_customer_id
Projeto Google CloudCliente OAuth 2.0 para autenticaçãoID do cliente + segredo
Conta Google AdsAlvo de todas as operações da APIcustomer_id

Não são a mesma conta. Uma MCC pode possuir um Developer Token sem ser proprietária da conta de destino — só precisa estar vinculada como administradora. O projeto Google Cloud pode estar sob uma identidade Google diferente da MCC. A conta de destino é a conta do anunciante onde ficam as campanhas.

Esta separação é importante porque o API Center (onde os Developer Tokens são provisionados) só está disponível dentro de contas de administrador. Uma conta Google Ads independente não pode acessar o API Center, mesmo que tenha usuários com acesso administrativo.

O cabeçalho da chamada de API reúne estas três identidades mais um token Bearer do OAuth:

developer-token: <from MCC API Center>
login-customer-id: <MCC numeric ID, no dashes>
customer-id: <target account numeric ID>
Authorization: Bearer <OAuth 2.0 access token>

Pré-requisitos

  • Uma conta de administrador Google Ads com configuração concluída
  • A conta de anúncios de destino vinculada à conta de administrador e o vínculo aceito
  • Um projeto Google Cloud com a Google Ads API ativada
  • Python 3.9+ com a biblioteca google-ads (pip install google-ads)
  • Um navegador para o fluxo de consentimento OAuth, realizado uma única vez

Passo 1: conta de administrador e Developer Token

O API Center encontra-se em Ferramentas e configurações → Configuração → API Center dentro de uma conta de administrador. Se o API Center estiver ausente, a conta não é uma conta de administrador ou sua configuração está incompleta.

A partir do API Center, solicite um Developer Token. Defina o tipo de conta como Advertiser (não Agency ou Third-Party) quando o token se destina às suas próprias contas. O token é emitido imediatamente com o nível Test Access.

O Test Access permite:

  • Operações de leitura apenas em contas de teste
  • Operações de escrita apenas em contas de teste
  • Nenhuma operação de leitura ou escrita em contas de produção

As requisições a contas de produção com Test Access falham com DEVELOPER_TOKEN_NOT_APPROVED (“The developer token is only approved for use with test accounts”). Desde a descontinuação de setembro de 2026, as versões atuais da API retornam CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION em seu lugar (ACTION_NOT_PERMITTED na v24 e anteriores).

Solicitação de Basic Access

Para acessar contas de produção, solicite Basic Access a partir da mesma página do API Center. O formulário de solicitação contém 12 perguntas. Para uso interno em suas próprias contas, as respostas relevantes são:

PerguntaResposta
Q4: Relação com um representante do GoogleNão
Q6: Modelo de negócioDescreva seu caso de uso (e-commerce, geração de leads, relatórios internos)
Q8: Quem terá acessoUsuários internos — apenas funcionários
Q9: Ferramenta desenvolvida por terceirosNão (scripts/agentes próprios)
Q10: API de acompanhamento de conversões e remarketingNão (a menos que realmente a utilize)
Q11: Tipos de campanhaSearch, Performance Max, Shopping (conforme aplicável)
Q12: CapacidadesCriação de campanhas, gerenciamento de campanhas, relatórios

É necessário um documento de projeto (PDF) para a Q7. Deve descrever a arquitetura da API, o fluxo de autenticação, a estratégia de limitação de requisições, o tratamento de erros e o caso de uso exclusivamente interno. Seja factual — a equipe de conformidade verifica a consistência com o caso de uso declarado.

Tempo de processamento em junho de 2026: aproximadamente 3 dias úteis, com uma nota sobre volume de solicitações superior ao habitual.

Passo 2: OAuth 2.0

Configuração do projeto Google Cloud

No Google Cloud Console, no projeto correspondente:

  1. Ative a Google Ads API (APIs e serviços → Biblioteca)
  2. Configure a tela de consentimento OAuth:
  • Tipo de usuário: Internal (apenas usuários do seu Google Workspace podem autorizar — dispensa a verificação externa do app)
  • Nome do app, e-mail de suporte, e-mail de contato do desenvolvedor
  1. Adicione o escopo em Acesso a dados: https://www.googleapis.com/auth/adwords
  2. Crie um ID do cliente OAuth:
  • Tipo de aplicativo: Desktop app
  • Baixe o JSON com o segredo do cliente

O tipo Desktop app utiliza http://localhost como URI de redirecionamento. Isso está correto — o fluxo OAuth abre um navegador, o Google redireciona para localhost com o código de autorização e um servidor HTTP local captura esse código.

Geração do token de atualização

Um script Python mínimo (não verifica o parâmetro state retornado nem define permissões no arquivo de tokens; adicione ambas as medidas antes de usá-lo além de uma execução local pontual) que executa um servidor HTTP local em 127.0.0.1:0 (porta aleatória), imprime a URL de autorização, aguarda uma requisição, extrai o parâmetro code e troca esse código por tokens:

from pathlib import Path
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
from google_auth_oauthlib.flow import Flow

class CallbackHandler(BaseHTTPRequestHandler):
    code_value = None
    def do_GET(self):
        qs = parse_qs(urlparse(self.path).query)
        CallbackHandler.code_value = (qs.get('code') or [None])[0]
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b'OAuth complete.')
    def log_message(self, format, *args):
        return

server = HTTPServer(('127.0.0.1', 0), CallbackHandler)
redirect_uri = f'http://127.0.0.1:{server.server_port}/'
flow = Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/adwords'],
    redirect_uri=redirect_uri
)
auth_url, _ = flow.authorization_url(
    access_type='offline',
    prompt='consent'
)
print(auth_url)
server.handle_request()
flow.fetch_token(code=CallbackHandler.code_value)
Path('google_ads_token.json').write_text(flow.credentials.to_json())

Dois parâmetros são importantes:

  • access_type='offline' — retorna um token de atualização, não apenas um token de acesso
  • prompt='consent' — força uma nova tela de consentimento mesmo que o usuário tenha autorizado anteriormente; necessário para obter um novo token de atualização se os escopos tiverem mudado

O token de atualização não tem duração fixa, mas deixa de funcionar se o usuário revogar o acesso, ficar sem uso por seis meses, o usuário alterar a senha (para tokens com escopos do Gmail), a conta exceder o limite do Google de tokens de atualização ativos ou um administrador do Workspace restringir o escopo ou impor uma duração de sessão. Planeje a necessidade de uma nova autorização.

Armadilha de escopo com clientes existentes

Se a URL de autorização definir include_granted_scopes=true e o usuário já tiver concedido a esse cliente OAuth outros escopos (Gmail, Drive, Calendar), o Google retorna a união dos escopos antigos e novos. A biblioteca google-auth-oauthlib rejeita esta discrepância de escopo por padrão. Defina a variável de ambiente antes de carregar o fluxo:

import os
os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'

Como alternativa, omita include_granted_scopes=true da URL de autorização (o script acima não o define), para que o token cubra apenas o escopo solicitado explicitamente.

Passo 3: google-ads.yaml

A biblioteca lê a configuração de um arquivo YAML:

developer_token: <value>
client_id: <value>
client_secret: <value>
refresh_token: <value>
login_customer_id: 1911599764
use_proto_plus: true

Regras de segurança:

  • Permissões do arquivo: 0600 (apenas leitura/escrita pelo proprietário)
  • Nunca incluir no controle de versões
  • Armazenar fora de qualquer repositório Git
  • Para configurações de equipe, distribuir via gerenciador de segredos, não por arquivo compartilhado

login_customer_id é o ID numérico da MCC sem hífens. Indica à API por meio de qual conta de administrador o usuário autenticado acessa a conta de destino e é obrigatório sempre que o acesso passa por uma conta de administrador. O customer_id de destino é passado no momento da chamada, não na configuração.

use_proto_plus é uma chave de configuração obrigatória: true seleciona a interface de mensagens proto-plus usada neste guia; false seleciona mensagens protobuf simples, que o Google recomenda para tarefas sensíveis ao desempenho.

Passo 4: inicialização do cliente Python

from google.ads.googleads.client import GoogleAdsClient

client = GoogleAdsClient.load_from_storage(
    '/path/to/google-ads.yaml',
    version='v22'
)
gs = client.get_service('GoogleAdsService')

O parâmetro version seleciona explicitamente a versão da API. A biblioteca google-ads é distribuída com várias versões instaladas em paralelo; os exemplos aqui usam v22. Em outubro de 2026, as versões atuais da biblioteca já não incluem v22 (removida na 33.0.0), e a 34.0.0 adiciona v26, portanto substitua-a por uma versão atual. Especifique sempre a versão — a versão padrão pode estar desatualizada ou não suportar campos mais recentes.

Verifique a conectividade:

cs = client.get_service('CustomerService')
customers = cs.list_accessible_customers()
ids = [r.split('/')[-1] for r in customers.resource_names]
# Example output: ['1305475941', '3977581086', '1911599764']

Passo 5: operações de leitura (GAQL)

O Google Ads utiliza GAQL (Google Ads Query Language), uma sintaxe semelhante a SQL. Todas as operações de leitura passam por GoogleAdsService.search_stream(), que evita paginação e é preferível a search() para a maioria das consultas.

Campanhas com métricas de desempenho

SELECT
  campaign.id,
  campaign.name,
  campaign.status,
  campaign.advertising_channel_type,
  campaign.serving_status,
  campaign.bidding_strategy_type,
  metrics.impressions,
  metrics.clicks,
  metrics.cost_micros,
  metrics.conversions,
  metrics.conversions_value,
  metrics.ctr,
  metrics.average_cpc
FROM campaign
ORDER BY campaign.id

Orçamentos de campanha

SELECT
  campaign_budget.id,
  campaign_budget.name,
  campaign_budget.amount_micros,
  campaign_budget.delivery_method,
  campaign_budget.status,
  campaign.id,
  campaign.name
FROM campaign_budget

Grupos de anúncios

SELECT
  ad_group.id,
  ad_group.name,
  ad_group.status,
  ad_group.cpc_bid_micros,
  campaign.id,
  campaign.name
FROM ad_group
ORDER BY campaign.id, ad_group.id

Palavras-chave (por impressões)

SELECT
  ad_group_criterion.keyword.text,
  ad_group_criterion.keyword.match_type,
  ad_group_criterion.status,
  ad_group_criterion.criterion_id,
  ad_group.id,
  ad_group.name,
  campaign.id,
  campaign.name,
  metrics.impressions,
  metrics.clicks,
  metrics.cost_micros,
  metrics.conversions
FROM keyword_view
WHERE ad_group_criterion.type = 'KEYWORD'
ORDER BY metrics.impressions DESC
LIMIT 100

Anúncios com status de conformidade com as políticas

SELECT
  ad_group_ad.ad.id,
  ad_group_ad.ad.name,
  ad_group_ad.ad.type,
  ad_group_ad.status,
  ad_group_ad.policy_summary.approval_status,
  ad_group.id,
  ad_group.name,
  campaign.id,
  campaign.name
FROM ad_group_ad

Ações de conversão

SELECT
  conversion_action.id,
  conversion_action.name,
  conversion_action.status,
  conversion_action.type,
  conversion_action.category,
  conversion_action.include_in_conversions_metric,
  conversion_action.counting_type
FROM conversion_action

Padrão de execução Python

def gaql_query(client, customer_id, query):
    gs = client.get_service('GoogleAdsService')
    results = []
    for batch in gs.search_stream(customer_id=customer_id, query=query):
        for row in batch.results:
            results.append(row)
    return results

Passo 6: operações de escrita com validate_only

Os exemplos abaixo usam objetos de requisição em vez de argumentos nomeados porque o objeto de requisição contém validate_only. Todos os serviços de alteração (CampaignService, AdGroupService, AdGroupCriterionService, CampaignBudgetService) seguem o mesmo padrão:

from google.protobuf import field_mask_pb2

req = client.get_type('MutateCampaignsRequest')
req.customer_id = '1305475941'
req.validate_only = True
op = client.get_type('CampaignOperation')
op.create.name = 'Campaign Name'
op.create.status = client.enums.CampaignStatusEnum.PAUSED
op.create.advertising_channel_type = client.enums.AdvertisingChannelTypeEnum.SEARCH
op.create.campaign_budget = 'customers/1305475941/campaignBudgets/123456789'
op.create.manual_cpc.enhanced_cpc_enabled = False
req.operations.append(op)  # .append(), not .add()
client.get_service('CampaignService').mutate_campaigns(request=req)

Pontos principais deste padrão (com use_proto_plus: true):

  • validate_only é um campo no objeto de requisição, não um argumento nomeado do método mutate
  • As operações são anexadas via req.operations.append(op); .add() pertence à interface protobuf simples (use_proto_plus: false)
  • Aqui, os caminhos de recursos são escritos como strings explícitas ('customers/1305475941/campaigns/22479990461'); os serviços também fornecem métodos auxiliares de caminho, como campaign_service.campaign_path(customer_id, campaign_id), que o Google recomenda em vez de nomes montados manualmente

Controle de alterações em três etapas

Para segurança em produção, as alterações passam por três etapas de controle:

Etapa 1 — validate_only=True: A API valida a estrutura da requisição, campos obrigatórios e referências de recursos. Nenhum objeto é criado. Execute isso primeiro para cada alteração.

Etapa 2 — Criação com status pausado: Defina validate_only=False e crie o objeto com status=PAUSED. Verifique o resultado com uma consulta de leitura antes de prosseguir.

Etapa 3 — Ativação em produção: Uma chamada de API separada que atualiza apenas o campo status para ENABLED. Isso deve exigir aprovação explícita, não ser incorporado na criação.

# Gate 3: enable a previously created paused campaign
req = client.get_type('MutateCampaignsRequest')
req.customer_id = '1305475941'
req.validate_only = False
op = client.get_type('CampaignOperation')
op.update.resource_name = 'customers/1305475941/campaigns/22479990461'
op.update.status = client.enums.CampaignStatusEnum.ENABLED
op.update_mask.CopyFrom(field_mask_pb2.FieldMask(paths=['status']))
req.operations.append(op)
client.get_service('CampaignService').mutate_campaigns(request=req)

Atualização de orçamento

req = client.get_type('MutateCampaignBudgetsRequest')
req.customer_id = '1305475941'
req.validate_only = True
op = client.get_type('CampaignBudgetOperation')
op.update.resource_name = 'customers/1305475941/campaignBudgets/123456789'
op.update.amount_micros = 1_000_000  # $1.00 per day
op.update_mask.CopyFrom(field_mask_pb2.FieldMask(paths=['amount_micros']))
req.operations.append(op)
client.get_service('CampaignBudgetService').mutate_campaign_budgets(request=req)

Atualização de lance de grupo de anúncios

req = client.get_type('MutateAdGroupsRequest')
req.customer_id = '1305475941'
req.validate_only = True
op = client.get_type('AdGroupOperation')
op.update.resource_name = 'customers/1305475941/adGroups/165827073530'
op.update.cpc_bid_micros = 250_000  # $0.25
op.update_mask.CopyFrom(field_mask_pb2.FieldMask(paths=['cpc_bid_micros']))
req.operations.append(op)
client.get_service('AdGroupService').mutate_ad_groups(request=req)

Criação de palavra-chave

req = client.get_type('MutateAdGroupCriteriaRequest')
req.customer_id = '1305475941'
req.validate_only = True
op = client.get_type('AdGroupCriterionOperation')
op.create.ad_group = 'customers/1305475941/adGroups/165827073530'
op.create.status = client.enums.AdGroupCriterionStatusEnum.PAUSED
op.create.keyword.text = 'example keyword'
op.create.keyword.match_type = client.enums.KeywordMatchTypeEnum.EXACT
req.operations.append(op)
client.get_service('AdGroupCriterionService').mutate_ad_group_criteria(request=req)

Tratamento de erros

from google.ads.googleads.errors import GoogleAdsException

try:
    response = service.mutate_campaigns(request=req)
except GoogleAdsException as ex:
    for error in ex.failure.errors:
        print(f'{error.error_code}: {error.message}')

Códigos de erro comuns e seu significado:

Código de erroCausa
RESOURCE_NOT_FOUNDO recurso referenciado não existe, foi removido ou tem um nome de recurso malformado
DEVELOPER_TOKEN_NOT_APPROVEDToken Test Access em uma conta de produção (CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION desde a descontinuação de setembro de 2026)
REQUIREDCampo obrigatório ausente (ex.: estratégia de lance na criação de campanha)
UNRECOGNIZED_FIELDCampo de uma versão diferente da API ou nome de campo incorreto
INVALID_ARGUMENTValor de campo não passa na validação (ex.: orçamento negativo)
PERMISSION_DENIEDUsuário OAuth não tem acesso à conta de destino

Níveis de acesso à API

O acesso à Google Ads API é escalonado, não binário:

NívelProvisionamentoLeitura (produção)Escrita (produção)Escrita (contas de teste)Limite diário de operações
Test AccessImediato (pelo API Center da MCC até setembro de 2026; agora automático quando a API é ativada no projeto do Cloud)❌❌✅15.000
Explorer Access (listado em outubro de 2026)Solicitação na página de visão geral do Cloud Console✅✅ (alguns serviços restritos)✅2.880 em produção / 15.000 em testes
Basic AccessSolicitação + revisão de conformidade✅✅✅15.000
Standard AccessSolicitação após Basic Access + auditoria manual✅✅✅Ilimitado

O Test Access é suficiente para o desenvolvimento em contas de teste do Google Ads: autenticação, consultas GAQL, testes validate_only e leitura/escrita completas. A passagem para Basic Access é condicionada à revisão de conformidade, não ao investimento.

O Standard Access remove o limite diário de operações (os limites de requisições por funcionalidade continuam em vigor). Requer uma solicitação separada, disponível apenas após o Basic Access, e uma auditoria manual; a documentação do Google sobre os níveis de acesso não indica um limiar de investimento.

Contas de teste

Contas de teste são contas gratuitas do Google Ads, sem cobrança, que nunca veiculam anúncios. Contas de teste e de produção não podem interagir, portanto uma conta de teste não pode ficar sob sua MCC de produção: crie uma conta de administrador de teste separada após entrar com uma Conta do Google que não esteja vinculada à sua MCC de produção, crie contas de cliente de teste sob ela e use uma como customer_id de destino (com o administrador de teste como login_customer_id) durante o desenvolvimento com Test Access.

validate_only entre níveis de acesso

validate_only=True funciona em todos os níveis de acesso, mas o Test Access continua a rejeitar alterações validate_only em contas de produção com o mesmo erro de autorização de qualquer outra requisição. Isso não é uma limitação do validate_only — é o mesmo controle de acesso aplicado a todas as operações de escrita, independentemente do parâmetro validate_only.

Acompanhamento de conversões: leitura da API vs. status funcional

A interface do Google Ads pode mostrar "Configurar acompanhamento de conversões" como recomendação mesmo quando existe uma ação de conversão ativa. A API pode confirmar a existência de uma ação de conversão (tipo WEBPAGE, categoria PURCHASE, status ENABLED, include_in_conversions_metric: true), mas isso apenas prova que o objeto da ação existe. Não prova que o site emite o evento AW-.../label correspondente, que a tag do Google está carregada ou que um sinal de conversão foi recebido.

Ao auditar o acompanhamento de conversões, separe a verificação da API (metadados da ação de conversão) da verificação no navegador (aba de rede, carregamento de tags, disparo de eventos). A API é a fonte de referência para a configuração; o navegador é a fonte de referência para a execução.

O padrão de atribuição de receita no backend aplica-se aqui: se os eventos de conversão do lado do cliente não forem confiáveis, planeje o upload de conversões via servidor ou offline por meio do ConversionUploadService da Google Ads API como alternativa.

Versionamento da API

A biblioteca Python google-ads é distribuída com várias versões da API. Em outubro de 2026, a versão mais recente (34.0.0) adiciona v26, e v22 e anteriores foram removidas da biblioteca. Cada versão adiciona, descontinua ou remove campos GAQL e métodos de serviço.

Regras para seleção de versão:

  • Especifique a versão explicitamente em load_from_storage(version='v22'). A versão padrão pode estar desatualizada.
  • Consulte as notas de versão da Google Ads API para identificar campos descontinuados antes de atualizar.
  • O método search_stream está disponível em todas as versões atuais e é o caminho de leitura recomendado.
  • use_proto_plus deve ser definido explicitamente (true ou false); seleciona a interface de mensagens Python, não uma versão da API.
  • O padrão de objeto de requisição para alterações (mutate_campaigns(request=req)) contém campos no nível da requisição, como validate_only; os exemplos atuais do Google ainda passam customer_id e operations como argumentos nomeados para alterações simples.

Segurança local

Todos os arquivos de credenciais devem permanecer fora do controle de versões:

~/.hermes/
  google-ads.yaml          # 0600 — dev token, OAuth client, refresh token
  google_ads_token.json    # 0600 — OAuth tokens, adwords scope
  google_client_secret.json # 0600 — OAuth client ID + secret

Para o repositório de trabalho, adicione um .gitignore:

google-ads.yaml
*_token*.json
*_secret*.json

Um arquivo de modelo com valores de exemplo pode ser incluído no controle de versões para documentar a estrutura esperada:

# google-ads.yaml.template — commit this, fill locally
developer_token: INSERT_DEV_TOKEN
client_id: INSERT_CLIENT_ID
client_secret: INSERT_CLIENT_SECRET
refresh_token: INSERT_REFRESH_TOKEN
login_customer_id: INSERT_MCC_ID
use_proto_plus: true

Campos obrigatórios para operações comuns

OperaçãoCampos obrigatórios
Criar campanha (Search)name, status, advertising_channel_type, campaign_budget, manual_cpc ou estratégia de lance, contains_eu_political_advertising
Criar grupo de anúncios (Search)name, status, type_, cpc_bid_micros, campaign
Criar palavra-chavead_group, status, keyword.text, keyword.match_type
Atualizar status da campanharesource_name, status, update_mask (paths: ['status'])
Atualizar orçamentoresource_name, amount_micros, update_mask (paths: ['amount_micros'])

A falta de um campo obrigatório retorna REQUIRED com o nome do campo. Uma operação de atualização sem update_mask é rejeitada com FieldMaskError.FIELD_MASK_MISSING.

Script de teste resumido

Um script resumido (as listas de campos e os filtros GAQL estão abreviados com ... e os IDs são marcadores de posição, portanto preencha-os antes da execução) que lê todos os tipos de entidade e executa testes de escrita validate_only:

# google_ads_api_test.py — read all entities + validate_only write tests
import warnings
warnings.filterwarnings('ignore')
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
from google.protobuf import field_mask_pb2

CFG = '/path/to/google-ads.yaml'
CID = '1305475941'
c = GoogleAdsClient.load_from_storage(CFG, version='v22')
gs = c.get_service('GoogleAdsService')

def gaql(query, label):
    print(f'\n=== {label} ===')
    n = 0
    for batch in gs.search_stream(customer_id=CID, query=query):
        for row in batch.results:
            n += 1
    print(f'{n} rows')

# Read all entities
gaql("SELECT customer.id, customer.descriptive_name FROM customer WHERE customer.id = ...", "CUSTOMER")
gaql("SELECT campaign.id, campaign.name, campaign.status, ...  FROM campaign", "CAMPAIGNS")
gaql("SELECT campaign_budget.id, campaign_budget.name, ...  FROM campaign_budget", "BUDGETS")
gaql("SELECT ad_group.id, ad_group.name, ...  FROM ad_group", "AD GROUPS")
gaql("SELECT ad_group_criterion.keyword.text, ...  FROM keyword_view WHERE ...", "KEYWORDS")
gaql("SELECT ad_group_ad.ad.id, ...  FROM ad_group_ad", "ADS")
gaql("SELECT conversion_action.id, ...  FROM conversion_action", "CONVERSIONS")

# Write tests
def test_write(name, fn):
    print(f'\n--- {name} ---')
    try:
        fn()
        print('PASS')
    except GoogleAdsException as e:
        for err in e.failure.errors:
            print(f'{err.error_code}: {err.message}')

def test_create_campaign():
    req = c.get_type('MutateCampaignsRequest')
    req.customer_id = CID
    req.validate_only = True
    op = c.get_type('CampaignOperation')
    op.create.name = 'TEST_CAMPAIGN'
    op.create.status = c.enums.CampaignStatusEnum.PAUSED
    op.create.advertising_channel_type = c.enums.AdvertisingChannelTypeEnum.SEARCH
    op.create.campaign_budget = f'customers/{CID}/campaignBudgets/123456789'
    op.create.manual_cpc.enhanced_cpc_enabled = False
    req.operations.append(op)
    c.get_service('CampaignService').mutate_campaigns(request=req)

test_write('Create Campaign (validate_only)', test_create_campaign)
print('\nDone.')

Referências

Leitura complementar