API de WhatsApp com Google Sheets: enviar da planilha e registrar respostas

Com Google Apps Script, uma planilha envia mensagens pela D-API e recebe as respostas de volta em outra aba. O envio usa UrlFetchApp, o recebimento usa um Web App com doPost, e nada disso depende de conector pronto.

Quando a planilha é a ferramenta certa

Muita operação pequena vive no Google Sheets: a lista de alunos da turma, os clientes com parcela vencendo, os participantes de um evento. Mandar WhatsApp para essa lista a partir da própria planilha evita exportar CSV para outra ferramenta e mantém o controle de quem já recebeu no mesmo lugar.

Não existe integração nativa entre D-API e Google Sheets. A ligação é feita com o Apps Script que já vem com toda planilha: ele chama a API de WhatsApp por HTTP e publica uma URL para receber o webhook. Serve bem para dezenas ou poucas centenas de envios por dia. Acima disso, os limites do Apps Script começam a atrapalhar, e falamos deles mais abaixo.

Monte a planilha antes do código

Crie duas abas. A primeira, chamada Envios, com estas colunas na linha 1:

ColunaConteúdoExemplo
A: telefoneSó dígitos, com código do país5511999999999
B: nomePrimeiro nome para personalizarCarla
C: mensagemTexto a enviarSua inscrição no workshop está confirmada.
D: optinSIM quando a pessoa autorizouSIM
E: statusPreenchido pelo scriptenviado
F: enviado_emPreenchido pelo scriptdata e hora

A segunda aba, Respostas, recebe o que as pessoas escreverem de volta. Depois abra Extensões, Apps Script e, em Configurações do projeto, crie as propriedades do script DAPI_KEY com a sua API Key e DAPI_SESSION com o id da conexão.

Enviar com UrlFetchApp

A função abaixo percorre a aba Envios, pula quem não tem opt-in ou já recebeu, envia em lotes pequenos e grava o resultado de cada linha. O muteHttpExceptions faz o erro virar texto na planilha em vez de derrubar a execução inteira:

const LOTE = 40 // cabe com folga nos 6 minutos de uma execução

function enviarPendentes() {
  const props = PropertiesService.getScriptProperties()
  const aba = SpreadsheetApp.getActive().getSheetByName('Envios')
  const linhas = aba.getDataRange().getValues()
  let enviados = 0

  for (let i = 1; i < linhas.length && enviados < LOTE; i++) {
    const [telefone, nome, mensagem, optin, status] = linhas[i]
    if (optin !== 'SIM' || status) continue

    const resp = UrlFetchApp.fetch('https://api.d-api.cloud/api/v1/messages/send/text', {
      method: 'post',
      contentType: 'application/json',
      headers: { Authorization: props.getProperty('DAPI_KEY') },
      payload: JSON.stringify({
        sessionId: props.getProperty('DAPI_SESSION'),
        to: String(telefone),
        text: 'Oi, ' + nome + '! ' + mensagem,
      }),
      muteHttpExceptions: true,
    })

    const ok = resp.getResponseCode() < 300
    aba.getRange(i + 1, 5, 1, 2).setValues([[ok ? 'enviado' : 'erro ' + resp.getContentText(), new Date()]])
    enviados++
    Utilities.sleep(4000 + Math.random() * 4000) // intervalo irregular entre envios
  }
}

Para rodar sozinho, crie em Acionadores um acionador baseado em tempo que chama enviarPendentes a cada 15 minutos. Cada execução pega o próximo lote de linhas sem status, então uma lista grande vai sendo consumida ao longo do dia, sem estourar o tempo de uma execução.

Receber respostas com doPost

No mesmo projeto, adicione a função que o Google chama quando alguém faz POST na URL do Web App. Ela registra só mensagens recebidas de contatos, fora de grupos, e ignora ids repetidos:

