# Playbook de integração para parceiros e agências

> Um roteiro reutilizável para agências implantarem a API do GS Engage em vários clientes com o mesmo padrão de qualidade.

- URL canônica: https://docs.growthstation.app/docs/api/playbook-agencia
- Idioma: pt-BR
- Última atualização: 2026-09-20T08:21:20.451Z
- Produto: GS Engage
- Mantido por: Produto GS Engage



<PageHero emoji="🧩" title="Playbook de integração para parceiros e agências" description="Um roteiro que você monta uma vez e reaproveita em cada novo cliente: mesma sequência, mesmos padrões, menos surpresas." gradient="violet" />

Você atende vários clientes e não quer reinventar a integração a cada projeto. A ideia desta página é essa: transformar a implantação da API do GS Engage em um **processo repetível**. O que muda de um cliente para outro é quase sempre só a chave de acesso; o resto do fluxo você padroniza.

Esta é a trilha da **Camila**, que cuida de operação e tecnologia para uma carteira de clientes. Se esse é o seu papel, o objetivo aqui é entregar rápido, sem retrabalho e sem sustos em produção.

<Callout type="warning" title="Não existe ambiente de teste separado">
  Toda chamada à API é **real** e afeta os dados de produção do cliente — não há sandbox. Ao validar uma conta nova, comece sempre por operações de leitura (consultar dados) e avise o cliente antes de qualquer escrita (criar, editar ou remover).
</Callout>

