tva
← Artículos

API de Google Ads: configuración, autenticación, lectura y escritura

Guía técnica para configurar el acceso programático a Google Ads, desde la arquitectura hasta la primera llamada a la API. Cubre la configuración del MCC, OAuth 2.0, los niveles de acceso del token de desarrollador, la biblioteca de Python google-ads, las consultas de lectura GAQL y el patrón de escritura validate_only.

Actualización (octubre de 2026): Google retiró los tokens de desarrollador el 9 de septiembre de 2026. Los niveles de acceso a la API ahora se asignan por proyecto de Google Cloud y se gestionan en la página de descripción general de Google Ads API en Cloud Console; el encabezado developer-token es opcional y se ignora, y API Center ya no gestiona el registro ni los cambios de acceso. Google indica que el código existente sigue funcionando. Los pasos sobre tokens de desarrollador y API Center que aparecen a continuación describen la configuración publicada en junio de 2026. La configuración actual se explica en nuestro artículo de seguimiento, Acceso a la API de Google Ads en 2026: los proyectos de Cloud sustituyen a los Developer Tokens.

Arquitectura

Se requieren tres entidades distintas antes de poder realizar una llamada a la API:

EntidadPropósitoEjemplo
Cuenta de administrador (MCC)Emite el token de desarrolladorlogin_customer_id
Proyecto de Google CloudCliente OAuth 2.0 para autenticaciónID de cliente + secreto
Cuenta de Google AdsDestino de todas las operaciones de la APIcustomer_id

No son la misma cuenta. Un MCC puede tener un token de desarrollador sin ser propietario de la cuenta de destino; solo necesita estar vinculado como administrador. El proyecto de Google Cloud puede pertenecer a una identidad de Google distinta de la del MCC. La cuenta de destino es la cuenta del anunciante donde se encuentran las campañas.

Esta separación es importante porque API Center (donde se aprovisionan los tokens de desarrollador) solo está disponible dentro de cuentas de administrador. Una cuenta de Google Ads independiente no puede acceder a API Center, incluso si tiene usuarios con permisos de administrador.

El encabezado de la llamada a la API combina estas tres identidades con un token Bearer de 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>

Requisitos previos

  • Una cuenta de administrador de Google Ads con la configuración completa
  • La cuenta publicitaria de destino vinculada a la cuenta de administrador y el vínculo aceptado
  • Un proyecto de Google Cloud con la API de Google Ads habilitada
  • Python 3.9+ con la biblioteca google-ads (pip install google-ads)
  • Un navegador para el flujo de consentimiento OAuth que se realiza una sola vez

Paso 1: cuenta de administrador y token de desarrollador

API Center se encuentra en Herramientas y configuración → Configuración → API Center dentro de una cuenta de administrador. Si API Center no aparece, la cuenta o bien no es una cuenta de administrador o su configuración está incompleta.

Desde API Center, solicite un token de desarrollador. Establezca el tipo de cuenta como Anunciante (no Agencia ni Terceros) cuando el token es para sus propias cuentas. El token se emite inmediatamente con nivel de acceso de prueba.

El acceso de prueba permite:

  • Operaciones de lectura solo en cuentas de prueba
  • Operaciones de escritura solo en cuentas de prueba
  • Ninguna operación de lectura ni escritura en cuentas de producción

Las solicitudes a cuentas de producción con acceso de prueba fallan con DEVELOPER_TOKEN_NOT_APPROVED («The developer token is only approved for use with test accounts»). Desde la retirada de septiembre de 2026, las versiones actuales de la API devuelven CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION en su lugar (ACTION_NOT_PERMITTED en v24 y anteriores).

Solicitud de acceso básico

Para acceder a cuentas de producción, solicite acceso básico desde la misma página de API Center. El formulario de solicitud contiene 12 preguntas. Para uso interno en sus propias cuentas, las respuestas relevantes son:

PreguntaRespuesta
Q4: Relación con un representante de GoogleNo
Q6: Modelo de negocioDescriba su caso de uso (comercio electrónico, captación de clientes potenciales, informes internos)
Q8: Quién tendrá accesoUsuarios internos — solo empleados
Q9: Herramienta desarrollada por tercerosNo (scripts/agentes propios)
Q10: API de seguimiento de conversiones y remarketingNo (a menos que realmente la use)
Q11: Tipos de campañaSearch, Performance Max, Shopping (según corresponda)
Q12: CapacidadesCreación de campañas, gestión de campañas, generación de informes

