Convenções da API

Como identificar um contato, paginar listas, tratar erros e evitar duplicidade quando sua automação tentar de novo.

Estas quatro regras valem em toda a API. Aprendendo uma vez, você sabe usar qualquer endpoint novo.

1. Identificar um contato: contact_id ou phone

Todo endpoint que fala de contato aceita os dois:

{ "contact_id": "3f9a…" }
{ "phone": "5551999998888" }

O telefone é normalizado (aceita com ou sem o nono dígito, com ou sem símbolos) e a busca alcança também os números secundários do contato.

Quando os dois vêm, o contact_id vence — ele é exato, o telefone é uma busca.

Prefira o contact_id. Contato de Instagram ou de Lead Ads sem telefone é alcançável por ele. Todo endpoint que cria algo devolve o contact_id; guarde-o do lado da sua automação.

2. Paginação: cursor, não página

Listas devolvem no máximo 100 itens (padrão 50) e um cursor:

{
  "ok": true,
  "contacts": [ … ],
  "has_more": true,
  "next_cursor": "MjAyNi0wOC0wNVQxMjozNDo1Ni43…"
}

Para a próxima página, mande o cursor de volta:

curl "https://www.scalacrm.com/api/v1/contacts?cursor=MjAyNi0w…&limit=100" \
  -H "Authorization: Bearer sk_live_…"

Repita enquanto has_more for true.

Por que cursor e não ?page=2: a lista se reordena o tempo todo (lead novo, mensagem nova). Com número de página, um item que entra no topo empurra outro para a página seguinte — e você recebe o mesmo registro duas vezes ou nunca o vê. Com cursor isso não acontece.

3. Erros: sempre com código

{
  "ok": false,
  "error": {
    "code": "not_found",
    "message": "Contato não encontrado nesta conta.",
    "field": "contact_id"
  }
}

Programe contra o code, nunca contra a mensagem (que pode mudar):

codestatuso que fazer
invalid_request400Corrigir o corpo. Retentar igual não adianta
unauthenticated401Conferir a chave
forbidden403Permissão da chave ou recurso fora do plano
not_found404O alvo não existe nesta conta
conflict409Idempotency-Key reusada com outro corpo
rate_limited429Esperar o Retry-After e retentar
internal500Falha nossa — retentar é razoável

Sucesso sempre traz "ok": true, então um único teste serve para tudo.

4. Idempotência: mande Idempotency-Key

Automação retenta — é o normal, não a exceção. Sem uma chave, o retry cria o segundo contato, o segundo card, a segunda mensagem.

curl -X POST https://www.scalacrm.com/api/v1/cards \
  -H "Authorization: Bearer sk_live_…" \
  -H "Idempotency-Key: lead-4821" \
  -H "Content-Type: application/json" \
  -d '{"contact_id":"3f9a…","stage_id":"7c2b…"}'

Se a mesma chave chegar de novo com o mesmo corpo, devolvemos a resposta original (com o cabeçalho Idempotent-Replay: true) sem executar nada.

⚠️ Mesma chave com corpo diferente devolve 409. É proposital: sem isso, uma chave fixa no código com corpo variável receberia a resposta de outra requisição — em silêncio. Use uma chave por operação: o id do lead no seu sistema, o id da linha da planilha, um UUID.

As chaves valem 24 horas — tempo de sobra para qualquer retry.

Vendas são diferentes. Em POST /v1/sales a chave de idempotência é o campo external_id, que vale para sempre (não 24h). Venda duplicada dispara conversão duplicada para Meta e Google, o que envenena a otimização das suas campanhas com receita que não existiu.

Veja também