API Google Ads : configuration, authentification, lecture et écriture
Un guide technique pour la mise en place d’un accès programmatique à Google Ads — de l’architecture au premier appel API. Couvre la configuration MCC, OAuth 2.0, les niveaux d’accès du jeton développeur, la bibliothèque Python google-ads, les requêtes de lecture GAQL et le schéma d’écriture validate_only.
Mise à jour (octobre 2026) : Google a supprimé les jetons développeur le 9 septembre 2026. Les niveaux d’accès à l’API sont désormais attribués par projet Google Cloud et gérés sur la page de présentation de l’API Google Ads dans la Cloud Console ; l’en-tête developer-token est facultatif et ignoré, et le Centre API ne gère plus les inscriptions ni les changements d’accès. Google indique que le code existant continue de fonctionner. Les étapes ci-dessous concernant les jetons développeur et le Centre API décrivent la configuration telle qu’elle a été publiée en juin 2026. La configuration actuelle est présentée dans notre article de suivi, Accès à l'API Google Ads en 2026 : les projets Cloud remplacent les Developer Tokens.
Architecture
Trois entités distinctes sont nécessaires pour pouvoir effectuer le premier appel API :
| Entité | Rôle | Exemple |
|---|---|---|
| Compte administrateur (MCC) | Émet le jeton développeur | login_customer_id |
| Projet Google Cloud | Client OAuth 2.0 pour l’authentification | Identifiant client + secret |
| Compte Google Ads | Cible de toutes les opérations API | customer_id |
Il ne s’agit pas du même compte. Un MCC peut posséder un jeton développeur sans posséder le compte cible — il doit seulement être lié en tant qu’administrateur. Le projet Google Cloud peut être associé à une identité Google différente de celle du MCC. Le compte cible est le compte annonceur où se trouvent les campagnes.
Cette séparation est importante car le Centre API (où les jetons développeur sont délivrés) n’est disponible qu’à l’intérieur des comptes administrateur. Un compte Google Ads autonome ne peut pas accéder au Centre API, même s’il dispose d’utilisateurs administrateurs.
L’en-tête d’appel API assemble ces trois identités plus un jeton OAuth Bearer :
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érequis
- Un compte administrateur Google Ads avec une configuration complète
- Le compte publicitaire cible lié au compte administrateur et le lien accepté
- Un projet Google Cloud avec l’API Google Ads activée
- Python 3.9+ avec la bibliothèque
google-ads(pip install google-ads) - Un navigateur pour le procédure de consentement OAuth à effectuer une seule fois
Étape 1 : compte administrateur et jeton développeur
Le Centre API se trouve sous Outils et paramètres → Configuration → Centre API dans un compte administrateur. Si le Centre API est absent, le compte n’est soit pas un compte administrateur, soit sa configuration est incomplète.
Depuis le Centre API, demandez un jeton développeur. Définissez le type de compte sur Annonceur (et non Agence ou Tiers) lorsque le jeton est destiné à vos propres comptes. Le jeton est émis immédiatement au niveau accès test.
L’accès test permet :
- Les opérations de lecture sur les comptes de test uniquement
- Les opérations d’écriture sur les comptes de test uniquement
- Aucune opération de lecture ou d’écriture sur les comptes de production
Les requêtes sur les comptes de production avec l’accès test échouent avec DEVELOPER_TOKEN_NOT_APPROVED (« The developer token is only approved for use with test accounts »). Depuis la suppression des jetons développeur en septembre 2026, les versions actuelles de l’API renvoient à la place CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION (ACTION_NOT_PERMITTED dans v24 et les versions antérieures).
Demande d’accès de base
Pour accéder aux comptes de production, faites une demande d’accès de base depuis la même page du Centre API. Le formulaire de demande comporte 12 questions. Pour un usage interne sur vos propres comptes, les réponses pertinentes sont :
| Question | Réponse |
|---|---|
| Q4 : Relation avec un représentant Google | Non |
| Q6 : Modèle économique | Décrivez votre propre cas d’usage (e-commerce, génération de prospects, rapports internes) |
| Q8 : Qui aura accès | Utilisateurs internes — employés uniquement |
| Q9 : Outil développé par un tiers | Non (scripts/agents internes) |
| Q10 : API de suivi des conversions et de remarketing | Non (sauf si vous l’utilisez réellement) |
| Q11 : Types de campagnes | Search, Performance Max, Shopping (selon le cas) |
| Q12 : Capacités | Création de campagnes, gestion de campagnes, production de rapports |
Un document de conception (PDF) est requis pour la Q7. Il doit décrire l’architecture de l’API, le flux d’authentification, la stratégie de limitation de débit, la gestion des erreurs et le cas d’usage exclusivement interne. Restez factuel — l’équipe de conformité vérifie la cohérence avec le cas d’usage déclaré.
Délai de traitement en juin 2026 : environ 3 jours ouvrés, avec une note concernant un volume de demandes plus élevé que d’habitude.
Étape 2 : OAuth 2.0
Configuration du projet Google Cloud
Dans la console Google Cloud, sous le projet concerné :
- Activez l’API Google Ads (API et services → Bibliothèque)
- Configurez l’écran de consentement OAuth :
- Type d’utilisateur : Interne (seuls les utilisateurs de votre Google Workspace peuvent autoriser l’application — ce qui évite la vérification des applications externes)
- Nom de l’application, adresse e-mail d’assistance, adresse e-mail de contact du développeur
- Ajoutez le champ d’application sous Accès aux données :
https://www.googleapis.com/auth/adwords - Créez un identifiant client OAuth :
- Type d’application : Application de bureau
- Téléchargez le fichier JSON du secret client
Le type Application de bureau utilise http://localhost comme URI de redirection. C’est correct — le flux OAuth ouvre un navigateur, Google redirige vers localhost avec le code d’autorisation, et un serveur HTTP local le capture.
Génération du jeton d’actualisation
Un script Python minimal (il ne vérifie pas le paramètre state renvoyé et ne définit pas les droits d’accès au fichier de jetons ; ajoutez ces deux protections avant de l’utiliser au-delà d’une exécution locale ponctuelle) qui exécute un serveur HTTP local sur 127.0.0.1:0 (port aléatoire), affiche l’URL d’autorisation, attend une requête, extrait le paramètre code et l’échange contre des jetons :
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())
Deux paramètres sont importants :
access_type='offline'— renvoie un jeton d’actualisation, pas seulement un jeton d’accèsprompt='consent'— force un nouvel écran de consentement même si l’utilisateur a déjà autorisé ; nécessaire pour obtenir un nouveau jeton d’actualisation si les champs d’application ont changé
Le jeton d’actualisation n’a pas de durée de vie fixe, mais cesse de fonctionner si l’utilisateur révoque l’accès, s’il reste inutilisé pendant six mois, si l’utilisateur change son mot de passe (pour les jetons ayant des champs d’application Gmail), si le compte dépasse la limite Google de jetons d’actualisation actifs ou si un administrateur Workspace restreint le champ d’application ou impose une durée de session. Prévoyez une nouvelle autorisation.
Piège des champs d’application avec des clients existants
Si l’URL d’autorisation définit include_granted_scopes=true et que l’utilisateur a précédemment accordé à ce client OAuth d’autres champs d’application (Gmail, Drive, Calendar), Google renvoie l’union des anciens et des nouveaux champs d’application. La bibliothèque google-auth-oauthlib rejette cette divergence de champs d’application par défaut. Définissez la variable d’environnement avant de charger le flux :
import os
os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'
Vous pouvez aussi omettre include_granted_scopes=true de l’URL d’autorisation (le script ci-dessus ne le définit pas), afin que le jeton couvre uniquement le champ d’application explicitement demandé.
Étape 3 : google-ads.yaml
La bibliothèque lit la configuration depuis un fichier YAML :
developer_token: <value>
client_id: <value>
client_secret: <value>
refresh_token: <value>
login_customer_id: 1911599764
use_proto_plus: true
Règles de sécurité :
- Droits d’accès au fichier :
0600(lecture/écriture réservées au propriétaire) - Ne jamais versionner dans un dépôt Git
- Stocker en dehors de tout dépôt Git
- Pour les configurations d’équipe, distribuer via un gestionnaire de secrets, pas un fichier partagé
login_customer_id est l’identifiant numérique du MCC sans tirets. Il indique à l’API par quel compte administrateur l’utilisateur authentifié accède au compte cible et est requis dès que l’accès passe par un compte administrateur. Le customer_id cible est passé au moment de l’appel, pas dans la configuration.
use_proto_plus est une clé de configuration obligatoire : true sélectionne l’interface de messages proto-plus utilisée dans ce guide, false sélectionne les messages protobuf simples, que Google recommande pour les traitements sensibles aux performances.
Étape 4 : initialisation du client 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')
Le paramètre version sélectionne explicitement la version de l’API. La bibliothèque google-ads est livrée avec plusieurs versions installées en parallèle ; les exemples présentés ici utilisent v22. En octobre 2026, les versions actuelles de la bibliothèque n’incluent plus v22 (supprimée dans 33.0.0) et la version 34.0.0 ajoute v26 : utilisez donc une version actuelle à la place. Spécifiez toujours la version — la valeur par défaut peut être en retard ou ne pas prendre en charge les champs plus récents.
Vérifiez la connectivité :
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']
Étape 5 : opérations de lecture (GAQL)
Google Ads utilise GAQL (Google Ads Query Language), un langage de type SQL. Toutes les opérations de lecture passent par GoogleAdsService.search_stream(), qui évite la pagination et est préféré à search() pour la plupart des requêtes.
Campagnes et indicateurs de performance
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
Budgets de campagne
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
Groupes d’annonces
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
Mots-clés (par nombre d’impressions)
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
Annonces et statut de conformité aux règles
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
Actions de conversion
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
Schéma d’exécution 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
Étape 6 : opérations d’écriture avec validate_only
Les exemples ci-dessous utilisent des objets de requête plutôt que des arguments nommés, car l’objet de requête contient validate_only. Chaque service de mutation (CampaignService, AdGroupService, AdGroupCriterionService, CampaignBudgetService) suit le même schéma :
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)
Points clés de ce schéma (avec use_proto_plus: true) :
validate_onlyest un champ de l’objet requête, pas un argument nommé de la méthode de mutation- Les opérations sont ajoutées via
req.operations.append(op);.add()appartient à l’interface protobuf simple (use_proto_plus: false) - Les chemins de ressources sont écrits ici sous forme de chaînes explicites (
'customers/1305475941/campaigns/22479990461') ; les services proposent aussi des méthodes utilitaires commecampaign_service.campaign_path(customer_id, campaign_id), que Google recommande plutôt que de construire les noms manuellement
Contrôle des mutations en trois phases
Pour la sécurité en production, les mutations passent par trois points de contrôle :
Point de contrôle 1 — validate_only=True : L’API valide la structure de la requête, les champs obligatoires et les références de ressources. Aucun objet n’est créé. Exécutez ceci en premier pour chaque mutation.
Point de contrôle 2 — Création en pause : Passez validate_only=False et créez l’objet avec status=PAUSED. Vérifiez le résultat avec une requête de lecture avant de continuer.
Point de contrôle 3 — Activation en production : Un appel API séparé qui met à jour uniquement le champ status à ENABLED. Cela devrait nécessiter une approbation explicite et ne pas être intégré dans la création.
# 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)
Mise à jour du budget
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)
Mise à jour de l’enchère d’un groupe d’annonces
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)
Création d’un mot-clé
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)
Gestion des erreurs
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}')
Codes d’erreur courants et leur signification :
| Code d’erreur | Cause |
|---|---|
RESOURCE_NOT_FOUND | La ressource référencée n’existe pas, a été supprimée ou porte un nom de ressource mal formé |
DEVELOPER_TOKEN_NOT_APPROVED | Jeton d’accès test sur un compte de production (CLOUD_PROJECT_NOT_APPROVED_FOR_PRODUCTION depuis la suppression des jetons développeur en septembre 2026) |
REQUIRED | Champ obligatoire manquant (ex. stratégie d’enchère lors de la création d’une campagne) |
UNRECOGNIZED_FIELD | Champ d’une version d’API différente ou nom de champ incorrect |
INVALID_ARGUMENT | La valeur du champ ne passe pas la validation (ex. budget négatif) |
PERMISSION_DENIED | L’utilisateur OAuth n’a pas accès au compte cible |
Niveaux d’accès à l’API
L’accès à l’API Google Ads est par paliers, pas binaire :
| Niveau | Attribution | Lecture (production) | Écriture (production) | Écriture (comptes de test) | Limite d’opérations quotidiennes |
|---|---|---|---|---|---|
| accès test | Immédiat (depuis le Centre API du MCC jusqu’en septembre 2026 ; désormais automatique lors de l’activation de l’API dans le projet Cloud) | ❌ | ❌ | ✅ | 15 000 |
| accès explorateur (répertorié en octobre 2026) | Demande sur la page de présentation de la Cloud Console | ✅ | ✅ (certains services restreints) | ✅ | 2 880 en production / 15 000 en test |
| accès de base | Demande + examen de conformité | ✅ | ✅ | ✅ | 15 000 |
| accès standard | Demande après l’accès de base + audit manuel | ✅ | ✅ | ✅ | Illimité |
L’accès test est suffisant pour le développement sur les comptes de test Google Ads : authentification, requêtes GAQL, tests validate_only et lecture/écriture complète. Le passage à l’accès de base est conditionné par un examen de conformité, pas par les dépenses.
L’accès standard supprime le plafond d’opérations quotidiennes (les limites de débit par fonctionnalité restent applicables). Il nécessite une demande séparée, disponible uniquement après l’obtention de l’accès de base, et un audit manuel ; la documentation Google sur les niveaux d’accès ne mentionne aucun seuil de dépenses.
Comptes de test
Les comptes de test sont des comptes Google Ads gratuits sans facturation qui ne diffusent jamais d’annonces. Les comptes de test et de production ne peuvent pas interagir ; un compte de test ne peut donc pas se trouver sous votre MCC de production : créez un compte administrateur de test distinct en étant connecté avec un compte Google qui n’est pas lié à votre MCC de production, créez des comptes clients de test sous ce compte administrateur et utilisez l’un d’eux comme customer_id cible (avec le compte administrateur de test comme login_customer_id) pendant le développement avec l’accès test.
validate_only selon les niveaux d’accès
validate_only=True fonctionne à tous les niveaux d’accès, mais l’accès test rejette tout de même les mutations validate_only sur les comptes de production avec la même erreur d’autorisation que toute autre requête. Ce n’est pas une limitation de validate_only — c’est le même contrôle d’accès appliqué à toutes les opérations d’écriture, indépendamment du paramètre validate_only.
Suivi des conversions : lecture de l’API et fonctionnement réel
L’interface Google Ads peut afficher « Configurer le suivi des conversions » comme recommandation même lorsqu’une action de conversion existe et est activée. L’API peut confirmer l’existence d’une action de conversion (type WEBPAGE, catégorie PURCHASE, statut ENABLED, include_in_conversions_metric: true), mais cela prouve seulement que l’objet d’action existe. Cela ne prouve pas que le site web émet l’événement AW-.../label correspondant, que la balise Google est chargée, ou qu’un signal de conversion a été reçu.
Lors de l’audit du suivi des conversions, séparez la vérification API (métadonnées de l’action de conversion) de la vérification navigateur (onglet réseau, chargement de la balise, déclenchement des événements). L’API est le référentiel pour la configuration ; le navigateur est le référentiel pour l’exécution.
Le schéma d’attribution de revenus côté serveur s’applique ici : si les événements de conversion côté client ne sont pas fiables, prévoyez des envois de conversions côté serveur ou hors ligne via le ConversionUploadService de l’API Google Ads comme solution de repli.
Gestion des versions de l’API
La bibliothèque Python google-ads est livrée avec plusieurs versions de l’API. En octobre 2026, la dernière version (34.0.0) ajoute v26, et v22 ainsi que les versions antérieures ont été supprimées de la bibliothèque. Chaque version ajoute, déprécie ou supprime des champs GAQL et des méthodes de service.
Règles pour la sélection de version :
- Spécifiez la version explicitement dans
load_from_storage(version='v22'). La valeur par défaut peut être obsolète. - Consultez les notes de version de l’API Google Ads pour les dépréciations de champs avant de mettre à niveau.
- La méthode
search_streamest disponible dans toutes les versions actuelles et constitue le chemin de lecture recommandé. use_proto_plusdoit être défini explicitement (trueoufalse) ; il sélectionne l’interface de messages Python, pas une version de l’API.- Le schéma d’objet de requête pour les mutations (
mutate_campaigns(request=req)) contient les champs au niveau de la requête tels quevalidate_only; les exemples actuels de Google passent toujourscustomer_idetoperationscomme arguments nommés pour les mutations simples.
Sécurité locale
Tous les fichiers d’identifiants d’authentification doivent rester en dehors du contrôle de version :
~/.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
Pour le dépôt de travail, ajoutez un .gitignore :
google-ads.yaml
*_token*.json
*_secret*.json
Un fichier modèle avec des valeurs de substitution peut être versionné pour documenter la structure attendue :
# 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
Champs requis pour les opérations courantes
| Opération | Champs requis |
|---|---|
| Créer une campagne (Search) | name, status, advertising_channel_type, campaign_budget, manual_cpc ou stratégie d’enchère, contains_eu_political_advertising |
| Créer un groupe d’annonces (Search) | name, status, type_, cpc_bid_micros, campaign |
| Créer un mot-clé | ad_group, status, keyword.text, keyword.match_type |
| Mettre à jour le statut d’une campagne | resource_name, status, update_mask (chemins : ['status']) |
| Mettre à jour un budget | resource_name, amount_micros, update_mask (chemins : ['amount_micros']) |
L’absence d’un champ requis renvoie REQUIRED avec le nom du champ. L’absence de update_mask sur une opération de mise à jour est rejetée avec FieldMaskError.FIELD_MASK_MISSING.
Script de test condensé
Un script condensé (les listes de champs GAQL et les filtres sont abrégés par ... et les identifiants sont des valeurs de remplacement à renseigner avant l’exécution) qui lit tous les types d’entités et exécute des tests d’écriture 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.')
Références
- Documentation de l’API Google Ads
- Bibliothèque Python google-ads
- Référence GAQL
- OAuth 2.0 pour applications de bureau
- Construire un assistant IA propre à un projet via Telegram — même schéma OAuth appliqué à un champ d’application Google différent
- Architecture de référence pour une couche d’opérations IA fondée sur des threads — le modèle opérationnel dans lequel l’automatisation API s’intègre
- Opérations individuelles à grande échelle : gérer des dizaines de projets avec une petite équipe — pourquoi l’automatisation API remplace le travail manuel dans l’interface à l’échelle