Se requiere un documento de diseño (PDF) para Q7. Debe describir la arquitectura de la API, el flujo de autenticación, la estrategia de limitación de solicitudes, el manejo de errores y el caso de uso exclusivamente interno. Describa los hechos con precisión: el equipo de cumplimiento revisa la coherencia con el caso de uso declarado.

Tiempo de procesamiento a junio de 2026: aproximadamente 3 días hábiles, con una nota sobre un volumen de solicitudes superior al habitual.

Paso 2: OAuth 2.0

Configuración del proyecto en Google Cloud

En la Consola de Google Cloud, dentro del proyecto correspondiente:

  1. Habilite la API de Google Ads (API y servicios → Biblioteca)
  2. Configure la pantalla de consentimiento OAuth:
  • Tipo de usuario: Interno (solo usuarios de su Google Workspace pueden autorizar — omite la verificación externa de la app)
  • Nombre de la app, correo electrónico de soporte, correo electrónico de contacto del desarrollador
  1. Añada el ámbito de autorización en Acceso a datos: https://www.googleapis.com/auth/adwords
  2. Cree un ID de cliente OAuth:
  • Tipo de aplicación: Aplicación de escritorio
  • Descargue el JSON del secreto de cliente

El tipo de aplicación de escritorio usa http://localhost como URI de redirección. Esto es correcto — el flujo de OAuth abre un navegador, Google redirige a localhost con el código de autorización, y un servidor HTTP local lo captura.

Generación del token de actualización

Un script mínimo de Python (no verifica el parámetro state devuelto ni establece los permisos del archivo de tokens; añada ambas medidas antes de usarlo más allá de una ejecución local puntual) que ejecuta un servidor HTTP local en 127.0.0.1:0 (puerto aleatorio), imprime la URL de autorización, espera una solicitud, extrae el parámetro code y lo intercambia 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())

Dos parámetros son importantes:

  • access_type='offline' — devuelve un token de actualización, no solo un token de acceso
  • prompt='consent' — fuerza una nueva pantalla de consentimiento incluso si el usuario autorizó previamente; necesario para obtener un nuevo token de actualización si los ámbitos de autorización cambiaron

El token de actualización no tiene una duración fija, pero deja de funcionar si el usuario revoca el acceso, no se usa durante seis meses, el usuario cambia su contraseña (para tokens con ámbitos de Gmail), la cuenta supera el límite de Google de tokens de actualización activos o un administrador de Workspace restringe el ámbito o impone una duración de sesión. Prevea que será necesario volver a autorizar.

Problemas con los ámbitos de autorización de clientes existentes

Si la URL de autorización establece include_granted_scopes=true y el usuario ya había concedido a este cliente OAuth otros ámbitos de autorización (Gmail, Drive, Calendar), Google devuelve la unión de los ámbitos de autorización antiguos y nuevos. La biblioteca google-auth-oauthlib rechaza esta discrepancia de ámbitos de autorización por defecto. Establezca la variable de entorno antes de cargar el flujo:

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

Como alternativa, omita include_granted_scopes=true de la URL de autorización (el script anterior no lo establece), de modo que el token cubra solo el ámbito de autorización solicitado explícitamente.

Paso 3: google-ads.yaml

La biblioteca lee la configuración de un archivo YAML:

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

Reglas de seguridad:

  • Permisos del archivo: 0600 (solo el propietario puede leerlo y escribir en él)
  • Nunca incluir en control de versiones
  • Almacenar fuera de cualquier repositorio Git
  • Para configuraciones de equipo, distribuir mediante un gestor de secretos, no un archivo compartido

login_customer_id es el identificador numérico del MCC sin guiones. Le indica a la API a través de qué cuenta de administrador accede el usuario autenticado a la cuenta de destino, y es obligatorio siempre que el acceso se realice a través de una cuenta de administrador. El customer_id de destino se pasa en el momento de la llamada, no en la configuración.

use_proto_plus es una clave de configuración obligatoria: true selecciona la interfaz de mensajes proto-plus usada en esta guía; false selecciona los mensajes protobuf simples, que Google recomienda para tareas sensibles al rendimiento.

Paso 4: inicialización del 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')

El parámetro version selecciona explícitamente la versión de la API. La biblioteca google-ads incluye múltiples versiones instaladas en paralelo; los ejemplos aquí usan v22. A octubre de 2026, las versiones actuales de la biblioteca ya no incluyen v22 (eliminada en 33.0.0) y la versión 34.0.0 añade v26, por lo que debe sustituirla por una versión actual. Especifique siempre la versión — la predeterminada puede estar desactualizada o no admitir campos más recientes.

