Pular para o conteúdo

Listas de Contatos

As Listas são os agrupamentos de contatos da sua organização — as mesmas listas da aba Contatos → Listas e que as campanhas de e-mail usam como público. A aba aparece para administradores quando o CRM de e-mail está disponível. Esta seção cobre os endpoints para adicionar um contato à lista, ler os membros e descadastrar.

É por aqui que um sistema externo (formulário, checkout, CRM, n8n, Make) coloca gente dentro do SquadOS: o contato entra com e-mail válido, origem do consentimento e campos personalizados, e isso dispara as automações que usam o gatilho “Contato adicionado à lista”.

Todos os endpoints exigem o header Authorization: Bearer pk_.... Quando houver corpo JSON, inclua também Content-Type: application/json.

Base URL: https://api.squados.io/v1

Consulte Autenticação para obter sua chave, e Erros para a referência de códigos.

{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Newsletter",
"public_name": "Novidades do produto",
"description": "Quem assinou pelo rodapé do site",
"kind": "marketing",
"subscribed_count": 1284,
"unsubscribed_count": 37,
"created_at": "2026-08-01T12:00:00Z",
"updated_at": "2026-08-19T09:31:00Z"
}
CampoTipoDescrição
iduuidIdentificador da lista. É o listId dos endpoints abaixo.
namestringNome interno, o que sua equipe vê no painel.
public_namestringNome exibido para o contato no centro de preferências.
descriptionstring ou nullNota interna sobre a lista.
kindstringmarketing ou transactional.
subscribed_countintegerInscritos ativos.
unsubscribed_countintegerQuem descadastrou.
created_atdate-timeCriação da lista em ISO 8601.
updated_atdate-timeÚltima alteração da lista em ISO 8601.

Lista as listas da organização, da mais recente para a mais antiga.

Parâmetros de query

NomeTipoPadrãoDescrição
limitinteger50Máximo de 100.
offsetinteger0Deslocamento para paginar.

Envie inteiros não negativos e use limit entre 1 e 100. A resposta não traz total, next nem has_more: some a quantidade recebida ao offset e encerre quando vierem menos itens que o limit.

Terminal window
curl -X GET "https://api.squados.io/v1/lists" \
-H "Authorization: Bearer pk_sua_chave_aqui"

Resposta — 200 OK

{
"lists": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Newsletter",
"public_name": "Novidades do produto",
"description": null,
"kind": "marketing",
"subscribed_count": 1284,
"unsubscribed_count": 37,
"created_at": "2026-08-01T12:00:00Z",
"updated_at": "2026-08-19T09:31:00Z"
}
],
"limit": 50,
"offset": 0
}

Detalha uma lista.

Resposta — 200 OK

{
"list": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Newsletter",
"public_name": "Novidades do produto",
"description": null,
"kind": "marketing",
"subscribed_count": 1284,
"unsubscribed_count": 37,
"created_at": "2026-08-01T12:00:00Z",
"updated_at": "2026-08-19T09:31:00Z"
}
}

listId inválido responde 400 invalid_request. Uma lista interna, inexistente ou de outra organização responde 404 not_found — a chave só enxerga a organização que a gerou.


O endpoint principal. Cria (ou reaproveita) o contato pelo e-mail e o inscreve na lista.

Parâmetros de caminho

NomeTipoDescrição
listIduuidID da lista.

Corpo da requisição

CampoTipoObrigatórioDescrição
emailstringsimEndereço do contato. É normalizado para minúsculas — [email protected] e [email protected] são o mesmo contato.
consent_sourcestringsimOnde esta pessoa consentiu em receber contato. De 3 a 500 caracteres, em texto livre (ex.: "formulário de newsletter do rodapé", "checkout da loja em 12/08/2026").
namestringnãoNome de exibição do contato, até 200 caracteres. Quando enviado preenchido, atualiza o nome atual.
metadataobjectnãoCampos personalizados do contato (veja abaixo).
statusstringnãosubscribed (padrão) ou pending.
Terminal window
curl -X POST "https://api.squados.io/v1/lists/3fa85f64-5717-4562-b3fc-2c963f66afa6/contacts" \
-H "Authorization: Bearer pk_sua_chave_aqui" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"name": "Maria Silva",
"consent_source": "formulário de newsletter do rodapé do site",
"metadata": {
"plano": "pro",
"mrr": 199,
"origem": "google_ads"
}
}'

Resposta — 201 Created

{
"contact": {
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"email": "[email protected]",
"name": "Maria Silva",
"metadata": { "plano": "pro", "mrr": 199, "origem": "google_ads" }
},
"membership": {
"id": "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
"list_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "subscribed",
"consent_source": "formulário de newsletter do rodapé do site"
},
"created": true
}

Repetir o mesmo e-mail com o mesmo status na mesma lista não duplica nada: a resposta vem 200 OK com "created": false. Mesmo nessa resposta, um name preenchido atualiza o nome e metadata é mesclado ao contato. O campo created descreve se a associação mudou, não se o contato nasceu: confirmar pending como subscribed devolve 201 e created: true, embora reutilize a mesma associação.

O metadata é mesclado, nunca substituído: mandar {"plano": "enterprise"} numa segunda chamada troca só o plano e preserva os outros campos.

