Extrair prospecções e atividades para um dashboard
Puxe suas prospecções e atividades do GS Engage de forma paginada para montar um dashboard de funil e calcular sua taxa de conversão.
Você é o Rafael, cuida de BI, e o time de vendas quer enxergar o funil: quantas prospecções estão rodando, quantas foram ganhas, quantas foram perdidas — e qual a taxa de conversão. Esse número não mora num relatório pronto: você precisa extrair os dados brutos do GS Engage e montar o painel do seu jeito (Metabase, Power BI, Looker Studio, uma planilha, o que for).
Este guia mostra como puxar todas as suas prospecções e, quando precisar, o histórico de atividades de cada uma — de forma paginada e confiável — para alimentar um dashboard.
Em uma frase
Você lista as prospecções com GET /api/v1/prospections, percorre todas as páginas, traduz o status técnico para o vocabulário de vendas e calcula a conversão dividindo as Ganhas pelo total que já foi decidido.
Um endpoint é só um endereço da API que devolve dados. Para montar o dashboard de funil, você usa dois:
| Endpoint | O que devolve | Quando usar |
|---|---|---|
GET /api/v1/prospections | A lista de prospecções, com o status de cada uma | Base do funil — é daqui que sai a conversão |
GET /api/v1/prospections/{id}/activities | As atividades (ligações, mensagens, e-mails) de uma prospecção | Detalhe: esforço por prospecção, cadência de trabalho |
Na prática: comece sempre pela lista de prospecções. Só desça para as atividades quando o painel precisar detalhar o que aconteceu dentro de cada prospecção específica.
Toda chamada é real (não há sandbox)
O GS Engage não tem ambiente de teste separado. Mas fique tranquilo: os dois endpoints deste guia são somente leitura (GET). Eles não alteram nada — apenas leem seus dados de produção. É seguro experimentar à vontade.
Sua apiKey é uma senha
A apiKey (cerca de 40 caracteres, criada em Configurações > Configurações de API) vai na URL como parâmetro ?apiKey=.... Isso significa que ela pode aparecer em logs de servidor, no histórico do navegador e em links compartilhados. Guarde em variável de ambiente e nunca cole em canais públicos — nem numa consulta salva do seu BI que outras pessoas veem.
A API devolve o status de cada prospecção como um código técnico em inglês. O time de vendas não fala essa língua — ele fala "Ganha", "Perdida". Antes de montar qualquer gráfico, faça essa tradução na sua camada de dados. É simples e direto:
Valor na API (status) | Rótulo que o cliente vê no app | O que significa |
|---|---|---|
IN_PROGRESS | Em andamento | Prospecção ativa; o vendedor ainda está trabalhando o lead |
FROZEN | Congelada | Pausada temporariamente; nada acontece até ser retomada |
WON | Ganha | Deu certo — o lead foi convertido |
LOST | Perdida | Não deu certo; a prospecção foi encerrada sem venda |
Faça a tradução uma vez só
Guarde esse mapeamento em uma tabela de referência (ou num CASE WHEN na sua query) e reaproveite em todos os gráficos. Assim o painel inteiro fala a mesma língua do vendedor, e você nunca mostra IN_PROGRESS cru para o time comercial.
Conversão é a pergunta central do funil: de tudo que foi decidido, quanto virou venda? A conta usa só dois status — WON e LOST — porque prospecções IN_PROGRESS e FROZEN ainda não têm desfecho e distorceriam o número se entrassem na base.
Taxa de conversão = Ganhas (WON) ÷ (Ganhas (WON) + Perdidas (LOST))Exemplo concreto: em um período você tem 120 WON e 380 LOST. As IN_PROGRESS e FROZEN ficam de fora do cálculo.
120 ÷ (120 + 380) = 120 ÷ 500 = 0,24 → 24% de conversão- Considere apenas prospecções já decididas (WON + LOST) no denominador da conversão.
- Mostre também um card separado com quantas prospecções seguem Em andamento — é o funil "vivo".
- Não jogue IN_PROGRESS ou FROZEN no denominador — elas ainda podem virar Ganha ou Perdida e derrubariam artificialmente a taxa.
- Não confunda "total de prospecções" com "total decidido"; são bases diferentes.
O GET /api/v1/prospections aceita filtros que você pode combinar com a paginação. Use-os para reduzir o volume e focar só no recorte que o dashboard precisa.
Traz só as prospecções em um estado específico. Aceita os valores técnicos: IN_PROGRESS, FROZEN, WON, LOST. Útil, por exemplo, para um card que conta apenas as Ganhas.
Limita a uma ou mais Cadências (as sequências de atividades que o vendedor executa). Ideal para comparar a conversão entre cadências diferentes.
Traz as prospecções de um lead específico. Serve mais para telas de detalhe do que para o funil geral.
Recorte por status ou puxe tudo?
Para calcular conversão você precisa de WON e LOST juntos. Você pode fazer duas chamadas (uma com status=WON, outra com status=LOST) e usar o campo total de cada uma — é a forma mais barata de obter as contagens. Ou puxar tudo sem filtro de status e agrupar do seu lado. As duas abordagens funcionam; a primeira gasta menos requisições.
A lista de prospecções não vem toda de uma vez — ela vem paginada. A resposta tem sempre dois blocos: data (o pedaço de registros daquela página) e meta (as informações que dizem onde você está e quanto falta).
{
"data": [
{ "id": "...", "status": "WON", "leadId": "...", "createdAt": "2026-07-10T14:03:00Z" }
],
"meta": {
"limit": 50,
"count": 50,
"total": 1240,
"page": 1,
"totalPages": 25
}
}O que cada campo de meta significa para você:
| Campo | O que é |
|---|---|
limit | Quantos registros por página você pediu |
count | Quantos vieram nesta página (pode ser menor que limit na última) |
total | O total de registros que batem com seus filtros |
page | Em que página você está agora (começa em 1) |
totalPages | Quantas páginas existem no total |
A regra de ouro da paginação: continue pedindo a próxima página enquanto page < totalPages. Você controla a página com o parâmetro page e o tamanho com limit.
Nem todo endpoint tem meta
A maioria dos endpoints paginados segue o formato { data, meta }. Só GET /api/v1/webhooks vem sem meta (ainda com os itens em data). Para os deste guia (prospections e as activities), você pode contar com o meta.
Ao paginar uma extração, você precisa de uma ordem estável — senão registros novos entrando durante a leitura podem fazer você pular ou repetir linhas entre páginas. Ordene explicitamente por data de criação usando os parâmetros orderBy e orderDirection (asc ou desc):
GET /api/v1/prospections?apiKey=SUA_CHAVE&orderBy=createdAt&orderDirection=asc&limit=100&page=1Por que asc por createdAt
Ordenar do mais antigo para o mais novo (asc) deixa a base histórica no começo e os registros recentes no fim. Para extrações incrementais (só o que é novo desde a última carga), isso facilita: você lê até alcançar registros mais recentes que a sua última sincronização e para por ali.
Este é o coração do guia: um loop que percorre todas as páginas de prospecções e junta tudo numa lista única, pronta para carregar no seu dashboard. Troque SUA_CHAVE pela sua chave (de preferência via variável de ambiente).
import os
import time
import requests
api_key = os.environ["GS_API_KEY"] # guarde a chave em variável de ambiente
url = "https://api.gsengage.com/api/v1/prospections"
def fetch_all_prospections():
todas = []
page = 1
while True:
resp = requests.get(url, params={
"apiKey": api_key,
"limit": 100,
"page": page,
"orderBy": "createdAt",
"orderDirection": "asc",
})
# Respeita o rate limit (200 leituras/min)
if resp.status_code == 429:
espera = int(resp.headers.get("Retry-After", "5"))
time.sleep(espera)
continue
resp.raise_for_status()
body = resp.json()
todas.extend(body["data"])
meta = body["meta"]
if meta["page"] >= meta["totalPages"]:
break
page += 1
return todas
prospeccoes = fetch_all_prospections()
print(f"Extraídas {len(prospeccoes)} prospecções")
# Traduz o status e calcula a conversão
rotulos = {
"IN_PROGRESS": "Em andamento",
"FROZEN": "Congelada",
"WON": "Ganha",
"LOST": "Perdida",
}
ganhas = sum(1 for p in prospeccoes if p["status"] == "WON")
perdidas = sum(1 for p in prospeccoes if p["status"] == "LOST")
decididas = ganhas + perdidas
conversao = (ganhas / decididas) if decididas else 0
print(f"Ganhas: {ganhas} | Perdidas: {perdidas} | Conversão: {conversao:.1%}")const apiKey = process.env.GS_API_KEY; // guarde a chave em variável de ambiente
const baseUrl = "https://api.gsengage.com/api/v1/prospections";
async function fetchAllProspections() {
const todas = [];
let page = 1;
while (true) {
const params = new URLSearchParams({
apiKey,
limit: "100",
page: String(page),
orderBy: "createdAt",
orderDirection: "asc",
});
const resp = await fetch(`${baseUrl}?${params}`);
// Respeita o rate limit (200 leituras/min)
if (resp.status === 429) {
const espera = Number(resp.headers.get("Retry-After") ?? 5);
await new Promise((r) => setTimeout(r, espera * 1000));
continue;
}
if (!resp.ok) throw new Error(`Erro ${resp.status}`);
const body = await resp.json();
todas.push(...body.data);
const { page: atual, totalPages } = body.meta;
if (atual >= totalPages) break;
page += 1;
}
return todas;
}
const prospeccoes = await fetchAllProspections();
const ganhas = prospeccoes.filter((p) => p.status === "WON").length;
const perdidas = prospeccoes.filter((p) => p.status === "LOST").length;
const decididas = ganhas + perdidas;
const conversao = decididas ? ganhas / decididas : 0;
console.log(`Ganhas: ${ganhas} | Perdidas: ${perdidas} | Conversão: ${(conversao * 100).toFixed(1)}%`);No terminal, você busca página por página. Primeiro a página 1, olhe o meta.totalPages da resposta e repita incrementando page até chegar lá:
# Página 1 — veja meta.totalPages na resposta
curl "https://api.gsengage.com/api/v1/prospections?apiKey=SUA_CHAVE&orderBy=createdAt&orderDirection=asc&limit=100&page=1"
# Página 2, 3, ... até page == totalPages
curl "https://api.gsengage.com/api/v1/prospections?apiKey=SUA_CHAVE&orderBy=createdAt&orderDirection=asc&limit=100&page=2"Para uma extração de verdade, prefira o exemplo em Python ou Node — o loop cuida de percorrer todas as páginas sozinho.
O que a resposta significa para o negócio: com essa lista completa em mãos, você tem o funil inteiro — dá para contar quantas prospecções estão em cada estado, calcular a conversão do período e quebrar por cadência (routineIds) ou por vendedor, dependendo dos campos que o seu painel expõe.
Quando o painel precisar ir além do funil — por exemplo, medir quanto esforço cada prospecção exigiu (número de ligações, mensagens, e-mails) — você desce para as atividades de uma prospecção específica:
curl "https://api.gsengage.com/api/v1/prospections/ID_DA_PROSPECCAO/activities?apiKey=SUA_CHAVE&limit=100&page=1"Essa resposta também é paginada no formato { data, meta } — use exatamente o mesmo loop do exemplo acima para percorrer todas as páginas. Como você faria uma chamada por prospecção, use isso com parcimônia: puxe as atividades só das prospecções que o dashboard realmente detalha, para não estourar o limite de requisições.
Cuidado com o rate limit ao descer para atividades
São 200 requisições de leitura por minuto (janela de 60s). Se você buscar as atividades de milhares de prospecções em sequência, vai bater no limite e receber 429. A resposta traz o header Retry-After (em segundos) — espere esse tempo antes de tentar de novo, de preferência com backoff exponencial (dobrando a espera a cada nova falha).
graph TD
A["Inicia extracao page=1"] --> B["GET /prospections?page=N"]
B --> C["Junta body.data na lista"]
C --> D{"meta.page < meta.totalPages?"}
D -->|Sim| E["page = page + 1"]
E --> B
D -->|Nao| F["Lista completa em maos"]
F --> G["Traduz status e calcula conversao"]
G --> H["Carrega no dashboard de funil"]Antes de subir o dashboard
0/6As mensagens de erro do GS Engage já vêm em português — leia sempre o campo message da resposta. Os tropeços mais frequentes nessa extração:
O que houve: a chave não foi enviada ou está errada. Por quê: faltou o ?apiKey=... na URL, ou a chave foi revogada. Como corrigir: confira o parâmetro na URL e valide a chave com uma chamada leve, como GET /api/v1/custom-fields — um 200 confirma que ela funciona.
O que houve: você fez mais de 200 requisições de leitura em 60 segundos. Por quê: paginação ou busca de atividades rápida demais, sem pausa. Como corrigir: leia o header Retry-After (segundos), espere esse tempo e retome com backoff exponencial. Os headers X-RateLimit-Remaining e X-RateLimit-Reset ajudam a antecipar o momento de desacelerar.
O que houve: o painel mostra menos prospecções do que deveria. Por quê: você leu só a primeira página e ignorou o meta.totalPages. Como corrigir: implemente o loop de paginação — continue enquanto meta.page < meta.totalPages.
Preciso incluir as prospecções Congeladas (FROZEN) na conversão?
Não. Assim como IN_PROGRESS, uma prospecção FROZEN ainda não tem desfecho — ela pode ser retomada e virar Ganha ou Perdida. A conversão usa só WON e LOST. Mostre as Congeladas em um card à parte, se o time quiser acompanhá-las.
Qual o melhor valor de limit para extrair mais rápido?
Um limit maior (por exemplo, 100) reduz o número de requisições para percorrer tudo, o que ajuda a não bater no rate limit. Comece com 100 e ajuste se precisar. Lembre que a última página normalmente vem com count menor que o limit — isso é esperado.
Como faço uma carga incremental, só do que é novo?
Ordene por createdAt em ordem crescente (asc) e guarde a data do último registro que você já carregou. Na próxima extração, percorra as páginas até alcançar registros com createdAt mais recente que essa marca — e ignore o que você já tinha. Assim você não reprocessa a base inteira todo dia.
Consigo fazer isso sem escrever código, direto no meu BI?
Ferramentas como Make e n8n conseguem consumir a API REST e cuidar da paginação em um fluxo visual, entregando os dados para o seu destino. Muitos BIs também importam de um conector HTTP. O importante é que qualquer que seja a ferramenta, ela precise respeitar a paginação { data, meta } e o rate limit.
Este artigo foi útil?
Validar a assinatura do webhook (HMAC SHA-256)
Confirme que cada entrega de webhook veio mesmo do GS Engage recalculando a assinatura HMAC SHA-256 a partir do corpo cru e do seu secret.
Ler as conversas (WhatsApp e E-mail) de um lead
Liste as conversas de um lead por canal e puxe as mensagens de cada thread para registrar o histórico de contato onde você quiser.