Un premier appel GET
Exemple avec l’API publique et gratuite geo.api.gouv.fr, qui ne demande pas de clé : retrouver la
commune et sa population à partir d’un code postal.
function testApi() {
const url = 'https://geo.api.gouv.fr/communes?codePostal=59193&fields=nom,population';
const reponse = UrlFetchApp.fetch(url);
const communes = JSON.parse(reponse.getContentText());
Logger.log(communes); // [{nom=Erquinghem-Lys, population=…, code=…}]
}
L’API renvoie un tableau JSON ; JSON.parse le transforme en tableau d’objets
JavaScript, que l’on parcourt comme n’importe quel tableau.
Remplir une colonne du classeur avec la réponse
Onglet Codes : les codes postaux en colonne A, le script remplit la ou les communes (B) et la population (C, celle de la première commune quand un code postal en couvre plusieurs).
function completerCommunes() {
const feuille = SpreadsheetApp.getActive().getSheetByName('Codes');
const derniere = feuille.getLastRow();
if (derniere < 2) return;
const codes = feuille.getRange(2, 1, derniere - 1, 1).getValues();
const resultats = codes.map(([cp]) => {
if (!cp) return ['', ''];
const url = 'https://geo.api.gouv.fr/communes?codePostal=' +
encodeURIComponent(String(cp).padStart(5, '0')) + '&fields=nom,population';
const rep = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
if (rep.getResponseCode() !== 200) return ['Erreur ' + rep.getResponseCode(), ''];
const communes = JSON.parse(rep.getContentText());
if (communes.length === 0) return ['Introuvable', ''];
return [communes.map(c => c.nom).join(', '), communes[0].population || ''];
});
feuille.getRange(2, 2, resultats.length, 2).setValues(resultats); // une seule écriture
}
Deux réflexes à garder : encodeURIComponent pour tout paramètre inséré dans une URL
(accents, espaces, &), et une seule écriture avec setValues à la fin
plutôt qu’un setValue par ligne, beaucoup plus lent. padStart remet le zéro initial que
Sheets supprime quand un code postal comme 02100 est saisi comme un nombre.
Un appel POST en JSON avec une clé API
La plupart des API (CRM, facturation, outils d’e-mailing) attendent une clé dans un en-tête et un corps JSON. La clé est lue dans les propriétés du script, jamais écrite dans le code :
function envoyerContact(contact) {
const cle = PropertiesService.getScriptProperties().getProperty('API_KEY');
if (!cle) throw new Error('Propriété API_KEY manquante.');
const rep = UrlFetchApp.fetch('https://api.exemple.com/v1/contacts', {
method: 'post',
contentType: 'application/json',
headers: { Authorization: 'Bearer ' + cle },
payload: JSON.stringify(contact),
muteHttpExceptions: true,
});
const code = rep.getResponseCode();
if (code < 200 || code >= 300) {
throw new Error('API ' + code + ' : ' + rep.getContentText().slice(0, 300));
}
return JSON.parse(rep.getContentText());
}
L’URL api.exemple.com est à remplacer par celle de votre service, et le format de l’en-tête par celui
que sa documentation indique (Bearer, X-API-Key, authentification basique…). Pour une
authentification basique, l’en-tête se construit avec
'Basic ' + Utilities.base64Encode(identifiant + ':' + motDePasse).
Sans JSON.stringify, un objet passé en payload est envoyé comme un formulaire
(application/x-www-form-urlencoded), ce que beaucoup d’API JSON refusent.
Gérer les erreurs
Par défaut, fetch lève une exception dès que le serveur répond avec un code d’erreur (4xx, 5xx), et le
message ne contient qu’une partie de la réponse. Avec muteHttpExceptions: true, vous récupérez la
réponse complète et décidez quoi faire :
| Code | Signification habituelle | Réaction |
|---|---|---|
| 401 / 403 | Clé absente, invalide ou sans droits | Vérifier la propriété et les droits de la clé |
| 404 | Ressource ou URL inexistante | Vérifier l’URL et les identifiants |
| 429 | Trop de requêtes | Attendre puis réessayer |
| 500 à 599 | Erreur côté serveur | Réessayer plus tard |
function fetchAvecReessai(url, options, essais = 3) {
for (let n = 1; n <= essais; n++) {
const rep = UrlFetchApp.fetch(url, Object.assign({ muteHttpExceptions: true }, options));
const code = rep.getResponseCode();
if (code !== 429 && code < 500) return rep;
Utilities.sleep(1000 * Math.pow(2, n)); // 2 s, 4 s, 8 s
}
throw new Error('API indisponible après ' + essais + ' essais : ' + url);
}
Plusieurs appels en parallèle avec fetchAll
Quand il faut interroger l’API pour des dizaines de lignes, UrlFetchApp.fetchAll envoie les requêtes
en parallèle et renvoie les réponses dans le même ordre :
const requetes = ['59193', '59000', '59280'].map(cp => ({
url: 'https://geo.api.gouv.fr/communes?codePostal=' + cp + '&fields=nom',
muteHttpExceptions: true,
}));
const reponses = UrlFetchApp.fetchAll(requetes);
reponses.forEach(r => Logger.log(r.getResponseCode() + ' ' + r.getContentText()));
C’est souvent ce qui permet à un traitement de rester sous la limite de 6 minutes par exécution. Respectez quand même les limites de débit de l’API appelée : envoyez les requêtes par paquets si elle renvoie des 429.
Éviter de rappeler l’API à chaque fois : le cache
function getTaux() {
const cache = CacheService.getScriptCache();
const enCache = cache.get('TAUX');
if (enCache) return JSON.parse(enCache);
const rep = UrlFetchApp.fetch('https://api.exemple.com/v1/taux', { muteHttpExceptions: true });
if (rep.getResponseCode() !== 200) throw new Error('API ' + rep.getResponseCode());
cache.put('TAUX', rep.getContentText(), 3600); // garde la réponse 1 heure
return JSON.parse(rep.getContentText());
}
Pour des données qui changent peu (taux, listes de référence, catalogues), le cache réduit le nombre d’appels, donc le risque de dépasser les quotas, et accélère le script.
Quotas et limites
| Limite (page des quotas Google) | gmail.com | Google Workspace |
|---|---|---|
| Appels UrlFetch par jour | 20 000 | 100 000 |
| Taille d’une réponse | 50 Mo | 50 Mo |
| Taille d’un envoi POST | 50 Mo | 50 Mo |
| Longueur de l’URL | 2 Ko | 2 Ko |
| Nombre d’en-têtes par appel | 100 | 100 |
Les requêtes partent des serveurs de Google, pas de votre poste : une API accessible uniquement depuis le réseau de l’entreprise (intranet, serveur sans adresse publique) ne sera pas joignable depuis Apps Script.
Questions fréquentes
Peut-on appeler une API depuis une fonction personnalisée (=MAFONCTION()) ?
Oui, UrlFetchApp fait partie des services autorisés dans une fonction personnalisée. Mais elle est
recalculée souvent et limitée à 30 secondes : pour plus de quelques cellules, préférez un script lancé par un menu
ou un déclencheur temporisé qui écrit les valeurs.
Comment recevoir des données (webhook) plutôt que les demander ?
Un script publié comme application web avec une fonction doPost(e) peut recevoir des requêtes d’un
autre service et écrire dans le classeur. C’est le sens inverse de UrlFetchApp.
IMPORTDATA ou UrlFetchApp ?
IMPORTDATA ou IMPORTXML suffisent pour lire un fichier CSV ou une page publique sans clé.
Dès qu’il faut une clé API, du JSON, un POST ou un traitement des erreurs, il faut passer par Apps Script.
Connecter Google Sheets à des API fait partie de la formation Google Apps Script. Pour relier vos fichiers à un CRM, un outil de facturation ou une application métier, voir l’automatisation Google Sheets sur mesure, et pour envoyer le résultat par e-mail, envoyer des e-mails depuis Google Sheets.