API do Pingo
Com a API, o seu site, formulário, planilha ou sistema conversa com o Pingo: envia o lead já com a origem do anúncio, consulta, move de etapa no funil e puxa números. Ela vem a partir do plano Corrente e cada conta cria as próprias chaves.
- Endereço base:
https://www.pingotracker.com.br/api/v1 - Tudo em JSON. Os nomes de campos, os códigos de erro e as permissões são em inglês (para o seu sistema tratar); as mensagens de erro são em português.
- Datas em ISO 8601 (UTC). Telefone só com dígitos e código do país (ex.:
5541999990000). Valores em reais, como número. - Use sempre a partir do seu servidor. A chave nunca vai em página pública, app ou repositório aberto.
Começando em 4 passos
- 1. Confira o plano. A API vem no plano Corrente e acima. Sem ela, a tela de chaves mostra o convite para trocar de plano.
- 2. Crie a chave. No Pingo, vá em Configurações > API > Criar chave (só o dono da conta). Dê um nome (ex.: "Site da clínica"), marque só as permissões que esse sistema precisa e copie a chave: ela aparece uma única vez.
- 3. Guarde no servidor. Coloque a chave numa variável de ambiente, por exemplo
PINGO_API_KEY. - 4. Teste. Peça a lista de funis:
curl "https://www.pingotracker.com.br/api/v1/pipelines" \
-H "Authorization: Bearer $PINGO_API_KEY"Veio uma lista de funis com etapas? Está pronto. Os ids de funil e etapa dessa resposta são os que você usa para criar leads direto numa etapa ou para movê-los.
Autenticação
Toda chamada leva a chave no cabeçalho:
Authorization: Bearer pgo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx- A chave é de uma conta: ela só enxerga e só altera dados dessa conta. Nenhum id de outra conta funciona.
- Chave ausente, mal formada, desconhecida ou revogada dão a mesma resposta (
401 invalid_api_key). - Não há CORS de propósito: o navegador não consegue chamar a API, o que impede o uso da chave em página pública.
- Vazou? Revogue em Configurações > API e crie outra. A revogação vale na hora. Quando a conta troca de dono, todas as chaves são revogadas.
- Cada conta pode ter até 5 chaves ativas. Use uma por sistema, para revogar uma sem derrubar as outras.
- O dono da conta recebe um aviso, no sino do Pingo e por e-mail, sempre que uma chave é criada ou revogada. Se não foi ele, é sinal para revogar na hora e trocar a senha.
Permissões da chave
Marque na criação só o que o sistema precisa. Uma chave só de escrita (para o formulário do site) não consegue ler a base de leads.
| Permissão | O que libera | Rotas |
|---|---|---|
leads:read | Consultar leads. Ler nome, telefone, e-mail, tags e negócios de qualquer lead da conta. | GET /leads, POST /leads/lookup, GET /leads/{id} |
leads:write | Criar e atualizar leads. Enviar leads novos (ex.: de um formulário do site) e atualizar nome, e-mail, tags e notas. | POST /leads, PATCH /leads/{id} |
pipeline:read | Ver funis e etapas. Listar os funis e as etapas. | GET /pipelines |
pipeline:write | Mover lead de etapa. Mover o negócio de um lead de etapa (não fecha venda e não dispara mensagem). | POST /leads/{id}/stage |
metrics:read | Ver métricas. Ver números agregados (leads por período e por origem), sem dados de pessoas. | GET /metrics |
Respostas e erros
Sucesso devolve { "data": ... }; listas devolvem { "data": [...], "next_cursor": ... }. Erro devolve sempre o mesmo formato, e o cabeçalho X-Request-Id traz o mesmo identificador:
{
"error": {
"code": "validation_error",
"message": "Alguns campos não passaram na validação.",
"request_id": "req_9f2c41d07a3b86e5",
"details": {
"fields": [
{
"field": "phone",
"message": "Telefone inválido. Envie com DDD (ex.: 41999990000) ou com +código do país."
}
]
}
}
}Ao falar com o suporte sobre uma chamada, informe o request_id. Trate o code no seu sistema (a mensagem pode mudar de texto).
| Código | HTTP | Significado |
|---|---|---|
invalid_api_key | 401 | Chave ausente, mal formada, desconhecida ou revogada (a resposta é a mesma nos quatro casos). |
api_not_enabled | 403 | O plano da conta não inclui a API (ela vem a partir do plano Corrente). |
plan_inactive | 403 | A licença da conta não está ativa. |
comercial_not_enabled | 403 | O módulo Comercial não está ligado na conta. |
insufficient_scope | 403 | A chave não tem a permissão que esta rota exige. |
invalid_json | 400 | O corpo não é um JSON válido. |
payload_too_large | 413 | O corpo passa de 16 KB. |
validation_error | 422 | Algum campo não passou na validação. error.details.fields diz quais. |
not_found | 404 | O recurso não existe na conta (ou é de outra conta: a resposta é igual). |
ambiguous_lead | 409 | Mais de um cadastro com o mesmo contato. |
external_id_conflict | 409 | O external_id já foi usado em um envio de outro telefone. |
ambiguous_deal | 409 | O lead tem mais de um negócio aberto no funil; informe deal_id. |
pipeline_not_configured | 409 | O funil não tem etapa de entrada. |
stage_in_other_pipeline | 409 | A etapa é de outro funil. (Em POST /leads vem como 422.) |
won_requires_closing | 409 | Etapa de ganho: o fechamento é registrado no Pingo. (Em POST /leads vem como 422.) |
deal_already_won | 409 | O negócio já está em etapa de ganho e não sai dela pela API. |
notes_full | 409 | A ficha do lead não comporta mais texto. |
rate_limited | 429 | Muitas requisições. Espere o tempo do cabeçalho Retry-After. |
internal_error | 500 | Erro do nosso lado. Informe o request_id ao suporte. |
Listas e o cursor: devolva em cursor o next_cursor da resposta anterior até ele vir null.
Limites
| Regra | Limite |
|---|---|
| Por endereço de IP (todas as chaves) | 300 chamadas por minuto |
| Por chave | 120 chamadas por minuto |
| Gravações por chave (POST e PATCH; a busca POST /leads/lookup só lê e não entra aqui) | 60 por minuto |
| GET /metrics por chave | 20 por minuto |
| Envios de lead por conta (POST /leads) | 3.000 por dia |
| Tamanho do corpo | 16 KB |
| Chaves ativas por conta | 5 |
Passou do limite? A resposta é 429 rate_limited com o cabeçalho Retry-After (segundos). Espere esse tempo antes de tentar de novo. Se você reenvia leads, mande external_id: repetir a chamada não duplica nada.
Origem do lead
Você não diz de onde o lead veio: manda os sinais que tem (attribution) e o Pingo calcula a origem com a mesma regra do resto do aplicativo. É o que faz o lead do seu site aparecer no Pingo com a origem (Meta, Google, busca, direto...) e a campanha que você informou em utm_campaign. A API só registra a origem: ela nunca envia conversão para o Meta ou o Google. Os eventos de conversão saem pelas etapas do funil de marketing, quando o Pixel está configurado e a equipe marca a venda.
| Sinais recebidos | Origem gravada |
|---|---|
utm_source ou utm_medium com facebook, instagram, meta, fb ou ig, e vem fbclid (ou fbc) | meta_ads (anúncio do Meta) |
Mesmo utm de Meta, SEM fbclid nem fbc (mesmo que o utm_medium seja cpc ou paid) | social (rede social, sem clique de anúncio) |
utm de Google (google, adwords, gads ou youtube) e vem gclid, gbraid, wbraid ou gad_source (mesmo com utm_medium organic) | google_ads (anúncio do Google) |
| Mesmo utm de Google, SEM nenhum desses quatro sinais (mesmo que o utm_medium seja cpc) | organic_google (busca orgânica) |
Qualquer outro utm_source ou utm_medium (mesmo com gclid ou fbclid junto) | organic |
Sem utm, com gclid, gbraid, wbraid ou gad_source | google_ads |
Sem utm e sem sinal do Google, com fbclid (ou fbc) | meta_ads |
Sem utm nem clique, referrer do Google | organic_google |
Sem utm nem clique, referrer de Instagram, Facebook, Threads, X/Twitter, TikTok, linktr.ee, bio.link, beacons.ai ou t.co | social |
Sem utm nem clique, qualquer outro referrer | referral |
| Nenhum sinal | untracked (Não rastreado) |
- Primeiro contato vence. Se o lead já tem uma origem registrada (qualquer uma diferente de
untrackededirect, inclusivesocial,organicereferral), uma chamada nova não muda nenhum dado de origem dele. Se a origem éuntrackedoudirect, o Pingo preenche a origem e só os campos que ainda estão vazios. - Guarde os parâmetros da URL (utm_*,
gclid,fbclid) quando a pessoa chega no site e mande junto com o formulário. Sem eles o lead entra comountracked(Não rastreado). origineutmsó aparecem nas respostas se o plano da conta inclui a Origem automática; a origem é gravada de qualquer forma.- O utm decide primeiro; só sem utm entram os cliques e o referrer. Quando o utm cita Meta e Google ao mesmo tempo, vale o Meta; sem utm, o Google vence o Meta.
- Envie os sinais da PRIMEIRA visita (guarde em cookie ou localStorage), não o referrer da página do formulário: depois de navegar dentro do site, esse referrer é o próprio site e vira referral.
- O referrer precisa ser a URL completa, com https://. Só o endereço do site e o caminho são guardados (o que vem depois do ? é descartado).
- Sem fbclid, um lead de anúncio do Meta fica como social. Sem gclid, gbraid, wbraid ou gad_source, um lead de anúncio do Google fica como organic_google.
- O utm é lido por "contém": textos como "digital" ou "design" (que contêm "ig") são lidos como Meta. Use nomes claros em utm_source (google, facebook, instagram, newsletter...).
- Só o Google conta como busca orgânica. Bing e DuckDuckGo entram como referral.
- untracked (Não rastreado) é o lead sem nenhum sinal: a equipe pode preencher a origem à mão no Chat. Ele também aparece em origin e em by_origin.
- utm_content e utm_term são guardados na resposta do formulário, mas não entram no cálculo da origem.
- Um lead antigo que estava como untracked ou direct pode ter a origem preenchida uma vez, quando a API trouxer sinais. Isso muda o by_origin do período em que ele foi criado.
Receita: formulário do site
O caso mais comum. O formulário envia para o seu servidor, e o servidor chama o Pingo com a chave. Assim a chave não fica exposta e você controla o que é enviado.
// Next.js (app router): app/api/contato/route.ts
// A chave fica só no servidor (variável de ambiente), nunca no código que vai para o navegador.
export async function POST(req: Request) {
// O navegador manda os utm que guardou da URL e um envioId gerado UMA vez por formulário (ex.: crypto.randomUUID() quando a página carrega).
const { nome, telefone, email, utm, envioId } = await req.json();
const resposta = await fetch("https://www.pingotracker.com.br/api/v1/leads", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PINGO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: nome,
phone: telefone,
email,
tags: ["site"],
external_id: envioId, // o mesmo envioId em toda repetição do MESMO envio (clique duplo, nova tentativa): o lead não duplica
attribution: {
utm_source: utm?.source,
utm_medium: utm?.medium,
utm_campaign: utm?.campaign,
gclid: utm?.gclid,
fbclid: utm?.fbclid,
referrer: utm?.referrer,
},
}),
});
return Response.json({ ok: resposta.ok }, { status: resposta.ok ? 200 : 502 });
}Endpoints
Leads
/leadspermissão leads:writeCriar ou atualizar um lead
Cria o lead e o coloca no funil. Se já existe cadastro com o mesmo telefone, atualiza em vez de duplicar.
- O telefone é o que identifica o lead. O Pingo reconhece o mesmo número com ou sem o 9º dígito e com ou sem o 55, então reenviar "41 99999-0000" e "+55 41 9196-8668" não cria dois cadastros.
- Você NÃO envia a origem. Ela é calculada pelo Pingo a partir dos sinais de
attribution(utm_source, utm_medium, fbclid, gclid...), com a mesma regra do resto do aplicativo. Sem nenhum sinal, o lead fica comountracked(Não rastreado). Sinal com formato inválido é ignorado e voltado num aviso (warnings), sem derrubar o lead. - Vale o primeiro contato: se o lead já tem uma origem registrada (qualquer uma diferente de
untrackededirect, inclusivesocial,organicereferral), a chamada não muda nenhum dado de origem dele (utm, fbc, gclid...). Se a origem éuntrackedoudirect, o Pingo preenche a origem e só os campos de origem que ainda estão vazios, então a origem de um lead antigo pode mudar uma única vez. - Para repetir o envio com segurança (formulário reenviado, webhook que chega duas vezes), mande um
external_idúnico por envio. Com o mesmoexternal_id, o Pingo devolveduplicate: truee não grava nada de novo. - O lead entra na etapa de entrada do funil padrão. Para outro funil ou etapa, informe
deal.pipeline_idedeal.stage_id(veja GET /pipelines). Se o lead já tem negócio aberto nesse funil, ele NÃO é movido: para mover, use POST /leads/{id}/stage. - Esta chamada só grava. Não envia mensagem ao lead e não dispara NA HORA nenhuma automação do funil. Atenção: se a etapa tem uma automação por tempo (por exemplo, follow-up para quem fica parado há alguns dias), ela passa a valer para o lead da API como vale para qualquer outro lead.
- A nota (
notes) é acrescentada à ficha do lead, marcada com [API · nome da chave · data], sem apagar o que a equipe já escreveu. Tags novas são criadas na conta (até 5 por chamada). - Uma chave SEM
leads:read(a de um formulário, por exemplo) recebe sempre a mesma resposta curta,{ "received": true }com status 202, seja o lead novo ou já existente: assim a chave de escrita não serve para descobrir quem já é cliente. Comleads:read, a resposta trazid,created,duplicate,deale o cadastro (lead);created: false(status 200) quer dizer que o telefone já era conhecido no Pingo (cadastro ou conversa).
Corpo (JSON)
| Campo | Tipo | Descrição |
|---|---|---|
phoneobrigatório | texto | Telefone com DDD (ex.: 41999990000) ou com + e código do país (ex.: +14155550123). Pode vir com espaço, parênteses e traço; letras e ramal são recusados. Número com 10 ou 11 dígitos sem + só é aceito se for brasileiro de verdade (DDD que existe); um zero antes do DDD (041...) é tirado. |
name | texto (até 120) | Nome do lead. Em um cadastro que já existe, o nome não é sobrescrito. |
email | texto | E-mail. Só preenche se o cadastro ainda não tem e-mail. |
notes | texto (até 500) | Observação acrescentada à ficha do lead. |
tags | lista de textos (até 5, cada uma até 40) | Tags aplicadas ao lead. As que não existem são criadas. |
external_id | texto (até 100; letras, números e . _ : @ -) | Identificador DO ENVIO na sua origem (um por envio, não um valor fixo). Repetir o mesmo valor com o mesmo telefone não duplica nada; o mesmo valor com OUTRO telefone dá 409 external_id_conflict. |
consent | verdadeiro/falso | Se true, registra o consentimento LGPD do lead. Nunca remove um consentimento já dado. |
attribution | objeto | Sinais de origem, todos texto e opcionais: utm_source, utm_medium, utm_campaign, utm_content, utm_term, fbclid, fbc (o valor do cookie _fbc do Meta, se você o tiver), gclid, gbraid, wbraid, gad_source e referrer (URL completa, com https://; só o endereço e o caminho são guardados). Os identificadores de clique (fbclid, gclid, gbraid, wbraid) têm letras, números, _ e - (8 a 500 caracteres); fora disso são ignorados com aviso. |
deal.pipeline_id | texto | Funil de destino. Sem isto, vale o funil padrão. |
deal.stage_id | texto | Etapa de destino (do mesmo funil). Não pode ser etapa de ganho. |
deal.value | número | Valor PREVISTO do negócio em reais, quando o negócio é criado agora (não é venda fechada). Se o funil da conta tem uma automação que envia conversão ao Meta, ela pode usar esse valor quando o negócio for movido no Pingo. |
curl -X POST "https://www.pingotracker.com.br/api/v1/leads" \
-H "Authorization: Bearer $PINGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Maria Silva",
"phone": "41999990000",
"email": "maria@exemplo.com.br",
"notes": "Quer horário à tarde",
"tags": [
"site"
],
"external_id": "form-2026-0001",
"consent": true,
"attribution": {
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "implante-curitiba",
"gclid": "Cj0KCQjwExemploGclid123",
"referrer": "https://www.google.com/"
},
"deal": {
"value": 1500.5
}
}'Resposta 201
{
"data": {
"id": "cm1lead0000000000000000a1",
"created": true,
"duplicate": false,
"deal": {
"id": "cm1negoc0000000000000000a1",
"pipeline_id": "cm1funil000000000000000a1",
"stage_id": "cm1etapa000000000000entr1",
"status": "open",
"value": 1500.5,
"entered_stage_at": "2026-10-15T13:20:11.000Z",
"created_at": "2026-10-15T13:20:11.000Z"
},
"lead": {
"id": "cm1lead0000000000000000a1",
"name": "Maria Silva",
"phone": "5541999990000",
"email": "maria@exemplo.com.br",
"tags": [
"site",
"vip"
],
"origin": "google_ads",
"utm": {
"source": "google",
"medium": "cpc",
"campaign": "implante-curitiba"
},
"deals": [
{
"id": "cm1negoc0000000000000000a1",
"pipeline_id": "cm1funil000000000000000a1",
"stage_id": "cm1etapa000000000000entr1",
"status": "open",
"value": 1500.5,
"entered_stage_at": "2026-10-15T13:20:11.000Z",
"created_at": "2026-10-15T13:20:11.000Z"
}
],
"created_at": "2026-10-15T13:20:11.000Z",
"updated_at": "2026-10-15T13:20:11.000Z"
}
}
}Resposta 202: Chave sem leads:read (só escrita): resposta uniforme
{
"data": {
"received": true
}
}Erros desta rota (além dos gerais)
| HTTP | Código | Quando |
|---|---|---|
| 409 | ambiguous_lead | Há mais de um cadastro com este telefone no Pingo. Resolva a duplicidade no Pingo. (Chave sem leads:read recebe a resposta curta 202 e o envio não é aplicado.) |
| 409 | external_id_conflict | O external_id já foi usado em um envio de outro telefone. |
| 409 | pipeline_not_configured | O funil informado não tem etapa de entrada. |
| 422 | validation_error | Campo inválido, campo desconhecido, telefone inválido ou funil/etapa que não existe na conta. |
| 422 | stage_in_other_pipeline | A etapa informada não é do funil informado. |
| 422 | won_requires_closing | A etapa é de ganho: o fechamento (valor) é registrado no Pingo, não pela API. |
/leadspermissão leads:readListar leads
Lista os leads da conta, de 100 em 100 no máximo, com filtros que não são dado pessoal.
- As páginas são por
cursor: devolva emcursoronext_cursorda resposta anterior até ele virnull. - Para sincronizar de tempos em tempos, use
updated_sincecom a hora da última sincronização menos 5 minutos de folga. A data de atualização do lead considera também a mudança de etapa dos negócios. Um lead pode aparecer mais de uma vez em sincronizações seguidas; trate peloid. - Para achar UM lead por telefone ou e-mail, use POST /leads/lookup (telefone e e-mail não devem ir na URL).
origineutmsó aparecem se o plano da conta inclui a Origem automática.
Parâmetros da consulta
| Campo | Tipo | Descrição |
|---|---|---|
limit | inteiro (1 a 100) | Quantos leads por página. Padrão 50. |
cursor | texto | O next_cursor da página anterior. |
pipeline_id | texto | Só leads com negócio neste funil. |
stage_id | texto | Só leads com negócio nesta etapa. |
tag | texto | Só leads com esta tag (sem diferenciar maiúscula). |
updated_since | data e hora ISO 8601 | Só leads atualizados a partir deste momento. |
curl -X GET "https://www.pingotracker.com.br/api/v1/leads?limit=50&updated_since=2026-10-15T00%3A00%3A00Z" \
-H "Authorization: Bearer $PINGO_API_KEY"Resposta 200
{
"data": [
{
"id": "cm1lead0000000000000000a1",
"name": "Maria Silva",
"phone": "5541999990000",
"email": "maria@exemplo.com.br",
"tags": [
"site",
"vip"
],
"origin": "google_ads",
"utm": {
"source": "google",
"medium": "cpc",
"campaign": "implante-curitiba"
},
"deals": [
{
"id": "cm1negoc0000000000000000a1",
"pipeline_id": "cm1funil000000000000000a1",
"stage_id": "cm1etapa000000000000entr1",
"status": "open",
"value": 1500.5,
"entered_stage_at": "2026-10-15T13:20:11.000Z",
"created_at": "2026-10-15T13:20:11.000Z"
}
],
"created_at": "2026-10-15T13:20:11.000Z",
"updated_at": "2026-10-15T13:20:11.000Z"
}
],
"next_cursor": null
}Erros desta rota (além dos gerais)
| HTTP | Código | Quando |
|---|---|---|
| 422 | validation_error | Parâmetro inválido ou desconhecido (ex.: limit acima de 100). |
/leads/lookuppermissão leads:readAchar um lead por telefone ou e-mail
Devolve o lead que tem aquele telefone (ou e-mail). É POST de propósito: dado pessoal não deve ir na URL.
- Informe exatamente um entre
phoneeemail. - O telefone é comparado com e sem o 9º dígito e com e sem o 55. O e-mail não diferencia maiúscula. Número de outro país vai com o + na frente (ex.: +14155550123), mesmo que a resposta o traga só com dígitos: sem o +, 10 ou 11 dígitos só valem se forem brasileiros.
- Se houver mais de um cadastro com o mesmo contato, a resposta é 409 (
ambiguous_lead): a API não adivinha qual é o certo.
Corpo (JSON)
| Campo | Tipo | Descrição |
|---|---|---|
phone | texto | Telefone a procurar. |
email | texto | E-mail a procurar (use este OU o telefone). |
curl -X POST "https://www.pingotracker.com.br/api/v1/leads/lookup" \
-H "Authorization: Bearer $PINGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "41999990000"
}'Resposta 200
{
"data": {
"id": "cm1lead0000000000000000a1",
"name": "Maria Silva",
"phone": "5541999990000",
"email": "maria@exemplo.com.br",
"tags": [
"site",
"vip"
],
"origin": "google_ads",
"utm": {
"source": "google",
"medium": "cpc",
"campaign": "implante-curitiba"
},
"deals": [
{
"id": "cm1negoc0000000000000000a1",
"pipeline_id": "cm1funil000000000000000a1",
"stage_id": "cm1etapa000000000000entr1",
"status": "open",
"value": 1500.5,
"entered_stage_at": "2026-10-15T13:20:11.000Z",
"created_at": "2026-10-15T13:20:11.000Z"
}
],
"created_at": "2026-10-15T13:20:11.000Z",
"updated_at": "2026-10-15T13:20:11.000Z"
}
}Erros desta rota (além dos gerais)
| HTTP | Código | Quando |
|---|---|---|
| 404 | not_found | Nenhum lead com esse contato. |
| 409 | ambiguous_lead | Mais de um cadastro com esse contato. |
| 422 | validation_error | Telefone inválido, ou os dois (ou nenhum) informados. |
/leads/{id}permissão leads:readConsultar um lead
Devolve o lead pelo id, com tags, origem e negócios.
- Um id que não existe na sua conta e um id de outra conta dão exatamente a mesma resposta: 404.
Parâmetros do caminho
| Campo | Tipo | Descrição |
|---|---|---|
idobrigatório | texto | O id do lead. |
curl -X GET "https://www.pingotracker.com.br/api/v1/leads/ID_DO_LEAD" \
-H "Authorization: Bearer $PINGO_API_KEY"Resposta 200
{
"data": {
"id": "cm1lead0000000000000000a1",
"name": "Maria Silva",
"phone": "5541999990000",
"email": "maria@exemplo.com.br",
"tags": [
"site",
"vip"
],
"origin": "google_ads",
"utm": {
"source": "google",
"medium": "cpc",
"campaign": "implante-curitiba"
},
"deals": [
{
"id": "cm1negoc0000000000000000a1",
"pipeline_id": "cm1funil000000000000000a1",
"stage_id": "cm1etapa000000000000entr1",
"status": "open",
"value": 1500.5,
"entered_stage_at": "2026-10-15T13:20:11.000Z",
"created_at": "2026-10-15T13:20:11.000Z"
}
],
"created_at": "2026-10-15T13:20:11.000Z",
"updated_at": "2026-10-15T13:20:11.000Z"
}
}Erros desta rota (além dos gerais)
| HTTP | Código | Quando |
|---|---|---|
| 404 | not_found | Lead não encontrado na conta. |
/leads/{id}permissão leads:writeAtualizar um lead
Muda nome, e-mail, tags e acrescenta uma nota. O telefone não muda por aqui.
- Envie só o que quer mudar, ao menos um campo.
email: nullapaga o e-mail.add_tagscria as tags que não existem;remove_tagsignora as que não existem. O telefone não pode ser alterado (ele liga o cadastro à conversa do WhatsApp).- A mudança vale só no Pingo: o cadastro do seu sistema de gestão (Feegow, Clinicorp, Conta Azul...) não é alterado, então os dois podem ficar diferentes.
- A nota é acrescentada à ficha, nunca substitui. Se a ficha não comporta mais texto (limite de 2.000 caracteres), a resposta é 409
notes_fulle NADA é alterado.
Parâmetros do caminho
| Campo | Tipo | Descrição |
|---|---|---|
idobrigatório | texto | O id do lead. |
Corpo (JSON)
| Campo | Tipo | Descrição |
|---|---|---|
name | texto (até 120) | Novo nome. |
email | texto ou null | Novo e-mail, ou null para apagar. |
add_tags | lista de textos (até 5) | Tags a acrescentar. |
remove_tags | lista de textos (até 5) | Tags a retirar. |
notes | texto (até 500) | Nota acrescentada à ficha. |
curl -X PATCH "https://www.pingotracker.com.br/api/v1/leads/ID_DO_LEAD" \
-H "Authorization: Bearer $PINGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Maria Silva",
"add_tags": [
"retorno"
],
"remove_tags": [
"site"
],
"notes": "Ligar na quinta"
}'Resposta 200
{
"data": {
"id": "cm1lead0000000000000000a1",
"updated": true,
"lead": {
"id": "cm1lead0000000000000000a1",
"name": "Maria Silva",
"phone": "5541999990000",
"email": "maria@exemplo.com.br",
"tags": [
"site",
"vip"
],
"origin": "google_ads",
"utm": {
"source": "google",
"medium": "cpc",
"campaign": "implante-curitiba"
},
"deals": [
{
"id": "cm1negoc0000000000000000a1",
"pipeline_id": "cm1funil000000000000000a1",
"stage_id": "cm1etapa000000000000entr1",
"status": "open",
"value": 1500.5,
"entered_stage_at": "2026-10-15T13:20:11.000Z",
"created_at": "2026-10-15T13:20:11.000Z"
}
],
"created_at": "2026-10-15T13:20:11.000Z",
"updated_at": "2026-10-15T13:20:11.000Z"
}
}
}Erros desta rota (além dos gerais)
| HTTP | Código | Quando |
|---|---|---|
| 404 | not_found | Lead não encontrado na conta. |
| 409 | notes_full | A ficha do lead está cheia. Nada foi alterado. |
| 422 | validation_error | Campo inválido ou desconhecido (inclusive phone), ou corpo vazio. |
Funil
/leads/{id}/stagepermissão pipeline:writeMover o lead de etapa
Move o negócio aberto do lead para outra etapa do mesmo funil.
- Mover pela API NÃO dispara a automação da etapa: não manda mensagem ao lead e não envia conversão ao Meta. É o mesmo que mover em massa no Pingo sem marcar "disparar a automação". Automações por tempo da etapa nova ("parado há N dias") continuam valendo.
- A API não entra em etapa de ganho (fechar exige registrar o valor no Pingo) e não tira o negócio de uma etapa de ganho (não desfaz venda). Mover para uma etapa de perda e reabrir (sair da perda) funcionam.
- Se o lead tem mais de um negócio aberto no funil da etapa, informe
deal_id. Mover para a etapa em que o negócio já está devolvechanged: false.
Parâmetros do caminho
| Campo | Tipo | Descrição |
|---|---|---|
idobrigatório | texto | O id do lead. |
Corpo (JSON)
| Campo | Tipo | Descrição |
|---|---|---|
stage_idobrigatório | texto | Etapa de destino (veja GET /pipelines). |
deal_id | texto | Negócio a mover, quando o lead tem mais de um aberto no funil. |
curl -X POST "https://www.pingotracker.com.br/api/v1/leads/ID_DO_LEAD/stage" \
-H "Authorization: Bearer $PINGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"stage_id": "cm1etapa00000000000000pre1"
}'Resposta 200
{
"data": {
"changed": true,
"deal": {
"id": "cm1negoc0000000000000000a1",
"pipeline_id": "cm1funil000000000000000a1",
"stage_id": "cm1etapa00000000000000pre1",
"status": "open",
"value": 1500.5,
"entered_stage_at": "2026-10-15T14:02:40.000Z",
"created_at": "2026-10-15T13:20:11.000Z"
}
}
}Erros desta rota (além dos gerais)
| HTTP | Código | Quando |
|---|---|---|
| 404 | not_found | Lead, etapa ou negócio não encontrado na conta, ou o lead não tem negócio aberto nesse funil. |
| 409 | ambiguous_deal | Mais de um negócio aberto no funil da etapa. Informe deal_id. |
| 409 | stage_in_other_pipeline | A etapa é de outro funil que o do negócio. |
| 409 | won_requires_closing | A etapa é de ganho. |
| 409 | deal_already_won | O negócio já está numa etapa de ganho. |
/pipelinespermissão pipeline:readListar funis e etapas
Os funis da conta com suas etapas: são os ids que POST /leads e POST /leads/{id}/stage pedem.
- O funil padrão vem primeiro.
is_entrymarca a etapa onde o lead novo nasce;is_woneis_lostmarcam as etapas de ganho e de perda.
curl -X GET "https://www.pingotracker.com.br/api/v1/pipelines" \
-H "Authorization: Bearer $PINGO_API_KEY"Resposta 200
{
"data": [
{
"id": "cm1funil000000000000000a1",
"name": "Comercial",
"is_default": true,
"stages": [
{
"id": "cm1etapa000000000000entr1",
"name": "Leads de Entrada",
"order": 0,
"is_entry": true,
"is_won": false,
"is_lost": false
},
{
"id": "cm1etapa00000000000000pre1",
"name": "Pré Vendas",
"order": 1,
"is_entry": false,
"is_won": false,
"is_lost": false
},
{
"id": "cm1etapa000000000000fech1",
"name": "Fechado",
"order": 5,
"is_entry": false,
"is_won": true,
"is_lost": false
},
{
"id": "cm1etapa000000000000perd1",
"name": "Perdido (sem contato)",
"order": 6,
"is_entry": false,
"is_won": false,
"is_lost": true
}
]
}
]
}Métricas
/metricspermissão metrics:readMétricas do período
Números agregados da conta (leads por dia e por origem, negócios por etapa). Nenhum dado de pessoa.
- O período vai de
fromato, os dois inclusive, em dias de Brasília (padrão: os últimos 30 dias; no máximo 366 dias). leadsconta as conversas criadas no período, de qualquer canal (WhatsApp, formulários, API). Dias sem lead não aparecem emdaily.scheduledconta os leads do período que estão AGORA numa etapa de agendamento: quem já avançou para outra etapa deixa de contar.closedconta os que estão numa etapa de venda ou numa etapa com valor configurado (uma etapa "Agendou R$ 450" conta). Os dois sãonullse a conta não configurou a etapa.attendedsão as consultas com comparecimento na agenda do período.pipeline.stages[].open_dealsé o retrato de HOJE (negócios abertos por etapa), não depende do período.by_originsó aparece se o plano da conta inclui a Origem automática. Receita não faz parte desta versão.- Esta rota é mais pesada: limite de 20 chamadas por minuto por chave.
Parâmetros da consulta
| Campo | Tipo | Descrição |
|---|---|---|
from | data AAAA-MM-DD | Primeiro dia do período. |
to | data AAAA-MM-DD | Último dia do período (inclusive). |
pipeline_id | texto | Funil para o retrato de negócios por etapa. Padrão: o funil padrão. |
curl -X GET "https://www.pingotracker.com.br/api/v1/metrics?from=2026-10-01&to=2026-10-15" \
-H "Authorization: Bearer $PINGO_API_KEY"Resposta 200
{
"data": {
"period": {
"from": "2026-10-01",
"to": "2026-10-15"
},
"leads": 128,
"scheduled": 31,
"closed": 9,
"attended": 24,
"daily": [
{
"date": "2026-10-14",
"leads": 9
},
{
"date": "2026-10-15",
"leads": 12
}
],
"by_origin": [
{
"origin": "google_ads",
"leads": 60
},
{
"origin": "meta_ads",
"leads": 48
},
{
"origin": "direct",
"leads": 20
}
],
"pipeline": {
"id": "cm1funil000000000000000a1",
"name": "Comercial",
"stages": [
{
"id": "cm1etapa000000000000entr1",
"name": "Leads de Entrada",
"open_deals": 14
},
{
"id": "cm1etapa00000000000000pre1",
"name": "Pré Vendas",
"open_deals": 22
}
]
}
}
}Erros desta rota (além dos gerais)
| HTTP | Código | Quando |
|---|---|---|
| 404 | not_found | pipeline_id não existe na conta. |
| 422 | validation_error | Data inválida, período invertido ou maior que 366 dias. |
O que a API não faz
- Não envia mensagem de WhatsApp nem de Instagram.
- Não dispara as automações do funil na hora: criar ou mover um lead pela API só grava, não manda mensagem nem conversão ao Meta. Automações por tempo da etapa (como o follow-up de quem fica parado há alguns dias) continuam valendo para o lead da API.
- Não fecha negócio nem registra valor de venda: etapa de ganho é recusada (o fechamento é feito no Pingo).
- Não apaga lead, não lê conversas e não troca o telefone de um lead.
- Não avisa o seu sistema quando algo muda (sem webhooks de saída nesta versão): para acompanhar mudanças, consulte
GET /leads?updated_since=...de tempos em tempos.
Postman e OpenAPI
A coleção do Postman já vem com todas as rotas, exemplos e a variável api_key para você colar a chave. O arquivo OpenAPI serve para gerar clientes de código e importar em outras ferramentas.
Dúvidas ou algo que a API ainda não cobre? Escreva para contato@pingotracker.com.br com o request_id da chamada, se houver.