---
title: "Enviar WhatsApp pela planilha do Google Sheets (Apps Script + API)"
description: "Envie WhatsApp a partir do Google Sheets com Apps Script e a API não oficial: coluna de status, espaçamento, tratamento de 429 e confirmação do Google Forms."
url: "https://wame.api.br/blog/enviar-whatsapp-google-sheets-apps-script"
language: "pt-BR"
og:type: "article"
published_time: "2026-09-28"
modified_time: "2026-09-28"
author: "Raphael Serafim"
keywords: "api whatsapp não oficial, api não oficial whatsapp, enviar whatsapp google sheets, whatsapp apps script, planilha enviar whatsapp, google forms whatsapp confirmação, urlfetchapp whatsapp api"
reading_time: "9 min de leitura"
---

# Enviar WhatsApp pela planilha do Google Sheets (Apps Script + API)

> Envie WhatsApp a partir do Google Sheets com Apps Script e a API não oficial: coluna de status, espaçamento, tratamento de 429 e confirmação do Google Forms.

**Dá para enviar WhatsApp direto do Google Sheets com o Apps Script, que já vem na planilha: cada linha vira uma chamada `POST /{key}/message/text` na API não oficial da WAME, feita com `UrlFetchApp`, e o script anota o resultado numa coluna de status. Com três cuidados — chave guardada fora da planilha, envio só para quem consentiu e parada quando a API responder `429` —, a planilha vira uma automação confiável para confirmações, lembretes e avisos.**

Planilha é onde muita operação pequena vive: a lista de inscritos do evento, as consultas da semana, os pedidos do dia. Levar essa lista para o WhatsApp sem sair do Google Sheets resolve muita coisa sem precisar de servidor. Este tutorial monta o script completo, do primeiro envio ao gatilho do Google Forms.

## A planilha

Crie uma aba chamada `Envios` com estas colunas:

| A | B | C | D | E | F |
| --- | --- | --- | --- | --- | --- |
| Nome | Telefone | Mensagem | Consentiu | Status | Enviado em |
| Ana | 5511999999999 | Sua consulta é amanhã às 14h. | SIM | | |
| Bruno | 5521988888888 | Seu pedido saiu para entrega. | SIM | | |

Algumas regras:

- **Telefone** no formato internacional, só dígitos: código do país, DDD e número. Formate a coluna como texto para o Sheets não transformar em notação científica.
- **Consentiu** é a trava de segurança. O script só envia nas linhas com `SIM`.
- **Status** e **Enviado em** são preenchidos pelo script. Linha com status já preenchido não é enviada de novo.

## Guarde a chave fora da planilha

A `key` da instância autentica o envio. Se ela estiver numa célula, qualquer pessoa com acesso de leitura à planilha pode mandar mensagem pelo seu número. Guarde nas propriedades do script:

1. Na planilha, abra **Extensões > Apps Script**.
2. Em **Configurações do projeto**, na seção **Propriedades do script**, adicione `WAME_KEY` com a chave da sua instância.

No código, leia assim:

```js
function chave() {
  const key = PropertiesService.getScriptProperties().getProperty('WAME_KEY');
  if (!key) throw new Error('Defina WAME_KEY nas propriedades do script.');
  return key;
}
```

## Enviar uma mensagem

O envio é um POST com `UrlFetchApp`. O `muteHttpExceptions` faz o Apps Script devolver a resposta mesmo quando o status é erro, para você decidir o que fazer:

```js
function enviarTexto(telefone, texto) {
  const url = 'https://server.wame.api.br/' + chave() + '/message/text';
  const resposta = UrlFetchApp.fetch(url, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({ to: String(telefone), text: texto }),
    muteHttpExceptions: true,
  });
  return {
    codigo: resposta.getResponseCode(),
    corpo: resposta.getContentText(),
  };
}
```

Teste com o seu próprio número antes de rodar na lista.

## Percorrer a planilha com segurança

Agora o laço que lê as linhas, envia e anota. Ele pula o que já foi enviado, respeita o consentimento, espaça os envios e **para** se a API pedir:

