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 só é alcançável por ele. Todo endpoint que cria algo devolve ocontact_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):
| code | status | o que fazer |
|---|---|---|
invalid_request | 400 | Corrigir o corpo. Retentar igual não adianta |
unauthenticated | 401 | Conferir a chave |
forbidden | 403 | Permissão da chave ou recurso fora do plano |
not_found | 404 | O alvo não existe nesta conta |
conflict | 409 | Idempotency-Key reusada com outro corpo |
rate_limited | 429 | Esperar o Retry-After e retentar |
internal | 500 | Falha 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/salesa chave de idempotência é o campoexternal_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.
