ghl.access, ghl.refresh, …) e nunca saem pela API. Tudo abaixo, exceto o callback e o webhook, usa a chave admin (X-Admin-Key) e exige ZAPMEOW_MASTER_KEY.
Variáveis
Conectar
GET /admin/tenants/{id}/ghl/install-url?userType=Locationdevolve o link de autorização (vale 30 min).Companyserve para instalação pela agência: o tenant precisa terghlLocationId, o ZapMeow troca o token da agência por um da subconta e renova os dois sozinho.- O cliente abre o link e escolhe a subconta. A GHL volta em
GET /ghl/oauth/callback?code&state. Ostateé assinado e amarra o retorno ao tenant; se a subconta autorizada não for a do tenant, nada é gravado. - O token de acesso dura cerca de 24 h; o de renovação gira a cada uso e o novo é gravado antes de usar o acesso. Há renovação sob demanda (uma por vez por tenant), 401 renova e repete a chamada, e uma rotina a cada 10 min renova o que está perto de vencer. Se a GHL recusa a renovação (
invalid_grant), a conexão vai parastatus: reauthe o cliente precisa reinstalar. PUT /admin/tenants/{id}/ghl/pitcom{"value","locationId"}liga uma subconta por Private Integration Token (sem renovação). Serve para testar sem criar o app; não use para clientes.
Espelho
A carga inicial roda sozinha depois da instalação. Webhook:
POST /ghl/webhook (URL única do app, em Advanced Settings). Confere o X-GHL-Signature (Ed25519, base64, sobre o corpo cru); sem assinatura válida, 401. Trata Opportunity* (cria, atualiza, apaga) e UNINSTALL (desconecta). O estágio vindo do webhook atualiza o espelho e dispara o evento GHLEvent para quem assinou com Manager.onGHL (motor de fluxo), com o estágio anterior. Se o espelho já tinha esse estágio (eco de um movimento feito pelas nossas tools), não há evento. Subconta desconhecida responde 200, para a GHL não repetir.
Tools
GET /admin/tenants/{id}/ghl/tools lista nome, descrição, inputSchema e o modo atual. POST /admin/tenants/{id}/ghl/tools/{tool} com {"session","input","dryRun"} chama.
Modo por tool, na seção
tools da config (PUT /admin/tenants/{id}/config/tools, {"modes":{"gravar_campo":"executa"}}):
pede_ok(padrão): a chamada é validada e fica emzm_toolpending(202, compendingIde o plano). Nada vai à GHL atéPOST .../ghl/pending/{pid}/approve({"by"}); o plano é refeito na hora de aprovar..../rejectdescarta. Aprovar duas vezes executa uma só.executa: envia direto.dryRun: true: modo sombra; devolve o plano sem enviar e sem criar pendência.
zm_toollog (GET .../toollog) com modo, entrada e resultado. GET .../ghl/pending?status=pending lista os pedidos.
O que não é oficial ou não existe
- Iniciar ligação pelo LC Phone: não há endpoint público (só dá para registrar ligações já feitas). Por isso não existe tool
ligar_ghl; a ligação continua pelo/calldo ZapMeow. - Criar pipeline ou estágio por API: não existe; o cliente monta na GHL e o ZapMeow só lê.
- WhatsApp por QR (whatsmeow) dentro do ecossistema GHL: nenhum documento da GHL o autoriza nem o proíbe por nome; o risco é da Meta e da revisão do Marketplace. Manter só em instalação privada (até 5 agências) até perguntar por escrito à GHL.
- Não testado contra uma subconta real: formato do
customFields(field_value), eco do webhook e payload (plano ou dentro dedata; os dois são aceitos) vêm da documentação e do OpenAPI, validados contra um mock. - Um único processo: o travamento do refresh é em memória. Com mais de uma réplica, dois refresh simultâneos podem invalidar o token.