name: null, string vazia e metadata: {} não apagam valores existentes. Para manter a chamada realmente idempotente, envie sempre o mesmo nome, metadata, status e origem de consentimento para o mesmo evento externo.

Os campos que você envia ficam disponíveis nas automações como {{contact.metadata.campo}}.

Regras do objeto:

  • Objeto plano. Valores só podem ser texto, número, booleano ou null — nada de objeto aninhado ou array.
  • Chaves em [A-Za-z0-9_], até 64 caracteres. valor_total funciona; valor-total é recusado com 400, porque a interpolação {{...}} não alcança chave com hífen — o campo existiria e nunca seria substituído.
  • No máximo 30 chaves e 8 KB no total.

Campanhas de e-mail não aceitam contact.metadata.* como personalização. O catálogo de campanhas é fechado em {{contact.first_name}}, {{contact.name}} e {{contact.email}}; uma tag diferente bloqueia o agendamento. Se precisar usar metadata num fluxo, faça isso em uma automação.

Com "status": "pending", o contato entra na lista sem receber campanha e sem disparar a automação. Quando a pessoa confirmar, chame o mesmo endpoint sem o status (ou com subscribed): a associação passa a subscribed e é nesse momento que a automação dispara.

StatusCódigoQuando acontece
400invalid_requestlistId, JSON, corpo, email, name, consent_source, metadata ou status inválido.
404not_foundA lista não existe nesta organização.
409conflictO endereço está na lista de supressão da organização (bounce definitivo ou reclamação de spam), ou o contato já descadastrou desta lista.
500internal_errorFalha inesperada ao criar/atualizar o contato ou a associação. A operação pode ter sido parcial; repita com os mesmos dados.

Lista os membros, do mais recente para o mais antigo.

Parâmetros de query

NomeTipoPadrãoDescrição
statusstringFiltra por subscribed, unsubscribed ou pending.
limitinteger50Máximo de 100.
offsetinteger0Deslocamento para paginar.

Esta listagem também não traz total nem cursor. Use inteiros não negativos, avance o offset pelo número de itens recebidos e pare quando o lote vier menor que o limit.

Terminal window
curl -X GET "https://api.squados.io/v1/lists/3fa85f64-5717-4562-b3fc-2c963f66afa6/contacts?status=subscribed&limit=100" \
-H "Authorization: Bearer pk_sua_chave_aqui"

Resposta — 200 OK

{
"contacts": [
{
"membership_id": "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
"status": "subscribed",
"consent_source": "formulário de newsletter do rodapé do site",
"subscribed_at": "2026-08-20T14:02:00Z",
"unsubscribed_at": null,
"contact_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"email": "[email protected]",
"name": "Maria Silva",
"metadata": { "plano": "pro", "mrr": 199 }
}
],
"limit": 50,
"offset": 0
}

O contact_id é o mesmo identificador usado pelos endpoints de tags e pelo painel de contato.

Além dos erros globais, este endpoint devolve 400 invalid_request para listId ou status inválido, 404 not_found para lista indisponível ao token e 500 internal_error quando a consulta dos membros falha.


DELETE /lists/{listId}/contacts/{contactId}

Section titled “DELETE /lists/{listId}/contacts/{contactId}”

Descadastra o contato da lista.

Terminal window
curl -X DELETE "https://api.squados.io/v1/lists/3fa85f64-.../contacts/7c9e6679-..." \
-H "Authorization: Bearer pk_sua_chave_aqui"

Resposta — 200 OK

{ "membership_id": "8a1b2c3d-...", "status": "unsubscribed", "changed": true }

A associação passa a unsubscribed e a trilha de consentimento é preservada — a linha não é apagada. Chamar de novo devolve 200 com "changed": false. O contato continua existindo na organização, com as conversas e tags dele; sai apenas desta lista.

listId ou contactId inválido devolve 400 invalid_request; lista ou associação inexistente devolve 404 not_found; falha ao persistir o descadastro devolve 500 internal_error. O endpoint aceita membros subscribed e pending: nos dois casos o estado final é unsubscribed.


Disparar automação quando o contato entra

Section titled “Disparar automação quando o contato entra”

Esta é a razão de existir do endpoint. No editor de automações, use o gatilho “Contato adicionado à lista”:

  1. Escolha a lista (deixe vazio para valer para qualquer lista da organização).
  2. Monte o fluxo. Desde o primeiro passo você tem:
    • {{contact.first_name}}, {{contact.display_name}}, {{contact.identity_value}} (o e-mail) e {{contact.metadata.campo}} — os campos que você mandou no POST;
    • {{trigger.payload.list_name}}, {{trigger.payload.list_id}}, {{trigger.payload.consent_source}} e {{trigger.payload.member_id}}.
  3. Publique e ligue a automação.

A partir daí, uma associação nova em subscribed ou a transição de pending para subscribed tenta colocar um run na fila de cada automação ativa e publicada cujo gatilho corresponda à lista. Não disparam: entrada em pending, chamada que já encontra o mesmo status e descadastro. A resposta da API confirma a associação; ela não traz run_id nem confirma que a automação terminou.