Verifique la conectividad:

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']

Paso 5: operaciones de lectura (GAQL)

Google Ads usa GAQL (Google Ads Query Language), una sintaxis similar a SQL. Todas las operaciones de lectura pasan por GoogleAdsService.search_stream(), que evita la paginación y es preferible a search() para la mayoría de las consultas.

Campañas con métricas de rendimiento

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

Presupuestos de campaña

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 anuncios

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

Palabras clave (por impresiones)

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

Anuncios y su estado de cumplimiento de 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

Acciones de conversión

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

Patrón de ejecución en 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

Paso 6: operaciones de escritura con validate_only

Los ejemplos siguientes usan objetos de solicitud en lugar de argumentos con nombre porque el objeto de solicitud contiene validate_only. Cada servicio de modificación (CampaignService, AdGroupService, AdGroupCriterionService, CampaignBudgetService) sigue el mismo patrón:

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)

Puntos clave de este patrón (con use_proto_plus: true):

  • validate_only es un campo en el objeto de solicitud, no un argumento con nombre del método de modificación
  • Las operaciones se añaden mediante req.operations.append(op); .add() pertenece a la interfaz protobuf simple (use_proto_plus: false)
  • Aquí las rutas de recursos se escriben como cadenas explícitas ('customers/1305475941/campaigns/22479990461'); los servicios también proporcionan métodos auxiliares para rutas como campaign_service.campaign_path(customer_id, campaign_id), que Google recomienda en lugar de construir los nombres manualmente

Control de modificaciones en tres fases

Por seguridad en producción, las modificaciones pasan por tres controles:

Control 1 — validate_only=True: La API valida la estructura de la solicitud, los campos obligatorios y las referencias a recursos. No se crea ningún objeto. Ejecute esto primero para cada modificación.

Control 2 — Creación en pausa: Establezca validate_only=False y cree el objeto con status=PAUSED. Verifique el resultado con una consulta de lectura antes de continuar.

Control 3 — Activación en producción: Una llamada separada a la API que actualiza solo el campo status a ENABLED. Esto debe requerir aprobación explícita, no integrarse en la creación.

# 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)

Actualización de presupuesto

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)

Actualización de la puja de un grupo de anuncios

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)

Creación de palabra clave

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)

Manejo de errores

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 error comunes y su significado:

Código de errorCausa
RESOURCE_NOT_FOUNDEl recurso referenciado no existe, se eliminó o tiene un nombre de recurso mal formado
DEVELOPER_TOKEN_NOT_APPROVEDToken con acceso de prueba utilizado con una cuenta de producción (CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION desde la retirada de septiembre de 2026)
REQUIREDFalta un campo obligatorio (p. ej., estrategia de puja en la creación de campaña)
UNRECOGNIZED_FIELDCampo de una versión de API diferente o nombre de campo incorrecto
INVALID_ARGUMENTEl valor del campo no supera la validación (p. ej., presupuesto negativo)
PERMISSION_DENIEDEl usuario OAuth no tiene acceso a la cuenta de destino

Niveles de acceso a la API

El acceso a la API de Google Ads es escalonado, no binario:

NivelAprovisionamientoLectura (producción)Escritura (producción)Escritura (cuentas de prueba)Límite diario de operaciones
acceso de pruebaInmediato (desde API Center del MCC hasta septiembre de 2026; ahora automático al habilitar la API en el proyecto de Cloud)❌❌✅15.000
acceso de explorador (incluido a octubre de 2026)Solicitud en la página de descripción general de Cloud Console✅✅ (algunos servicios restringidos)✅2.880 en producción / 15.000 en pruebas
acceso básicoSolicitud + revisión de cumplimiento✅✅✅15.000
acceso estándarSolicitud tras obtener acceso básico + auditoría manual✅✅✅Ilimitado

El acceso de prueba es suficiente para el desarrollo con cuentas de prueba de Google Ads: autenticación, consultas GAQL, pruebas validate_only y lectura/escritura completa. El salto al acceso básico depende de la revisión de cumplimiento, no del gasto.

El acceso estándar elimina el límite diario de operaciones (siguen aplicándose los límites de frecuencia de solicitudes por función). Requiere una solicitud por separado, disponible solo después de obtener acceso básico, y una auditoría manual; la documentación de Google sobre los niveles de acceso no indica ningún umbral de gasto.