function doPost(e) {
  const evento = JSON.parse(e.postData.contents)
  const d = evento.data
  if (evento.event !== 'messages.received' || d.fromMe || d.is_group) return ok()

  const cache = CacheService.getScriptCache()
  if (cache.get(d.id)) return ok()
  cache.put(d.id, '1', 21600) // 6 horas

  SpreadsheetApp.getActive().getSheetByName('Respostas').appendRow([
    new Date(d.timestamp),
    d.from.jid.split('@')[0],
    d.from_name,
    d.type === 'text' ? d.message : '[' + d.type + ']',
  ])
  return ok()
}

function ok() {
  return ContentService.createTextOutput('ok')
}

Publique em Implantar, Nova implantação, tipo App da Web, executando como você e com acesso para qualquer pessoa, já que a D-API chama a URL sem login do Google. Copie a URL que termina em /exec e registre como webhook da conexão:

curl -X POST https://api.d-api.cloud/api/v1/sessions/SUA_SESSAO/webhook \
  -H "Authorization: SUA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "webhookUrl": "https://script.google.com/macros/s/SEU_ID/exec" }'

O webhook da D-API não tem assinatura, então a proteção aqui é a URL não ser divulgada. Se quiser ir além, confira no doPost se o sessionId do evento é o da sua conexão. O formato completo do evento está no guia de webhook de WhatsApp.

Cotas do Apps Script e cuidados com volume

  • Tempo por execução: 6 minutos. Por isso o envio é em lotes com acionador, e não um laço sobre a planilha inteira.
  • Chamadas UrlFetch: numa conta pessoal, 20 mil por dia, somando tudo o que seus scripts fazem. Contas Google Workspace têm cota maior.
  • Acionadores: contas pessoais têm um limite diário de tempo total de execução por acionadores. Intervalos longos entre envios consomem esse tempo.
  • Escrita concorrente: se muitas respostas chegam ao mesmo tempo, o appendRow em paralelo pode ficar lento. Para volume alto, a planilha deixa de ser o banco certo.

O limite que mais importa, porém, é o do WhatsApp. Intervalo irregular entre envios, mensagem personalizada e só para quem pediu são o que mantém o número de pé. O assunto tem guia próprio em como evitar banimento.

Quando sair da planilha

Se a lista passou de alguns milhares de contatos ou se o envio precisa acontecer no segundo em que algo muda no seu sistema, a planilha virou gargalo. Para envios grandes e recorrentes, veja disparo em massa pela API. Para lembretes que dependem de data, como vencimento, o guia de cobrança pelo WhatsApp mostra o desenho com o sistema de origem. E se você prefere fluxos visuais sem código, o n8n combina o node da D-API com o nó de Google Sheets que ele já traz.

Perguntas frequentes

Preciso de alguma extensão ou complemento no Google Sheets?

Não. Tudo roda no Google Apps Script, que já vem com a planilha em Extensões, Apps Script. O envio usa UrlFetchApp para chamar a API da D-API, e o recebimento usa um Web App com a função doPost.

Quantas mensagens consigo enviar por dia pela planilha?

O limite prático vem do Apps Script, não da planilha: numa conta Google pessoal a cota atual é de 20 mil chamadas UrlFetch por dia e cada execução para em 6 minutos. Confira a tabela oficial de cotas, porque o Google revisa esses números.

Onde guardo a API Key com segurança?

Nas propriedades do script, em Configurações do projeto. Assim a chave não fica numa célula que qualquer pessoa com acesso à planilha consegue ler, nem no código que alguém pode copiar.

Por que uma resposta apareceu duas vezes na aba de respostas?

Porque a D-API tenta de novo quando não recebe confirmação a tempo, e o Web App pode demorar. O exemplo desta página guarda o id de cada mensagem no cache do script por algumas horas e ignora repetições.

Posso mandar para uma lista de contatos que comprei?

Não deveria. Mensagem para quem não pediu gera denúncia, e denúncia leva o número a ser bloqueado. Envie só para quem autorizou o contato pelo WhatsApp e registre esse consentimento na própria planilha.

Teste a API de WhatsApp da D-API

Trial de 3 dias com acesso completo. Sem cartão, sem fidelidade.