🧭 Como pensar a integração entre vários clientes [#-como-pensar-a-integração-entre-vários-clientes]

O segredo de reaproveitar código entre clientes é isolar o que muda. Na prática, quase tudo é igual — a URL base, os caminhos, o formato dos dados. **O que muda por cliente é a `apiKey`** (a chave de acesso, com cerca de 40 caracteres, que autentica cada conta).

<Callout type="info" title="O que é a apiKey, em uma frase">
  A **apiKey** é a senha da conta na API. Ela vai no final do endereço (a URL), no formato `?apiKey=SUA_CHAVE` — não em cabeçalho. Cada cliente tem a sua, gerada na plataforma em <TextHighlight>Configurações</TextHighlight> → <TextHighlight>Configurações de API</TextHighlight>.
</Callout>

Pense na sua integração como um único código com a chave parametrizada por conta:

```js
// Uma configuração por cliente — só a chave muda
const clientes = {
  "cliente-a": { apiKey: process.env.GSENGAGE_KEY_CLIENTE_A },
  "cliente-b": { apiKey: process.env.GSENGAGE_KEY_CLIENTE_B },
};

const BASE_URL = "https://api.gsengage.com/api/v1";

function url(cliente, caminho) {
  const { apiKey } = clientes[cliente];
  return `${BASE_URL}${caminho}?apiKey=${apiKey}`;
}
```

Com isso, o mesmo fluxo serve para qualquer cliente: você troca só a etiqueta da conta e as chaves ficam guardadas fora do código, em variáveis de ambiente.

<Callout type="danger" title="A apiKey é uma senha — trate cada uma como tal">
  Como a chave viaja dentro da URL, ela aparece em **logs de servidor, no histórico do navegador e em qualquer link compartilhado**. Guarde cada chave em variável de ambiente ou cofre de senhas, uma por cliente. Nunca cole a URL completa (com a chave) em prints, tickets ou grupos. Se uma vazar, gere outra em Configurações de API — sem afetar os demais clientes.
</Callout>

✅ Checklist de implantação [#-checklist-de-implantação]

Use este checklist a cada novo cliente. Ele fica salvo no seu navegador, então você pode marcar item por item durante a implantação.

<Checklist id="playbook-agencia-implantacao" title="Implantar a API em um novo cliente">
  <ChecklistItem>
    Gerei a 

    `apiKey`

     do cliente em 

    <TextHighlight>Configurações</TextHighlight>

     → 

    <TextHighlight>Configurações de API</TextHighlight>

     e guardei em variável de ambiente (nunca no código).
  </ChecklistItem>

  <ChecklistItem>
    Validei a chave com uma leitura leve (

    `GET /api/v1/custom-fields`

    ) e recebi 

    `200`

    .
  </ChecklistItem>

  <ChecklistItem>
    Confirmei com o cliente 

    **antes**

     de qualquer escrita, porque não há ambiente de teste.
  </ChecklistItem>

  <ChecklistItem>
    Defini de onde vêm os leads (formulário, CRM, planilha) e para qual Cadência eles devem ir.
  </ChecklistItem>

  <ChecklistItem>
    Copiei o 

    `id`

     da Cadência de destino (

    `GET /api/v1/routines`

    ).
  </ChecklistItem>

  <ChecklistItem>
    Criei o primeiro lead de mentira (meu próprio e-mail) e confirmei que ele apareceu como 

    <TextHighlight>Levantada de Mão</TextHighlight>

    .
  </ChecklistItem>

  <ChecklistItem>
    Registrei os webhooks necessários e 

    **guardei o `secret` na hora**

     (ele só aparece uma vez).
  </ChecklistItem>

  <ChecklistItem>
    Implementei a validação da assinatura (HMAC SHA-256) do lado que recebe os webhooks.
  </ChecklistItem>

  <ChecklistItem>
    Tratei os erros 

    `400`

    , 

    `401`

    , 

    `404`

     e 

    `429`

     reaproveitando as mensagens em português da API.
  </ChecklistItem>

  <ChecklistItem>
    Ativei retentativas com backoff respeitando o header 

    `Retry-After`

    .
  </ChecklistItem>

  <ChecklistItem>
    Fiz um teste ponta a ponta e mostrei o resultado para o cliente antes de ligar o fluxo real.
  </ChecklistItem>
</Checklist>

🚀 A sequência recomendada [#-a-sequência-recomendada]

A ordem abaixo evita retrabalho: você só cria leads depois de ter certeza que a chave funciona, e só liga webhooks depois que os leads já entram na Cadência.

<Mermaid
  chart={`graph LR
A["1. Autenticar<br/>(validar a apiKey)"] --> B["2. Criar leads"]
B --> C["3. Colocar na Cadência<br/>(iniciar prospecção)"]
C --> D["4. Registrar webhooks"]
D --> E["5. Validar ponta a ponta"]`}
/>

<Steps>
  <Step num={1} title="Autenticar: confirme que a chave funciona">
    Antes de qualquer coisa, teste a `apiKey` do cliente com uma leitura leve e sem efeitos colaterais: listar os campos personalizados.

    ```bash
    curl "https://api.gsengage.com/api/v1/custom-fields?apiKey=SUA_CHAVE"
    ```

    Um `200` com uma lista (mesmo vazia, `[]`, se o projeto ainda não tem campos) confirma que a chave está válida. Um `401` significa chave ausente ou inválida — gere outra em Configurações de API. Não existe `GET /info` nem `GET /health`: este é o teste de saúde recomendado.
  </Step>

  <Step num={2} title="Criar leads: leve o contato para a base">
    Um lead precisa de **pelo menos um contato**. Os contatos vão em três arrays — `emails`, `phones` e `mobiles` — e cada item tem `value` e `label`.

    ```bash
    curl -X POST "https://api.gsengage.com/api/v1/leads?apiKey=SUA_CHAVE" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Maria Souza",
        "company": "Souza Consultoria",
        "emails": [{ "value": "maria@souza.com", "label": "Trabalho" }],
        "mobiles": [{ "value": "+5511999998888", "label": "WhatsApp" }]
      }'
    ```

    A resposta traz o lead criado. Um lead criado via API entra marcado como <TextHighlight>Levantada de Mão</TextHighlight> e aparece no topo da fila de atividades do vendedor.
  </Step>

  <Step num={3} title="Colocar na Cadência: inicie a prospecção">
    Para já distribuir o lead a um vendedor, adicione-o direto a uma Cadência. Primeiro pegue o `id` da Cadência de destino.

    ```bash
    curl "https://api.gsengage.com/api/v1/routines?apiKey=SUA_CHAVE"
    ```

    Depois, adicione o lead à Cadência escolhida:

    ```bash
    curl -X POST "https://api.gsengage.com/api/v1/routines/SEU_ROUTINE_ID/lead?apiKey=SUA_CHAVE" \
      -H "Content-Type: application/json" \
      -d '{ "leadId": "ID_DO_LEAD" }'
    ```

    Se a distribuição automática estiver ativa (ou se você informar um `responsibleId`), essa mesma chamada já inicia a prospecção. O contato que acabou de demonstrar interesse é atendido primeiro.
  </Step>

  <Step num={4} title="Registrar webhooks: receba avisos automáticos">
    Um **webhook** é um aviso que o GS Engage envia para um endereço seu quando algo acontece — por exemplo, quando uma prospecção é ganha. Ao criar o webhook, escolha só os eventos que interessam ao cliente.

    ```bash
    curl -X POST "https://api.gsengage.com/api/v1/webhooks?apiKey=SUA_CHAVE" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Avisos de venda - Cliente A",
        "url": "https://sua-agencia.com/hooks/cliente-a",
        "events": ["prospection.won", "prospection.lost"]
      }'
    ```

    A resposta traz um campo `secret` **uma única vez**. Copie e guarde na hora — ele não aparece de novo.
  </Step>

  <Step num={5} title="Validar ponta a ponta: prove que funciona">
    Feche o ciclo com um teste real e controlado: crie um lead de mentira (seu próprio e-mail), acompanhe ele entrar na Cadência e confirme que o webhook chegou no seu endereço com a assinatura correta. Só depois ligue o fluxo de verdade e mostre o resultado ao cliente.
  </Step>
</Steps>

🛡️ Padrões recomendados [#️-padrões-recomendados]

Estes quatro padrões valem para todos os clientes. Adote-os uma vez no seu código e você elimina a maior parte dos problemas de produção.

<FieldInfoGroup>
  <FieldInfo title="Idempotência: não crie o mesmo lead duas vezes" required>
    Se uma chamada falha por rede ou tempo esgotado, é tentador reenviar — e aí você corre o risco de criar o lead em duplicado. Antes de criar, confira se o contato já existe com `GET /api/v1/leads?search=maria@souza.com` (o parâmetro `search` filtra por nome, empresa, e-mail ou telefone). Guarde de que registro de origem veio cada lead para não reprocessar a mesma linha.
  </FieldInfo>

  <FieldInfo title="Retentativas com backoff exponencial" required>
    Falhas temporárias acontecem. Ao receber `429` (limite atingido) ou um erro de rede, espere e tente de novo — dobrando o tempo a cada tentativa e **sempre respeitando o header `Retry-After`** (que diz, em segundos, quanto esperar). Não fique reenviando em looping apertado.
  </FieldInfo>

  <FieldInfo title="Respeite os limites de chamadas (rate limit)" required>
    O **rate limit** é o teto de chamadas por minuto, numa janela fixa de 60 segundos: **200 de leitura** (GET/HEAD) e **100 de escrita** (POST/PUT/PATCH/DELETE). Ao estourar, a API responde `429` com `Retry-After` e os cabeçalhos `X-RateLimit-Limit`, `X-RateLimit-Remaining` e `X-RateLimit-Reset`. Para cargas grandes de leads, espalhe os envios ao longo do tempo.
  </FieldInfo>

  <FieldInfo title="Guarde o secret do webhook na criação" required>
    O `secret` de cada webhook volta **uma única vez**, na resposta do `POST /api/v1/webhooks`. É com ele que você confere que o aviso veio mesmo do GS Engage (assinatura HMAC SHA-256 — um "selo de autenticidade"). Salve-o no cofre do cliente na hora; se perder, terá de recriar o webhook.
  </FieldInfo>
</FieldInfoGroup>

<Callout type="tip" title="Um secret por webhook, uma apiKey por cliente">
  Mantenha o mesmo padrão de organização das chaves: cada cliente tem sua `apiKey` e cada webhook tem seu `secret`. Guardados separadamente, um vazamento nunca contamina os outros clientes.
</Callout>

Como conferir a assinatura do webhook [#como-conferir-a-assinatura-do-webhook]

Cada entrega chega no seu endereço como um `POST` com este envelope:

```json
{
  "id": "evt_123",
  "test": false,
  "event": "prospection.won",
  "data": { },
  "retries": 0,
  "manualRetries": 0,
  "createdAt": "2026-07-17T12:00:00Z"
}
```

A entrega vem assinada com **HMAC SHA-256** (um cabeçalho de assinatura calculado a partir do corpo da mensagem e do seu `secret`). Do seu lado, você recalcula a assinatura e compara: se baterem, o aviso é autêntico.

```js
import crypto from "crypto";

function assinaturaConfere(corpoBruto, assinaturaRecebida, secret) {
  const esperada = crypto
    .createHmac("sha256", secret)
    .update(corpoBruto)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(esperada),
    Buffer.from(assinaturaRecebida)
  );
}
```

<Callout type="info" title="A assinatura mudou de SHA-1 para SHA-256">
  Se você mantém integrações antigas, atualize o cálculo para **SHA-256**. A validação com SHA-1 não confere mais.
</Callout>

⚡ Entrega rápida com no-code (quando o cliente não tem time técnico) [#-entrega-rápida-com-no-code-quando-o-cliente-não-tem-time-técnico]

Nem todo cliente tem equipe de desenvolvimento — e nem toda integração precisa de código. Para os casos simples (levar um lead de um formulário para a Cadência, ou avisar o time no chat quando uma venda fecha), você entrega em uma tarde usando ferramentas de automação.

<Tabs items={['Zapier', 'Make e n8n', 'Quando escrever código']}>
  <Tab value="Zapier">
    O GS Engage oferece conexões nativas com o **Zapier**, incluindo gatilhos que reagem a eventos (webhooks). Você monta o fluxo arrastando blocos: um gatilho (formulário preenchido) e uma ação (criar o lead na Cadência) usando o passo "Webhooks by Zapier".
  </Tab>

  <Tab value="Make e n8n">
    **Make** e **n8n** também consomem a API REST e recebem webhooks do GS Engage. A lógica é a mesma: um gatilho, um passo de HTTP apontando para `https://api.gsengage.com/api/v1/...` com a `apiKey` na URL, e o corpo do lead em JSON.
  </Tab>

  <Tab value="Quando escrever código">
    Vá para código quando precisar de **validação de assinatura** dos webhooks, deduplicação robusta de leads ou lógica de negócio própria. Notificações simples (mandar um Slack quando uma prospecção é ganha) o no-code resolve sem programar.
  </Tab>
</Tabs>

<Callout type="tip" title="Regra prática de decisão">
  Se o objetivo cabe em "quando X acontece, faça Y" e não envolve conferir a assinatura do webhook, comece pelo no-code. Você entrega no mesmo dia e migra para código só se o cliente crescer.
</Callout>

🚫 Erros comuns a evitar [#-erros-comuns-a-evitar]

O que mais gera retrabalho em implantações de agência:

<DoDont>
  <DoDontItem type="do">
    Guarde uma 

    `apiKey`

     por cliente em variável de ambiente e parametrize o código pela conta.
  </DoDontItem>

  <DoDontItem type="dont">
    Não deixe chaves fixas no código nem reutilize a mesma chave entre clientes diferentes.
  </DoDontItem>

  <DoDontItem type="do">
    Teste sempre primeiro com um lead de mentira (seu próprio e-mail), porque toda chamada é real e não há sandbox.
  </DoDontItem>

  <DoDontItem type="dont">
    Não use dados de clientes reais nos testes iniciais, nem rode escritas sem avisar o cliente.
  </DoDontItem>

  <DoDontItem type="do">
    Copie e guarde o 

    `secret`

     do webhook no momento da criação.
  </DoDontItem>

  <DoDontItem type="dont">
    Não conte com pegar o 

    `secret`

     depois: ele só aparece uma vez, na resposta da criação.
  </DoDontItem>

  <DoDontItem type="do">
    Confira se cada lead tem pelo menos um contato antes de enviar.
  </DoDontItem>

  <DoDontItem type="dont">
    Não ignore o 

    `400`

    : a resposta traz a lista 

    `errors`

     com o campo exato e o motivo, em português.
  </DoDontItem>

  <DoDontItem type="do">
    Ao receber 

    `429`

    , espere o tempo do 

    `Retry-After`

     e tente de novo com backoff.
  </DoDontItem>

  <DoDontItem type="dont">
    Não dispare centenas de leads de uma vez: o limite de escrita é 100 chamadas por minuto.
  </DoDontItem>

  <DoDontItem type="do">
    Trate a paginação com cuidado: use 

    `limit`

     e 

    `page`

     e leia o bloco 

    `meta`

     das respostas paginadas.
  </DoDontItem>

  <DoDontItem type="dont">
    Não espere 

    `meta`

     de 

    `GET /webhooks`

     (traz 

    `data`

     sem 

    `meta`

    ). Já 

    `GET /custom-fields`

     é paginado normal (

    `{ data, meta }`

    ).
  </DoDontItem>
</DoDont>

<Callout type="warning" title="Mensagens de erro já vêm prontas em português">
  Reaproveite-as com o cliente no formato "o que houve → por quê → como corrigir". O `400` retorna `{ "message", "errors": [{ "field", "message" }] }`; o `401` é chave ausente ou inválida; o `404` é registro não encontrado; o `429` é limite atingido.
</Callout>

❓ Perguntas frequentes [#-perguntas-frequentes]

<FAQ>
  <FAQItem question="Preciso de uma apiKey diferente para cada cliente?">
    Sim. Cada conta tem a sua chave, gerada em Configurações → Configurações de API. Parametrize o código pela conta e guarde cada chave em variável de ambiente separada. Assim, se uma vazar, você a regenera sem afetar os outros clientes.
  </FAQItem>

  <FAQItem question="Existe um ambiente de teste para eu validar sem risco?">
    Não. Toda chamada é real e afeta os dados de produção do cliente. Por isso, comece sempre por leituras (como listar campos ou Cadências) e avise o cliente antes de qualquer escrita. Nos testes, use um lead de mentira com o seu próprio e-mail.
  </FAQItem>

  <FAQItem question="Como valido a chave de um cliente novo rapidinho?">
    Faça um `GET /api/v1/custom-fields?apiKey=SUA_CHAVE`. Um `200` com uma lista (mesmo `[]`) confirma que a chave funciona. Um `401` significa chave ausente ou inválida. Não existe `GET /info` nem `GET /health`.
  </FAQItem>

  <FAQItem question="Perdi o secret de um webhook. E agora?">
    O `secret` só é exibido uma vez, na resposta da criação. Se você não o guardou, apague o webhook (`DELETE /api/v1/webhooks/{webhookId}`) e crie de novo para receber um `secret` novo.
  </FAQItem>

  <FAQItem question="Consigo entregar sem escrever código?">
    Para fluxos simples, sim. Zapier tem conexão nativa; Make e n8n também consomem a API e recebem webhooks. Código passa a ser necessário quando você precisa validar a assinatura dos webhooks ou aplicar lógica de negócio própria.
  </FAQItem>
</FAQ>

📚 Continue por aqui [#-continue-por-aqui]

Artigos Relacionados [#artigos-relacionados]

<RelatedArticles>
  <RelatedArticle href="/docs/api/comece-aqui/escolha-seu-caminho" title="Escolha seu caminho" description="Compare as trilhas sem código, com código e análise de dados." />

  <RelatedArticle href="/docs/api/guias/enviar-leads-do-crm" title="Enviar leads do CRM" description="Sincronize contatos de outro sistema para o GS Engage." />

  <RelatedArticle href="/docs/api/guias/adicionar-lead-cadencia" title="Adicionar lead a uma Cadência" description="Coloque o lead na fila e inicie a prospecção." />

  <RelatedArticle href="/docs/api/guias/validar-assinatura-webhook" title="Validar a assinatura do webhook" description="Confira que o aviso veio mesmo do GS Engage com o secret." />

  <RelatedArticle href="/docs/api/no-code/zapier" title="Conectar com Zapier" description="Monte a integração sem escrever código." />

  <RelatedArticle href="/docs/api/referencia" title="Referência da API" description="Todos os endpoints, campos e respostas em detalhe." />
</RelatedArticles>