Cuentas de prueba

Las cuentas de prueba son cuentas gratuitas de Google Ads sin facturación que nunca publican anuncios. Las cuentas de prueba y de producción no pueden interactuar, por lo que una cuenta de prueba no puede depender de su MCC de producción: cree una cuenta de administrador de prueba independiente tras iniciar sesión con una cuenta de Google que no esté vinculada a su MCC de producción, cree cuentas de cliente de prueba bajo ella y use una como customer_id de destino (con el administrador de prueba como login_customer_id) durante el desarrollo con acceso de prueba.

validate_only en los distintos niveles de acceso

validate_only=True funciona en todos los niveles de acceso, pero el acceso de prueba sigue rechazando modificaciones validate_only en cuentas de producción con el mismo error de autorización que cualquier otra solicitud. Esto no es una limitación de validate_only — es el mismo control de acceso aplicado a todas las operaciones de escritura independientemente de la opción validate_only.

Seguimiento de conversiones: lectura de la API frente al estado funcional

La interfaz de Google Ads puede mostrar «Configurar seguimiento de conversiones» como recomendación incluso cuando existe una acción de conversión habilitada. La API puede confirmar la existencia de una acción de conversión (tipo WEBPAGE, categoría PURCHASE, estado ENABLED, include_in_conversions_metric: true), pero esto solo demuestra que el objeto de acción existe. No demuestra que el sitio web emita el evento AW-.../label correspondiente, que la etiqueta de Google esté cargada o que se haya recibido una señal de conversión.

Al auditar el seguimiento de conversiones, separe la verificación por API (metadatos de la acción de conversión) de la verificación por navegador (pestaña de red, carga de etiquetas, emisión de eventos). La API es la fuente de referencia para la configuración; el navegador es la fuente de referencia para la ejecución.

El patrón de atribución de ingresos en el backend se aplica aquí: si los eventos de conversión del lado del cliente no son fiables, planifique la carga de conversiones desde el servidor o sin conexión mediante el ConversionUploadService de la API de Google Ads como alternativa de respaldo.

Versionado de la API

La biblioteca de Python google-ads incluye múltiples versiones de la API. A octubre de 2026, la última versión (34.0.0) añade v26, y v22 y anteriores se han eliminado de la biblioteca. Cada versión añade, declara obsoletos o elimina campos GAQL y métodos de servicio.

Reglas para la selección de versión:

  • Especifique la versión explícitamente en load_from_storage(version='v22'). La predeterminada puede estar obsoleta.
  • Consulte las notas de versión de la API de Google Ads para conocer los campos declarados obsoletos antes de actualizar.
  • El método search_stream está disponible en todas las versiones actuales y es la ruta de lectura recomendada.
  • use_proto_plus debe establecerse explícitamente (true o false); selecciona la interfaz de mensajes de Python, no una versión de la API.
  • El patrón de objeto de solicitud para modificaciones (mutate_campaigns(request=req)) contiene campos de la solicitud como validate_only; los ejemplos actuales de Google siguen pasando customer_id y operations como argumentos con nombre para las modificaciones simples.

Seguridad local

Todos los archivos de credenciales deben permanecer fuera del control de versiones:

~/.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 el repositorio de trabajo, añada un .gitignore:

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

Un archivo de plantilla con valores de ejemplo puede incluirse en el repositorio para documentar la estructura 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 obligatorios para operaciones comunes

OperaciónCampos obligatorios
Crear campaña (Search)name, status, advertising_channel_type, campaign_budget, manual_cpc o estrategia de puja, contains_eu_political_advertising
Crear grupo de anuncios (Search)name, status, type_, cpc_bid_micros, campaign
Crear palabra clavead_group, status, keyword.text, keyword.match_type
Actualizar estado de campañaresource_name, status, update_mask (rutas: ['status'])
Actualizar presupuestoresource_name, amount_micros, update_mask (rutas: ['amount_micros'])

La ausencia de un campo obligatorio devuelve REQUIRED con el nombre del campo. La ausencia de update_mask en una operación de actualización se rechaza con FieldMaskError.FIELD_MASK_MISSING.

Script de prueba abreviado

Un script abreviado (las listas de campos y los filtros GAQL están abreviados con ... y los identificadores son marcadores de posición, por lo que debe completarlos antes de ejecutarlo) que lee todos los tipos de entidad y ejecuta pruebas de escritura 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.')

Referencias

Artículos relacionados