```js
const ABA = 'Envios';
const COL = { nome: 0, tel: 1, msg: 2, consentiu: 3, status: 4, quando: 5 };
const LIMITE_POR_EXECUCAO = 40;

function enviarPendentes() {
  const aba = SpreadsheetApp.getActive().getSheetByName(ABA);
  const dados = aba.getDataRange().getValues();
  let enviados = 0;

  for (let i = 1; i < dados.length; i++) {
    const linha = dados[i];
    const status = String(linha[COL.status]);
    if (status && !status.startsWith('AGUARDANDO')) continue; // já tratado
    if (String(linha[COL.consentiu]).toUpperCase() !== 'SIM') continue;
    if (enviados >= LIMITE_POR_EXECUCAO) break;             // continua na próxima execução

    const texto = String(linha[COL.msg]).replace('{nome}', linha[COL.nome]);
    const r = enviarTexto(linha[COL.tel], texto);

    if (r.codigo === 429) {
      // A API pediu calma: pare aqui e deixe o resto para depois.
      aba.getRange(i + 1, COL.status + 1).setValue('AGUARDANDO (429)');
      break;
    }

    const ok = r.codigo >= 200 && r.codigo < 300;
    aba.getRange(i + 1, COL.status + 1).setValue(ok ? 'ENVIADO' : 'ERRO ' + r.codigo);
    aba.getRange(i + 1, COL.quando + 1).setValue(new Date());
    enviados++;

    // Espaçamento entre envios, com variação.
    Utilities.sleep(8000 + Math.floor(Math.random() * 7000));
  }
}
```

Por que cada detalhe está ali:

- **Coluna de status como memória.** Se o script parar no meio — erro, limite de tempo, `429` —, a próxima execução continua de onde parou sem mandar duas vezes para ninguém.
- **Limite por execução.** O Apps Script encerra execuções longas depois de alguns minutos. Processar um lote por vez e continuar num gatilho é mais seguro que tentar tudo de uma vez.
- **Espaçamento com variação.** Mensagens em intervalo fixo e curto têm cara de robô. Os valores acima são uma sugestão conservadora; ajuste ao seu caso, sempre sem pressa.
- **Personalização.** O `{nome}` na coluna de mensagem vira o nome da pessoa. Texto idêntico para muita gente é um dos padrões que o anti-spam procura — e que a própria API freia.

A linha marcada como `AGUARDANDO (429)` não conta como tratada: a próxima execução tenta de novo exatamente a partir dela.

## O que o 429 significa

A API não oficial da WAME tem freios contra padrões de disparo em massa. Ela responde `429` quando a instância fala com gente nova demais por minuto ou quando o mesmo texto vai para números demais em poucos minutos. É um sinal para desacelerar, não um erro para repetir em seguida.

Por isso o script **para** em vez de tentar de novo no mesmo instante. Insistir é exatamente o comportamento que transforma um freio em problema para o número. Se o `429` aparece com frequência, reveja a lista e o ritmo — os princípios estão em [fila, rate limit e retry](/blog/fila-rate-limit-retry-disparo-whatsapp).

## Rodar sozinho, de hora em hora

Para a planilha se esvaziar sem ninguém clicar, crie um gatilho de tempo. Rode esta função uma vez:

```js
function criarGatilhoDeHora() {
  ScriptApp.newTrigger('enviarPendentes')
    .timeBased()
    .everyHours(1)
    .create();
}
```

Cada execução processa um lote, e a próxima continua. Envios distribuídos ao longo do dia são mais naturais que uma rajada às 9h.

## Confirmação automática do Google Forms

Um uso excelente — e totalmente dentro das regras — é confirmar a inscrição de quem acabou de preencher um formulário. A pessoa acabou de pedir; a mensagem é esperada.

1. No Google Forms, vincule as respostas a uma planilha.
2. No Apps Script dessa planilha, crie a função que trata cada resposta:

```js
function aoEnviarFormulario(e) {
  const valores = e.namedValues;              // campos pelo título da pergunta
  const nome = valores['Nome'][0];
  const telefone = valores['WhatsApp'][0].replace(/\D/g, '');
  const aceitou = valores['Aceito receber confirmação pelo WhatsApp'][0];

  if (aceitou !== 'Sim') return;

  const r = enviarTexto(
    telefone,
    'Oi, ' + nome + '! Recebemos sua inscrição. Qualquer dúvida, é só responder aqui.'
  );
  if (r.codigo !== 200 && r.codigo !== 201) console.log('Falha no envio', r.codigo, r.corpo);
}
```

