Leads
Um lead é um envio de formulário — um nome, um e-mail, um telefone digitados por uma pessoa real em um formulário do site. São dados pessoais, e esta superfície os trata assim.
| Método | Caminho | Escopo |
|---|---|---|
GET |
/v1/leads |
leads:read |
GET |
/v1/leads/{id} |
leads:read |
- URL base:
https://api.canverly.com - Autenticação:
Authorization: Bearer ck_…— escopoleads:read - Limite de requisição: 10 req/min por chave (bucket de leads) e 60 req/min (bucket geral)
O site é derivado da chave. Não existe parâmetro de site, e uma chave só lê os leads do próprio site.
GET /v1/leads
Seção intitulada “GET /v1/leads”Lista os leads do site, do mais recente para o mais antigo, paginados por cursor.
Parâmetros
Seção intitulada “Parâmetros”| Parâmetro | Tipo | Padrão | Observações |
|---|---|---|---|
form_id |
string (ULID/UUID) | — | Restringe a um formulário. Omita para listar todos os formulários do site. |
status |
string | clean |
clean, spam ou all. Qualquer outro valor é um 422. |
de |
string | — | Início do período — YYYY-MM-DD ou um instante RFC-3339. |
ate |
string | — | Fim do período — inclusivo quando informado como data (ate=2026-08-10 cobre todo o dia 10 de agosto); um instante RFC-3339 explícito é usado como limite superior exclusivo. |
cursor |
string | — | Cursor keyset vindo do next_cursor da página anterior. |
limit |
integer | 50 |
1–200. Valores fora da faixa são ajustados para dentro dela; um valor não inteiro é rejeitado. |
ordem |
string | desc |
Ordem — desc (mais recentes primeiro) ou asc. Qualquer outro valor é um 422. |
de precisa ser estritamente anterior a ate — um período invertido ou vazio é um 422, não uma lista vazia. Uma data ou um cursor que não pode ser interpretado também é um 422: nada é ignorado em silêncio, porque um filtro que cai silenciosamente em um fallback entregaria mais dados pessoais do que você pediu.
Exemplo
Seção intitulada “Exemplo”curl "https://api.canverly.com/v1/leads?status=clean&de=2026-08-01&ate=2026-08-31&limit=50" \ -H "Authorization: Bearer ck_live_xxx"{ "items": [ { "id": "01K8Z9K3F7T8M2QYV5N6B4WJ8R", "form_id": "01K8Z8YVQ4N7B1C2D3E4F5G6H7", "page_path": "/contato", "data": { "nome": "Ana Teste", "email": "ana@example.test", "mensagem": "Quero um orçamento." }, "status": "clean", "spam_score": 0, "created_at": "2026-08-24T14:03:11Z" } ], "next_cursor": ""}| Campo | Tipo | Observações |
|---|---|---|
items[] |
Lead[] | A página de leads — veja o objeto Lead. |
next_cursor |
string | null | Devolva-o como cursor para obter a próxima página. O fim da coleção é sinalizado por uma string vazia "" — trate "", null e um campo ausente da mesma forma: pare. Um cursor só é emitido quando a página veio cheia, então a última página sempre encerra a varredura. |
Paginação
Seção intitulada “Paginação”Keyset, não offset: leia next_cursor, envie-o como cursor e repita até ele voltar vazio. Cursores são opacos — não os interprete nem os construa. Um cursor de outro filtro não tem significado; mantenha os demais parâmetros idênticos em todas as páginas de uma mesma varredura.
curl "https://api.canverly.com/v1/leads?limit=50&cursor=1756044191000000000%7C01K8Z9K3F7T8M2QYV5N6B4WJ8R" \ -H "Authorization: Bearer ck_live_xxx"Lembre-se do teto de 10 req/min: com limit=200, isso dá até 2 000 leads por minuto, o que basta para uma sincronização, mas não para uma raspagem. Para um dump completo, use a exportação — veja Exportação em massa.
GET /v1/leads/{id}
Seção intitulada “GET /v1/leads/{id}”Lê um único lead. id é o ULID do lead (um UUID também é aceito). A resposta é um lead exatamente no mesmo formato de um item da lista — sem o envelope items.
curl "https://api.canverly.com/v1/leads/01K8Z9K3F7T8M2QYV5N6B4WJ8R" \ -H "Authorization: Bearer ck_live_xxx"{ "id": "01K8Z9K3F7T8M2QYV5N6B4WJ8R", "form_id": "01K8Z8YVQ4N7B1C2D3E4F5G6H7", "page_path": "/contato", "data": { "nome": "Ana Teste", "email": "ana@example.test" }, "status": "clean", "spam_score": 0, "created_at": "2026-08-24T14:03:11Z"}O objeto Lead
Seção intitulada “O objeto Lead”| Campo | Tipo | Observações |
|---|---|---|
id |
string (ULID) | Identificador do lead. |
form_id |
string (ULID) | O formulário que o gerou. |
page_path |
string | Caminho da página de onde o formulário foi enviado, ex.: /contato. |
data |
object | As respostas enviadas: id do campo → valor string. As chaves são os ids de campo do próprio formulário, então variam de formulário para formulário. |
status |
string | clean ou spam. |
spam_score |
integer | Intensidade do sinal de spam (0 = nenhum sinal). |
created_at |
string (RFC-3339) | Quando foi enviado, em UTC. |
Tudo em data é digitado por um visitante. Trate como entrada não confiável: escape antes de renderizar e nunca interpole em HTML, SQL ou comando de shell.
Exportação em massa
Seção intitulada “Exportação em massa”Para puxar a coleção inteira de uma vez — NDJSON ou CSV, em streaming — use GET /v1/export?resource=leads em vez de paginar esta rota. Ela exige tanto o escopo export quanto leads:read, e é auditada e tem limite de requisição exatamente como as rotas desta página. Veja Exportação e importação em massa.
Envelope: { "error": { "code", "message" } }. Tabela completa em Erros e limites de requisição.
| Status | error.code |
Quando |
|---|---|---|
400 |
upstream |
limit malformado na lista (não inteiro). Envie um número inteiro. |
401 |
unauthorized |
Chave ausente, inválida ou revogada. |
403 |
forbidden |
A chave não tem leads:read — ele é opt-in, então uma chave que nunca o recebeu cai aqui. Recrie a chave com o escopo. |
404 |
not_found |
O site não é membro, ou o app Forms não está instalado nele. Em /v1/leads/{id}, também: o lead não existe ou pertence a outro site. Todos esses casos são o mesmo 404 opaco. |
422 |
— | Filtro inválido na lista: status desconhecido, ordem desconhecida, de/ate que não pode ser interpretado, período invertido ou cursor malformado. A message diz qual. |
429 |
rate_limited |
O bucket rígido de leads (10/min) ou o bucket geral (60/min). Respeite o Retry-After. |
5xx |
upstream |
Erro upstream transitório; tente de novo com backoff. |
Como tratar os dados com responsabilidade
Seção intitulada “Como tratar os dados com responsabilidade”- Conceda
leads:reada uma chave, para uma tarefa. Uma chave de publicação não precisa dele. Uma chave por consumidor mantém a trilha de auditoria legível e o raio de impacto pequeno. - Parta do princípio de que a leitura fica registrada. Toda chamada que você faz é atribuída à chave na trilha de auditoria, inclusive as que terminam em
404. - Não espelhe leads em um sistema com controle de acesso mais fraco que o admin do Canverly, e não registre respostas completas em log — isso transforma um log de debug em uma cópia da base de contatos.
- Faça retries com educação. Em um
429, aguardeRetry-Aftersegundos. A 10 req/min, um ritmo fixo de uma requisição a cada 6 segundos nunca atinge o limite.