3. Crie o gatilho instalável de envio de formulário, rodando uma vez:

```js
function criarGatilhoDoFormulario() {
  ScriptApp.newTrigger('aoEnviarFormulario')
    .forSpreadsheet(SpreadsheetApp.getActive())
    .onFormSubmit()
    .create();
}
```

Ajuste os títulos das perguntas no `namedValues` para bater com o seu formulário. A pergunta de consentimento é a mesma trava da coluna `Consentiu`: sem ela, não envia.

Se você quiser validar que o número digitado tem WhatsApp antes de mandar, veja [como verificar se um número tem WhatsApp](/blog/verificar-numero-tem-whatsapp-api).

## O que não fazer com a planilha

Planilha facilita enviar para muita gente — e é justamente aí que mora o risco. A WAME não apoia spam, e nenhuma camada técnica salva um número que manda para quem não pediu:

- **Não importe lista comprada** nem contatos que não conhecem sua empresa.
- **Não remova a coluna de consentimento** para "ganhar tempo".
- **Não mande o mesmo texto para centenas de pessoas** de uma vez; personalize e distribua.
- **Ofereça uma saída.** Se alguém pedir para parar, marque na planilha e nunca mais envie. O processo está em [opt-in e opt-out automático](/blog/lista-contatos-optin-optout-whatsapp).

Usada para confirmar, lembrar e avisar quem pediu, a planilha tem risco de bloqueio muito baixo — ainda mais porque cada envio da API já sai com tempo humano de digitação.

> A camada não oficial da WAME não é afiliada, endossada ou suportada pelo WhatsApp ou pela Meta. O uso é de responsabilidade de quem envia.

## Quando sair da planilha

A planilha é ótima até precisar **receber** e reagir: responder ao cliente, abrir um atendimento, atualizar um CRM. Aí você precisa de um endpoint de webhook, e um script de planilha não é o lugar certo. Os próximos passos naturais são um [bot com a API não oficial](/blog/criar-bot-whatsapp-api-nao-oficial) ou um fluxo no n8n, como em [bot de IA com n8n](/blog/bot-ia-n8n-whatsapp-instagram-messenger).

## Conclusão

Com o Apps Script, o Google Sheets vira uma automação de WhatsApp sem servidor: `UrlFetchApp` chama a API não oficial, a coluna de status garante que ninguém recebe duas vezes e o gatilho de tempo esvazia a fila aos poucos. Guarde a chave nas propriedades do script, envie só para quem consentiu e pare quando a API responder `429`. A referência dos endpoints está na [documentação](/docs), e o panorama do que a camada não oficial oferece está em [vantagens da API não oficial](/blog/api-whatsapp-nao-oficial-vantagens).

## Perguntas frequentes

### Dá para enviar WhatsApp direto do Google Sheets?

Sim. Com o Apps Script, que já vem no Google Sheets, você chama a API não oficial da WAME com UrlFetchApp. Cada linha vira um POST em /{key}/message/text, e o script anota o resultado numa coluna de status.

### Onde guardo a chave da API no Apps Script?

Nas propriedades do script, com PropertiesService. Nunca numa célula da planilha: qualquer pessoa com acesso de leitura veria a chave e poderia enviar mensagens pelo seu número.

### O que fazer quando a API responde 429?

Parar o envio e retomar mais tarde. O 429 indica que a instância está falando com gente nova demais por minuto ou repetindo o mesmo texto para muitos números. O script deve encerrar a execução, deixar as linhas pendentes como estão e continuar num gatilho posterior.

### Posso usar a planilha para mandar mensagem para uma lista de contatos?

Só para quem pediu para receber. A planilha deve ter uma coluna de consentimento, e o script só envia nas linhas marcadas. Lista comprada ou contatos que não conhecem sua empresa geram denúncia e derrubam o número; a WAME não apoia esse uso.

### Como mandar confirmação automática quando alguém responde um Google Forms?

Vincule o formulário à planilha e crie um gatilho instalável de envio de formulário no Apps Script. A cada resposta, o script lê o nome e o telefone da nova linha e envia a confirmação pela API.
