API de Contatos
Um contato é uma pessoa individual com quem você troca mensagens — seu nome, número de telefone, e-mail, canal, tags, campos personalizados e as listas e campanhas às quais pertencem. A API de Contatos permite que você crie contatos, pesquise-os, atualize-os, adicione tags, importe-os em massa e remova-os, tudo sem usar o painel de controle.
Todos os caminhos nesta página são relativos à URL base:
https://api.youraiconnector.com/v1
Portanto, /contacts significa https://api.youraiconnector.com/v1/contacts.
Novo na API? Leia Acesso à API primeiro — ele aborda como gerar sua chave de API, as três formas de autenticação, limites de taxa e o formato de erro. Tudo nesta página pressupõe que você já tenha uma chave de API funcional.
Sobre IDs de contato
Cada contato possui um ID exclusivo. O ID que você recebe ao criar um contato (em data.contactId) é o mesmo ID que você usa em todos os outros lugares — para buscar, atualizar, adicionar tags, enviar uma mensagem ou excluir esse contato. Salve-o uma vez e reutilize-o.
Você não precisa criar um contato para obter seu ID. Você também pode pesquisar um por número de telefone ou e-mail (veja Obter um contato), ou percorrer todos os seus contatos (veja Listar contatos). Cada um deles retorna o mesmo ID.
Criar um contato
POST /contacts
Adiciona um novo contato à sua conta. Um número de telefone com código do país é obrigatório — apenas um e-mail não é suficiente. Todo o resto é opcional.
Você pode, opcionalmente, inserir o novo contato diretamente em uma ou mais listas com listId (uma única lista) ou listIds (uma matriz). Se ambos forem enviados, listIds prevalece.
Qualquer campo que você enviar que não seja um dos campos de criação padrão listados na tabela de campos Criar um contato abaixo (phoneNumber, firstName, lastName, email, channel, is_bot_active, is_private, lead_profile, listId, listIds, custom_fields) é armazenado automaticamente como um campo personalizado — portanto, um payload simples de uma ferramenta como Make ou Zapier funciona sem aninhamento. Você também pode passar um objeto custom_fields explícito.
| Campo | Obrigatório | Descrição |
|---|---|---|
phoneNumber |
Sim | O número de telefone do contato, com código do país (por exemplo, +15551234567). |
firstName |
Não | Primeiro nome. |
lastName |
Não | Sobrenome. |
email |
Não | Endereço de e-mail. |
channel |
Não | Canal de mensagens. Um entre whatsapp, sms, whatsapp_web. O padrão é whatsapp. |
is_bot_active |
Não | Se o assistente de IA responde a este contato. O padrão é true. |
is_private |
Não | Marcar o contato como privado. Quando true, o assistente de IA é desativado para ele. O padrão é false. |
lead_profile |
Não | Notas de texto livre sobre o lead. |
listId |
Não | Um único ID de lista para adicionar o contato. |
listIds |
Não | Uma matriz de IDs de lista para adicionar o contato (tem precedência sobre listId). |
custom_fields |
Não | Um objeto com seus próprios campos de chave/valor. Você também pode passá-los como chaves de nível superior. |
cURL
curl -X POST "https://api.youraiconnector.com/v1/contacts?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "+15551234567",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@example.com",
"is_bot_active": true,
"listIds": ["list123", "list456"]
}'
JavaScript
const res = await fetch("https://api.youraiconnector.com/v1/contacts", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
phoneNumber: "+15551234567",
firstName: "Jane",
lastName: "Smith",
email: "jane@example.com",
is_bot_active: true,
listIds: ["list123", "list456"],
}),
});
const data = await res.json();
console.log(data.data.contactId);
Python
import requests
res = requests.post(
"https://api.youraiconnector.com/v1/contacts",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"phoneNumber": "+15551234567",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@example.com",
"is_bot_active": True,
"listIds": ["list123", "list456"],
},
)
print(res.json()["data"]["contactId"])
Resposta
{
"success": true,
"data": {
"message": "Successfully created new contact",
"contactId": "contact_abc123",
"listsAdded": ["list123", "list456"]
}
}
O ID do novo contato está em data.contactId. As listas às quais ele foi adicionado são retornadas em data.listsAdded.
Duplicatas não são criadas. Se um contato com o mesmo número de telefone já existir, a chamada de criação não o cria nem o retorna. A resposta retorna com status HTTP
200e umerror_codede409no corpo, portanto, crie uma ramificação baseada emerror_codeem vez do status HTTP:{ "success": false, "error_code": 409, "error": "A contact with this phone number already exists for the current user." }Para trabalhar com um contato existente após um
error_codede409, procure-o com Obter um contato por telefone ou e-mail —GET /contacts?phoneNumber=...— e reutilize o ID retornado.
Grafias equivalentes do WhatsApp contam como o mesmo número. Alguns países possuem duas grafias válidas para a mesma linha móvel e o WhatsApp pode informar qualquer uma delas: México (
+52…e o legado+521…), Brasil (com ou sem o nono dígito) e Argentina (com ou sem o9após o+54). A verificação de duplicatas na criação e a correspondênciaGET /contacts?phoneNumber=funcionam em ambas as grafias, portanto, você recebe o contato existente de volta, independentemente da forma que enviar. Ophone_numberarmazenado no contato nunca é reescrito.
Obter um contato por telefone ou e-mail
GET /contacts?phoneNumber=... ou GET /contacts?email=...
Pesquisa um único contato e retorna o objeto de contato completo e enriquecido — incluindo suas listas, tags e campanhas resolvidas em pares { id, name }, além da última mensagem trocada.
Passe ou phoneNumber (em formato internacional) ou email. Se você não passar nenhum dos dois, este mesmo endpoint alterna para o modo Listar contatos.
cURL
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts?phoneNumber=%2B15551234567&apiKey=YOUR_API_KEY"
JavaScript
const phone = encodeURIComponent("+15551234567");
const res = await fetch(`https://api.youraiconnector.com/v1/contacts?phoneNumber=${phone}`, {
headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.contact);
Python
import requests
res = requests.get(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts",
headers={"X-API-Key": "YOUR_API_KEY"},
params={"phoneNumber": "+15551234567"},
)
print(res.json()["contact"])
Resposta
{
"success": true,
"contactId": "contact_abc123",
"contact": {
"id": "contact_abc123",
"firstName": "Jane",
"lastName": "Smith",
"email": "jane@example.com",
"phoneNumber": "+15551234567",
"channel": "whatsapp",
"isBotActive": true,
"isPrivate": false,
"doNotDisturb": false,
"lead_profile": null,
"avatarUrl": "https://example.com/photo.jpg",
"customFields": {},
"lists": [{ "id": "list123", "name": "VIP customers" }],
"tags": [{ "id": "tagHotLead", "name": "Hot lead" }],
"campaigns": [{ "id": "campaign789", "name": "Spring promo" }],
"currentCampaign": { "id": "campaign789", "name": "Spring promo" },
"lastMessage": {
"direction": "inbound",
"body": "Sounds good, thanks!",
"status": "received",
"timestamp": "2026-06-09T10:21:00.000Z"
}
}
}
O ID do contato é retornado tanto no nível superior (contactId) quanto dentro do objeto (contact.id). Se nada for encontrado, você recebe um 404 com { "success": false, "message": "Contact not found" }.
avatarUrlé a foto de perfil do contato, obtida do WhatsApp ou da Meta quando eles enviam uma mensagem para você. Ela é somente leitura: você não pode defini-la, e ela énullpara contatos que não possuem foto ou que entram em contato por um canal que não compartilha uma. Trate o link como temporário em vez de armazená-lo, já que alguns desses links de fotos expiram e são atualizados automaticamente. (No endpoint de lista abaixo, o mesmo valor é chamado deavatar_url.)
Números de telefone em URLs. Um sinal de
+em uma string de consulta deve ser codificado em URL como%2B, caso contrário, ele será lido como um espaço. Os exemplos acima fazem isso para você.
Obter um contato por ID
GET /contacts/{contactId}
Quando você já tiver o ID de um contato, busque-o diretamente. O formato da resposta é idêntico ao da consulta acima.
cURL
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123?apiKey=YOUR_API_KEY"
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123", {
headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.contact);
Python
import requests
res = requests.get(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123",
headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["contact"])
Um ID de contato que não existe em sua conta retorna um 404.
Obter estatísticas de contato
GET /contacts/{contactId}/stats
Retorna estatísticas agregadas de mensagens para um contato: totais, respostas de IA versus humanas, créditos gastos e carimbos de data/hora da primeira e última mensagem.
cURL
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/stats?apiKey=YOUR_API_KEY"
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/stats", {
headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.totalMessages, data.creditsUsed);
Python
import requests
res = requests.get(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/stats",
headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["totalMessages"], data["creditsUsed"])
Resposta
{
"success": true,
"totalMessages": 48,
"sent": 21,
"received": 27,
"aiReplies": 18,
"humanReplies": 3,
"creditsUsed": 34,
"botMessageCount": 18,
"firstMessageAt": "2026-05-01T09:00:00.000Z",
"lastMessageAt": "2026-06-09T10:21:00.000Z"
}
botMessageCount é o mesmo contador de mensagens de IA que o botão “resetar” no aplicativo para um contato zera. creditsUsed é o total de créditos acumulados para este contato, não apenas os números desta resposta. Um ID de contato que não existe na sua conta retorna um 404.
Listar contatos
GET /contacts
Chame GET /contacts sem phoneNumber nem email para percorrer todos os seus contatos, do mais recente para o mais antigo. Cada página retorna resumos compactos de contatos (listas, tags e campanhas retornam como arrays de IDs em vez de objetos completos) e um next_cursor.
| Parâmetro de consulta | Descrição |
|---|---|
limit |
Tamanho da página. O padrão é 50, máximo de 100. |
cursor |
O valor next_cursor da página anterior. Omitir na primeira página. |
listId |
Opcional. Retorna apenas contatos que pertencem a esta lista. |
Para percorrer todas as páginas: faça a primeira chamada sem um cursor e, em seguida, continue passando o next_cursor retornado como cursor. Pare quando next_cursor for null — isso significa que não há mais resultados.
cURL
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts?limit=50&apiKey=YOUR_API_KEY"
# next page:
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts?limit=50&cursor=contact_abc123&apiKey=YOUR_API_KEY"
JavaScript
async function listAllContacts() {
const all = [];
let cursor = null;
do {
const url = new URL("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, { headers: { "X-API-Key": "YOUR_API_KEY" } });
const data = await res.json();
all.push(...data.contacts);
cursor = data.next_cursor;
} while (cursor);
return all;
}
Python
import requests
def list_all_contacts():
all_contacts = []
cursor = None
while True:
params = {"limit": 100}
if cursor:
params["cursor"] = cursor
res = requests.get(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts",
headers={"X-API-Key": "YOUR_API_KEY"},
params=params,
)
data = res.json()
all_contacts.extend(data["contacts"])
cursor = data["next_cursor"]
if not cursor:
break
return all_contacts
Resposta
{
"success": true,
"contacts": [
{
"id": "contact_abc123",
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"phone_number": "+15551234567",
"channel": "whatsapp",
"is_bot_active": true,
"is_private": false,
"do_not_disturb": false,
"avatar_url": "https://example.com/photo.jpg",
"custom_fields": {},
"created_at": "2026-06-01T09:00:00.000Z",
"list_ids": ["list123"],
"tag_ids": ["tagHotLead"],
"campaign_ids": ["campaign789"],
"current_campaign_id": "campaign789"
}
],
"next_cursor": "contact_abc123"
}
Nota: Filtrar por um listId que não existe em sua conta retorna um 404. Um cursor inválido retorna um 400.
Contar contatos
GET /contacts/count
Retorna quantos contatos correspondem a um filtro, além de uma divisão por canal, sem precisar paginar por eles. Esta é a chamada correta para qualquer pergunta do tipo “quantos” — um bloco de painel, uma automação ou uma pergunta ao Champ. Todos os filtros são opcionais, e combinar vários deles restringe a contagem (um contato precisa corresponder a todos os que você enviar).
| Parâmetro de consulta | Descrição |
|---|---|
agentId |
Apenas contatos atribuídos a este agente de IA. Passe none para contatos sem agente atribuído (aqueles que são respondidos pelo agente padrão do canal). |
channel |
Apenas contatos neste canal, por exemplo, whatsapp, messenger, instagram, sms, email, chat_widget. |
tag |
Apenas contatos com esta tag, pelo nome da tag (maiúsculas/minúsculas não importam). Um nome de tag que você não possui retorna um 404. |
listId |
Apenas contatos nesta lista. |
botActive |
true ou false — apenas contatos cujo assistente de IA está ligado ou desligado. |
status |
Apenas contatos com este status, por exemplo, Lead. |
rules |
Um objeto JSON de regras codificado em URL, usando o mesmo formato de uma lista inteligente (veja O formato smart_rules mais abaixo). Não pode ser combinado com os outros filtros. |
Envie nenhum filtro e você obterá o número total de contatos em sua conta.
cURL
# everything
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/count?apiKey=YOUR_API_KEY"
# only the contacts one agent handles on Messenger
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/count?agentId=agent_xyz789&channel=messenger&apiKey=YOUR_API_KEY"
JavaScript
const url = new URL("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/count");
url.searchParams.set("agentId", "agent_xyz789");
url.searchParams.set("channel", "messenger");
const res = await fetch(url, { headers: { "X-API-Key": "YOUR_API_KEY" } });
const data = await res.json();
console.log(data.total);
Python
import requests
res = requests.get(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/count",
headers={"X-API-Key": "YOUR_API_KEY"},
params={"agentId": "agent_xyz789", "channel": "messenger"},
)
data = res.json()
print(data["total"])
Resposta
{
"success": true,
"total": 3423,
"by_channel": { "messenger": 2744, "instagram": 667, "none": 12 },
"filters": { "agentId": "agent_xyz789" }
}
by_channel divide o mesmo total por canal; contatos que não estão em nenhum canal são contados em none. filters ecoa os filtros que foram aplicados, para que você possa verificar se a chamada fez o que você pretendia.
Nota: Enviar rules junto com qualquer outro filtro, ou um valor rules que não seja um JSON válido, retorna um 400. Um nome de tag ou ID de lista que não existe em sua conta retorna um 404.
Atualizar um contato
PUT /contacts/{contactId}
Atualiza um contato existente. Apenas os campos que você incluir serão alterados — omita qualquer coisa que não queira modificar. Você deve enviar pelo menos um campo, ou receberá um 400 (“Nenhum campo para atualizar”).
| Campo | Descrição |
|---|---|
firstName |
Primeiro nome. |
lastName |
Sobrenome. |
email |
Endereço de e-mail. |
is_bot_active |
Se o assistente de IA responde a este contato. |
is_private |
Marcar como privado. Definir isto como true também desativa o assistente de IA. |
do_not_disturb |
Pausar o alcance automatizado para este contato. Também impede que a IA responda. |
follow_ups_disabled |
Parar todos os acompanhamentos automatizados para este contato (rápido, ciclo e lead frio) enquanto a IA continua respondendo às mensagens que eles enviam. Útil quando alguém já comprou. Permanece desativado até que você defina novamente como false. |
lead_profile |
Notas de lead em texto livre. |
custom_fields |
Um objeto de campos personalizados. Mesclado por chave — apenas as chaves que você enviar serão gravadas, o restante dos campos personalizados existentes será mantido. Você também pode passar chaves de campos personalizados no nível superior. |
cURL
curl -X PUT "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "firstName": "Jane", "do_not_disturb": true }'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123", {
method: "PUT",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ firstName: "Jane", do_not_disturb: true }),
});
const data = await res.json();
console.log(data.message);
Python
import requests
res = requests.put(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"firstName": "Jane", "do_not_disturb": True},
)
print(res.json()["message"])
Resposta
{
"success": true,
"message": "Contact updated successfully"
}
Campos personalizados são mesclados, não substituídos. Enviar
{ "custom_fields": { "tier": "gold" } }apenas definetier— quaisquer outros campos personalizados no contato permanecem exatamente como estavam. Para remover um campo personalizado inteiramente de todos os contatos, use Excluir um campo personalizado.
Adicionar ou remover tags
POST /contacts/{contactId}/tags
Adiciona e/ou remove tags de um único contato em uma única chamada. Passe os IDs das tags em addTagIds e removeTagIds. Pelo menos um dos dois deve estar preenchido.
As tags já devem existir na sua conta — crie-as primeiro através do endpoint de tags. Se o contato ou qualquer tag referenciada não existir, você receberá um 404.
| Campo | Descrição |
|---|---|
addTagIds |
Matriz de IDs de tags para adicionar ao contato. |
removeTagIds |
Matriz de IDs de tags para remover do contato. |
cURL
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/tags?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "addTagIds": ["tagHotLead"], "removeTagIds": ["tagColdLead"] }'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/tags", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
addTagIds: ["tagHotLead"],
removeTagIds: ["tagColdLead"],
}),
});
const data = await res.json();
console.log(data.added, data.removed);
Python
import requests
res = requests.post(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/tags",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"addTagIds": ["tagHotLead"], "removeTagIds": ["tagColdLead"]},
)
data = res.json()
print(data["added"], data["removed"])
Resposta
{
"success": true,
"contact_id": "contact_abc123",
"added": 1,
"removed": 1
}
Gerencie sua biblioteca de tags
Estes endpoints gerenciam a tag em si — renomeando-a ou excluindo-a da sua conta — ao contrário de aplicar ou remover uma tag em um contato (veja Adicionar ou remover tags acima). Cada tag na sua conta possui um ID (tagId): aquele exibido no gerenciador de tags do seu painel, e aquele retornado como data.tag_id quando você cria uma tag com POST /tags e um corpo JSON de { "name": "..." } (sem phoneNumber, email ou contactId).
Atualizar uma tag
PUT /tags/{tagId}
Envie apenas os campos que você está alterando.
| Campo | Descrição |
|---|---|
name |
O nome da tag. |
curl -X PUT "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/tags/tagHotLead?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Hot lead (Q3)" }'
Resposta
{ "success": true, "tag_id": "tagHotLead" }
Um tagId que não existe na sua conta retorna um 404.
Excluir uma tag
DELETE /tags/{tagId}
Exclui uma tag por ID. Isso não pode ser desfeito — contatos que possuem a tag simplesmente a perdem. Excluir uma tag que já foi removida (ou que nunca existiu) retorna 200 com deleted: 0 em vez de um 404, já que não há nada para enumerar.
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/tags/tagColdLead?apiKey=YOUR_API_KEY"
Resposta
{ "success": true, "deleted": 1 }
Excluir várias tags de uma vez
DELETE /tags
| Campo | Descrição |
|---|---|
tagIds |
Matriz de IDs de tags a serem excluídas (máx. 1000). |
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/tags?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "tagIds": ["tagColdLead", "tagUnsubscribed"] }'
Resposta
{ "success": true, "deleted": 2 }
IDs que não existem ou pertencem a outra conta são ignorados silenciosamente e não contados em deleted.
Definir sinalizador em massa
POST /contacts/bulk-flag
Define um sinalizador booleano em vários contatos de uma só vez. Até 500 IDs de contato por solicitação. IDs que não existem na sua conta são ignorados e contados em skipped.
| Campo | Descrição |
|---|---|
contactIds |
Matriz de IDs de contato para atualizar (máx. 500). |
field |
Qual sinalizador definir. Um de bot_active (assistente de IA ligado/desligado), dnd (pausar alcance automatizado), spam, private. |
value |
O valor booleano para definir o sinalizador. |
cURL
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-flag?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contactIds": ["contactId1", "contactId2"],
"field": "bot_active",
"value": false
}'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-flag", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
contactIds: ["contactId1", "contactId2"],
field: "bot_active",
value: false,
}),
});
const data = await res.json();
console.log(data.updated, data.skipped);
Python
import requests
res = requests.post(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-flag",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"contactIds": ["contactId1", "contactId2"],
"field": "bot_active",
"value": False,
},
)
data = res.json()
print(data["updated"], data["skipped"])
Resposta
{
"success": true,
"updated": 2,
"skipped": 0
}
Importar contatos em massa
POST /contacts/import
Cria até 500 contatos em uma única chamada a partir de um array JSON. Cada registro precisa de um phone_number em formato internacional; todo o resto é opcional. Registros com números de telefone inválidos ou canais não suportados são ignorados (não criados), e cada registro ignorado é relatado com seu índice e motivo — para que você possa corrigir apenas as falhas e tentar novamente.
Números de telefone que já existem em sua conta são ignorados como duplicate por padrão. Envie updateExisting: true para atualizar esses contatos: os campos presentes no registro sobrescrevem os do contato (first_name, last_name, email, lead_profile e custom_fields mesclados chave por chave), tags são adicionados e o contato é adicionado à listId. Canal, número de telefone e sinalizadores de bot nunca são alterados em um contato existente.
Você pode, opcionalmente, adicionar cada contato importado (ou atualizado) a uma lista com listId, definir um defaultChannel para registros que não especificam um, e marcar registros com tags (nomes de tags — tags ausentes são criadas, as existentes são correspondidas sem diferenciar maiúsculas de minúsculas).
Campos de nível superior
| Campo | Obrigatório | Descrição |
|---|---|---|
contacts |
Sim | Array de registros de contato (máx. 500). |
listId |
Não | Lista para adicionar cada contato importado (e atualizado). Deve ser uma lista em sua conta. |
defaultChannel |
Não | Canal aplicado a registros que omitem channel. Um entre whatsapp, sms, whatsapp_web. O padrão é whatsapp. |
updateExisting |
Não | true para atualizar contatos cujo número de telefone já existe, em vez de ignorá-los como duplicate. O padrão é false. |
Campos por registro
| Campo | Obrigatório | Descrição |
|---|---|---|
phone_number |
Sim | Número de telefone em formato internacional (um + inicial é adicionado se estiver faltando). |
first_name |
Não | Primeiro nome. |
last_name |
Não | Sobrenome. |
email |
Não | Endereço de e-mail. |
channel |
Não | Um entre whatsapp, sms, whatsapp_web. Recai sobre defaultChannel. |
is_bot_active |
Não | Se o assistente de IA responde. O padrão é true. |
is_private |
Não | Marcar como privado. O padrão é false. |
lead_profile |
Não | Notas de lead em texto livre. |
custom_fields |
Não | Objeto de chaves e valores de campos personalizados. |
tags |
Não | Array de nomes de tags (uma única string "a; b" também funciona). Tags que não existem são criadas; as existentes são correspondidas ignorando maiúsculas/minúsculas. Máx. 25 por registro. |
cURL
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{ "phone_number": "+12025551234", "first_name": "Ann", "last_name": "Lee", "tags": ["vip", "newsletter"] },
{ "phone_number": "+12025551235", "first_name": "Bob" }
],
"listId": "list123",
"defaultChannel": "whatsapp_web",
"updateExisting": true
}'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
contacts: [
{ phone_number: "+12025551234", first_name: "Ann", last_name: "Lee", tags: ["vip", "newsletter"] },
{ phone_number: "+12025551235", first_name: "Bob" },
],
listId: "list123",
defaultChannel: "whatsapp_web",
updateExisting: true,
}),
});
const data = await res.json();
console.log(`Imported ${data.imported}, updated ${data.updated}, skipped ${data.skipped.length}`);
Python
import requests
res = requests.post(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"contacts": [
{"phone_number": "+12025551234", "first_name": "Ann", "last_name": "Lee", "tags": ["vip", "newsletter"]},
{"phone_number": "+12025551235", "first_name": "Bob"},
],
"listId": "list123",
"defaultChannel": "whatsapp_web",
"updateExisting": True,
},
)
data = res.json()
print(f"Imported {data['imported']}, updated {data['updated']}, skipped {len(data['skipped'])}")
Resposta
{
"success": true,
"imported": 2,
"contact_ids": ["contact_abc123", "contact_def456"],
"updated": 0,
"updated_contact_ids": [],
"skipped": []
}
Se alguns registros não puderem ser criados, eles aparecerão em skipped com o motivo (aqui sem updateExisting, portanto o número existente é ignorado):
{
"success": true,
"imported": 1,
"contact_ids": ["contact_abc123"],
"updated": 0,
"updated_contact_ids": [],
"skipped": [
{ "index": 1, "phone_number": "+12025551235", "reason": "duplicate" }
]
}
Com updateExisting: true, a mesma solicitação relata o contato existente em updated / updated_contact_ids.
Possíveis motivos para ignorar: invalid_record, missing_phone_number, invalid_phone_number, invalid_channel, duplicate_in_request, duplicate, contact_limit_reached, create_failed.
Limites do plano. Se o limite de contatos do seu plano não permitir essa quantidade de novos contatos, toda a solicitação será rejeitada antecipadamente com um
403. Se o limite for atingido durante o processo, os registros restantes retornarão como ignorados com o motivocontact_limit_reached.
Importar contatos de um arquivo CSV
Para importações maiores do que o bulk import suporta (até aproximadamente 50.000 linhas), enfileire um trabalho de importação assíncrono para um arquivo CSV que já esteja no armazenamento da sua conta e, em seguida, faça a sondagem (polling) até que ele seja concluído.
Iniciar a importação
POST /contacts/import-csv
| Campo | Obrigatório | Descrição |
|---|---|---|
csvStoragePath |
Sim | Caminho de armazenamento do arquivo CSV, em users/{your account id}/imports/, terminando em .csv. |
listName |
Sim | Cria (ou reutiliza) uma lista com este nome e adiciona todos os contatos importados a ela. |
existingListRefs |
Não | Matriz de IDs de listas existentes para as quais também adicionar todos os contatos importados. |
defaultChannel |
Não | Canal aplicado às linhas que não especificam um. |
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import-csv?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"csvStoragePath": "users/abc123/imports/leads.csv",
"listName": "Webinar signups"
}'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import-csv", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
csvStoragePath: "users/abc123/imports/leads.csv",
listName: "Webinar signups",
}),
});
const data = await res.json();
console.log(data.job_id);
Python
import requests
res = requests.post(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import-csv",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"csvStoragePath": "users/abc123/imports/leads.csv",
"listName": "Webinar signups",
},
)
job_id = res.json()["job_id"]
Resposta (202 — a importação está na fila, ainda não foi concluída)
{
"success": true,
"job_id": "csvimp_abc123",
"status": "queued"
}
Colocando o arquivo no armazenamento. Este endpoint inicia e rastreia o trabalho de importação; ele não aceita um upload diretamente. O arquivo CSV precisa já estar em
csvStoragePathantes de você chamá-lo — o próprio importador de CSV do painel faz isso como seu primeiro passo.
Consultar o trabalho de importação
GET /contacts/import-csv/{jobId}
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import-csv/csvimp_abc123?apiKey=YOUR_API_KEY"
Resposta
{
"success": true,
"job_id": "csvimp_abc123",
"status": "completed",
"imported": 812,
"updated": 0,
"skipped": 14,
"errors": [],
"error_message": null
}
status passa por queued → processing → completed, ou failed com o motivo em error_message. Um jobId que não existe na sua conta retorna um 404.
Exportar contatos
Inicia uma exportação CSV assíncrona dos seus contatos e retorna um trabalho que você deve sondar para verificar a conclusão.
Iniciar a exportação
POST /contacts/export
| Campo | Obrigatório | Descrição |
|---|---|---|
listId |
Não | Exporta apenas os contatos que pertencem a esta lista. |
contactIds |
Não | Exporta apenas estes IDs de contato específicos. |
Deixar ambos em branco exporta todos os contatos da sua conta.
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "listId": "list123" }'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ listId: "list123" }),
});
const data = await res.json();
console.log(data.job_id);
Python
import requests
res = requests.post(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"listId": "list123"},
)
job_id = res.json()["job_id"]
Resposta (202 — a exportação está na fila)
{
"success": true,
"job_id": "export_abc123",
"status": "queued"
}
Verificar o status do trabalho de exportação
GET /contacts/export/{jobId}
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export/export_abc123?apiKey=YOUR_API_KEY"
Resposta
{
"success": true,
"job_id": "export_abc123",
"status": "completed",
"export_id": "exp_xyz789",
"contact_count": 812,
"error_message": null
}
Assim que
statusestiver"completed", você receberáexport_idecontact_count. O download do arquivo CSV gerado é feito na página de Exportações do seu painel.
Enviar uma mensagem para um contato
POST /contacts/{contactId}/send-message
Envia uma mensagem para um contato existente no canal em que ele já está. A mensagem é colocada na fila e entregue em segundo plano — a resposta confirma que ela foi aceita, não que já foi entregue.
| Campo | Obrigatório | Descrição |
|---|---|---|
body |
Sim | O texto da mensagem a ser enviada. |
mediaUrl |
Não | URL de um arquivo de mídia para anexar. |
mediaContentType |
Não | Tipo MIME da mídia anexada (por exemplo, image/jpeg). |
cURL
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/send-message?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "body": "Hi! Your appointment is confirmed." }'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/send-message", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ body: "Hi! Your appointment is confirmed." }),
});
const data = await res.json();
console.log(data.messageId);
Python
import requests
res = requests.post(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/send-message",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"body": "Hi! Your appointment is confirmed."},
)
print(res.json()["messageId"])
Resposta
{
"success": true,
"messageId": "aB3dE5fG7hI9jK1lM2nO",
"contactId": "contact_abc123",
"channel": "whatsapp",
"message": "Message created successfully. Delivery is being processed."
}
Não consegue enviar agora? Se o contato estiver com o modo não perturbe ou privado ativado, ou não estiver em um canal que possa receber mensagens de saída, a solicitação será rejeitada com um
422e umaerrorexplicativa.
Para enviar por número de telefone, ID do Instagram ou outra identidade de canal em vez de um ID de contato — e para mais informações sobre mensagens em geral — consulte a API de Mensagens.
Atribuir um agente de IA a um contato
POST /contacts/{contactId}/assign-agent
Move uma conversa existente para um agente de IA diferente, a partir da próxima mensagem. É a mesma coisa que Atribuir Agente de IA no menu de um chat, e a mesma etapa que a ação Atribuir agente de IA ou campanha usa em Automações.
| Campo | Obrigatório | Descrição |
|---|---|---|
agentId |
Sim | O ID do agente de IA que deve assumir, ou null para limpar a atribuição para que a conversa volte para a caixa de entrada da sua equipe. |
triggerAIResponse |
Não | true faz com que o agente recém-atribuído responda às últimas mensagens não respondidas do contato imediatamente. O padrão é false. |
Cuidado com
triggerAIResponse: true— ele envia uma mensagem ao contato imediatamente, portanto, use-o apenas quando quiser que eles sejam contatados agora. No Messenger e no Instagram, essa mensagem falha se o contato escreveu para você pela última vez há mais de 24 horas.
cURL
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/assign-agent?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "agentId": "agent_xyz789" }'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/assign-agent", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ agentId: "agent_xyz789" }),
});
const data = await res.json();
console.log(data.data.agentId);
Python
import requests
res = requests.post(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/assign-agent",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"agentId": "agent_xyz789"},
)
print(res.json()["data"]["agentId"])
Resposta
{
"success": true,
"data": {
"contactId": "contact_abc123",
"agentId": "agent_xyz789",
"aiResponseTriggered": false
}
}
O agente deve pertencer à mesma conta que o contato; caso contrário, a solicitação será rejeitada com um
404ou403. Encontre os IDs dos agentes na página Agentes de IA (a URL de cada agente termina com seu ID).
Atribuir um agente de IA a vários contatos
POST /contacts/bulk-assign-agent
Move várias conversas para um agente de IA diferente em uma única chamada — ou limpa a atribuição de todas elas com null. É puramente uma mudança de roteamento: nenhuma mensagem é enviada e o agente não responde a ninguém. Cada contato simplesmente recebe o novo agente na próxima vez que escrever. (É por isso que não há triggerAIResponse aqui.)
| Campo | Obrigatório | Descrição |
|---|---|---|
agentId |
Sim | O agente de IA que deve assumir, ou null para limpar a atribuição. |
contactIds |
Um dos três | Até 500 IDs de contato para mover. |
filter |
Um dos três | Escolha os contatos no servidor em vez de listá-los, do mais recente para o mais antigo. Aceita as mesmas chaves dos filtros do endpoint de contagem: agentId (ou none), channel, tag, listId, botActive, status. |
rules |
Um dos três | Um objeto de regras de lista inteligente — veja O formato smart_rules. |
limit |
Não | Quantos contatos mover nesta chamada ao selecionar com filter ou rules. De 1 a 500, o padrão é 500. |
Envie exatamente um entre contactIds, filter ou rules.
cURL
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-assign-agent?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agentId": "agent_xyz789",
"filter": { "agentId": "agent_abc123", "channel": "messenger" }
}'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-assign-agent", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
agentId: "agent_xyz789",
filter: { agentId: "agent_abc123", channel: "messenger" },
}),
});
const data = await res.json();
console.log(data.updated, data.remaining);
Python
import requests
res = requests.post(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-assign-agent",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"agentId": "agent_xyz789",
"filter": {"agentId": "agent_abc123", "channel": "messenger"},
},
)
data = res.json()
print(data["updated"], data["remaining"])
Resposta
{
"success": true,
"agentId": "agent_xyz789",
"matched": 3415,
"updated": 500,
"skipped": 0,
"remaining": 2915,
"filters": { "agentId": "agent_abc123" }
}
matched é quantos contatos a seleção encontrou no total, updated quantos foram movidos por esta chamada, skipped quantos dos IDs que você enviou não foram encontrados em sua conta, e remaining quantos ainda correspondem agora que esta chamada foi concluída.
Movendo todos. Como uma chamada move no máximo 500 contatos, um grupo grande requer algumas chamadas. Use um filtro que pare de corresponder a um contato assim que ele for movido — por exemplo, filter: { "agentId": "agent_abc123" } ao atribuir a agent_xyz789 — e repita exatamente a mesma chamada até que remaining retorne como 0. Quando você passa contactIds em vez disso, remaining é sempre 0.
Atribuir um contato a um departamento
POST /contacts/{contactId}/department
“Atribuir este lead ao departamento de Vendas” — registra um contato em um departamento nomeado e, por padrão, o encaminha para quem, nesse departamento, tiver menos contatos no momento. Isso é diferente de atribuir um agente de IA: um departamento responde a “qual equipe é responsável por isso”, um agente responde a “qual IA responde a isso”, e definir um nunca limpa o outro.
| Campo | Obrigatório | Descrição |
|---|---|---|
department_id |
Sim | O departamento no qual registrar o contato. Passe null para limpar. |
hand_to_member |
Não | Também encaminha o contato para a pessoa com menos carga de trabalho nesse departamento. O padrão é true. Nunca reatribui um contato que alguém já possua. |
cURL
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/department?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "department_id": "dept_sales" }'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/department", {
method: "POST",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ department_id: "dept_sales" }),
});
const data = await res.json();
console.log(data.assigned_to);
Python
import requests
res = requests.post(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/department",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"department_id": "dept_sales"},
)
print(res.json()["assigned_to"])
Resposta
{
"success": true,
"department_id": "dept_sales",
"assigned_to": "member_uid_123"
}
assigned_to é null quando o contato já pertencia a alguém ou você passou hand_to_member: false.
Vincular um contato entre canais
“Continuar no WhatsApp” (ou SMS) localiza ou cria o contato desta pessoa em outro canal baseado em telefone e vincula os dois, para que o restante do aplicativo os reconheça como a mesma pessoa.
Vincular a outro canal
POST /contacts/{contactId}/link-channel
| Campo | Obrigatório | Descrição |
|---|---|---|
channel |
Sim | O canal ao qual vincular. Um entre whatsapp, whatsapp_web, sms. |
phoneNumber |
Não | Número de telefone a ser usado no novo canal. O padrão é o próprio número do contato de origem. |
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/link-channel?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "channel": "sms" }'
Resposta
{
"success": true,
"data": {
"contact_id": "contact_def456",
"person_id": "person_xyz789",
"created": true
}
}
created informa se um novo contato foi criado para o canal de destino ou se um existente foi encontrado e vinculado. Chamar isso uma segunda vez é seguro — ele retorna o mesmo contact_id com created: false em vez de criar uma duplicata.
Um 422 significa que a conta não pode realizar este vínculo no momento: o contato já está nessa família de canais, não possui número de telefone para usar ou não há remetente conectado para o canal de destino. Um 409 significa que os dois contatos já estão vinculados a duas pessoas diferentes — desvincule um primeiro.
Listar conversas vinculadas de um contato
GET /contacts/{contactId}/linked
Retorna as outras conversas que são a mesma pessoa que este contato. Um contato não vinculado retorna um array vazio, não um 404 — “esta pessoa não tem outros canais” é um estado normal.
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/linked?apiKey=YOUR_API_KEY"
Resposta
{
"success": true,
"data": [
{
"contact_id": "contact_def456",
"channel": "sms",
"custom_channel": null,
"first_name": "Jane",
"last_name": "Smith",
"phone_number": "+15551234567",
"last_message": "Sounds good, thanks!",
"last_message_timestamp": "2026-06-09T10:21:00.000Z",
"linked_from": {
"contact_id": "contact_abc123",
"channel": "whatsapp",
"linked_at": "2026-06-01T09:00:00.000Z",
"reason": "continue_on_channel"
}
}
]
}
Desvincular um contato
DELETE /contacts/{contactId}/link
Remove este contato de sua pessoa, de forma unilateral — quaisquer outros contatos ainda vinculados a essa pessoa mantêm seu vínculo, portanto, desvincular um de três não dissolve o grupo.
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/link?apiKey=YOUR_API_KEY"
Resposta
{ "success": true }
Buscar a foto de perfil de um contato
POST /contacts/{contactId}/profile-pic
Busca (e armazena em cache) a foto de perfil do WhatsApp ou Meta do contato sob demanda — a mesma foto retornada como avatarUrl em Obter um contato, atualizada.
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/profile-pic?apiKey=YOUR_API_KEY"
Resposta
{
"success": true,
"avatar_url": "https://example.com/photo.jpg",
"cached": false
}
cached: true significa que a URL veio de uma busca recente em vez de uma consulta nova ao provedor — as fotos são armazenadas em cache por 7 dias, e um contato que o provedor relata não ter foto acessível é armazenado como indisponível por 24 horas. Quando não há foto para buscar, avatar_url é omitido e message explica o motivo.
Auto-tag de contatos com IA
Executa as regras de tag da sua conta em todo o histórico de conversas de um ou mais contatos e aplica (ou remove) tags exatamente como a marcação em tempo real que ocorre durante um chat ao vivo — mesmas regras, mesmo custo de crédito por tag.
Iniciar uma execução
POST /contacts/auto-tag
| Campo | Obrigatório | Descrição |
|---|---|---|
scope |
Sim | "contacts" para marcar contatos específicos, ou "agent" para marcar todas as conversas atualmente gerenciadas por um agente de IA. |
contact_ids |
Obrigatório quando scope é "contacts" |
Array de IDs de contato, de 1 a 500. |
agent_id |
Obrigatório quando scope é "agent" |
O agente de IA cujas conversas devem ser marcadas. Quando scope é "contacts", isso é opcional e apenas restringe quais regras de tag do agente serão executadas. |
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/auto-tag?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "scope": "contacts", "contact_ids": ["contact_abc123", "contact_def456"] }'
Um único contato é executado em linha e retorna o resultado imediatamente:
{ "success": true, "result": { "tags_applied": 2, "tags_removed": 0 } }
Dois ou mais contatos (ou scope: "agent") são executados como um trabalho em segundo plano e retornam 202 imediatamente:
{ "success": true, "run_id": "m1x2y3-a1b2c3d4", "total": 214 }
Consultar uma execução
GET /contacts/auto-tag/run
Retorna a execução atual (ou mais recente) da conta, para que você possa consultar o progresso sem precisar rastrear o run_id por conta própria.
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/auto-tag/run?apiKey=YOUR_API_KEY"
Resposta
{
"success": true,
"run": {
"run_id": "m1x2y3-a1b2c3d4",
"status": "running",
"total": 214,
"processed": 58,
"tagged_contacts": 12,
"tags_applied": 15,
"tags_removed": 2,
"credits_charged": 15
}
}
run é null quando a conta nunca iniciou uma. status muda de "running" para "completed" ou "failed".
Apenas uma execução em lote pode estar em andamento por conta de cada vez — iniciar uma segunda enquanto outra está em execução retorna 409 com error_code: "auto_tag_run_in_progress". Ficar sem créditos em uma execução de contato único retorna 402 com error_code: "insufficient_credits"; uma execução em lote, em vez disso, para prematuramente e relata até onde chegou em run.
Excluir um contato
DELETE /contacts/{contactId}
Exclui permanentemente um contato por ID, juntamente com seu histórico de mensagens. Isso não pode ser desfeito. Para excluir vários contatos em uma única chamada, use Excluir contatos abaixo.
cURL
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123?apiKey=YOUR_API_KEY"
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123", {
method: "DELETE",
headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.success);
Python
import requests
res = requests.delete(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123",
headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["success"])
Resposta
{
"success": true
}
Um ID de contato que não existe na sua conta, ou que pertence a uma conta diferente, retorna um 404.
Excluir contatos
DELETE /contacts
Exclui permanentemente um ou mais contatos por ID em uma única chamada (até 500 IDs). IDs que não existem na sua conta são ignorados e contados em skipped. Isso não pode ser desfeito.
| Campo | Descrição |
|---|---|
contactIds |
Matriz de IDs de contato para excluir (máx. 500). |
cURL
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "contactIds": ["contactId1", "contactId2"] }'
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts", {
method: "DELETE",
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ contactIds: ["contactId1", "contactId2"] }),
});
const data = await res.json();
console.log(`Deleted ${data.deleted}, skipped ${data.skipped}`);
Python
import requests
res = requests.delete(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"contactIds": ["contactId1", "contactId2"]},
)
data = res.json()
print(f"Deleted {data['deleted']}, skipped {data['skipped']}")
Resposta
{
"success": true,
"deleted": 2,
"skipped": 0
}
Excluir um campo personalizado
DELETE /contacts/custom-fields/{fieldKey}
Remove uma chave de campo personalizado de todos os contatos em sua conta. Use isso para limpar após renomear ou desativar um campo personalizado. A chave pode conter apenas letras, números, sublinhados e hifens. Retorna quantos contatos foram atualizados. Isso não pode ser desfeito.
cURL
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/custom-fields/webinar_date_nh?apiKey=YOUR_API_KEY"
JavaScript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/custom-fields/webinar_date_nh", {
method: "DELETE",
headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(`Removed from ${data.updated} contacts`);
Python
import requests
res = requests.delete(
"<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/custom-fields/webinar_date_nh",
headers={"X-API-Key": "YOUR_API_KEY"},
)
print(f"Removed from {res.json()['updated']} contacts")
Resposta
{
"success": true,
"updated": 42
}
Nota: Uma chave de campo com caracteres não suportados retorna um 400.
Listas
Listas agrupam contatos. Uma lista pode ser estática (você decide quem faz parte dela) ou inteligente (a associação é calculada a partir de regras e mantida atualizada automaticamente — veja Organizando Listas e Contatos).
| Campo | Descrição |
|---|---|
name |
Obrigatório na criação. Até 100 caracteres. |
status |
live (padrão) ou draft. Minúsculo. |
contact_ids |
Matriz de IDs de contato para colocar na lista. Apenas listas estáticas. |
type |
static (padrão) ou smart. |
smart_rules |
O conjunto de regras — obrigatório quando type é smart. Veja abaixo. |
Criar uma lista
POST /lists
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/lists?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Hot leads (active)",
"type": "smart",
"smart_rules": {
"match": "all",
"conditions": [
{ "field": "tags", "op": "has_any", "value": ["tagHotLead"] },
{ "field": "last_activity_at", "op": "within_last", "value": { "amount": 90, "unit": "days" } }
]
}
}'
Resposta
{
"success": true,
"list_id": "list_abc123",
"evaluation": { "added": 3, "removed": 0, "total": 3 }
}
Uma lista inteligente é avaliada inline, na mesma solicitação, portanto evaluation informa exatamente quem acabou nela. Em uma lista estática, evaluation é null.
Atualizar uma lista
PUT /lists/{listId}
Envie apenas os campos que você está alterando. Alterar smart_rules reavalia a lista imediatamente e retorna o mesmo objeto evaluation.
curl -X PUT "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/lists/list_abc123?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "smart_rules": { "match": "any", "conditions": [ { "field": "tags", "op": "has_any", "value": ["tagHotLead", "tagWebinar"] } ] } }'
Você pode alternar uma lista entre os dois tipos:
- Estática → inteligente: envie
{ "type": "smart", "smart_rules": { … } }. As regras assumem o controle imediatamente. - Inteligente → estática: envie
{ "type": "static" }. As regras são descartadas e quem estiver na lista permanece nela.
A estrutura de smart_rules
{
"match": "all",
"conditions": [
{ "field": "tags", "op": "has_any", "value": ["tagHotLead"] },
{ "field": "channel", "op": "is_any", "value": ["whatsapp", "sms"] },
{ "field": "last_incoming_message_at", "op": "not_within_last", "value": { "amount": 7, "unit": "days" } },
{ "field": "created_at", "op": "after", "value": "2026-01-01" },
{ "field": "is_bot_active", "op": "is", "value": true },
{ "field": "email", "op": "is_set" },
{ "field": "custom_field", "key": "Plan", "op": "eq", "value": "pro" }
]
}
match—all(todas as condições devem ser verdadeiras) ouany(pelo menos uma).conditions— 1 a 20 condições, cada uma com no máximo 100 valores, strings de até 200 caracteres.
field |
op |
value |
|---|---|---|
tags |
has_any, has_all, has_none |
matriz de IDs de tag |
lists |
in_any, not_in_any |
matriz de IDs de lista (apenas listas estáticas — uma lista inteligente não pode ser criada a partir de outra lista inteligente) |
channel |
is_any, is_none |
matriz de canais |
status |
is_any, is_none |
matriz de status de contato |
created_at, last_activity_at, last_incoming_message_at, last_outgoing_message_at, first_ai_interaction_at, last_ai_interaction_at |
within_last, not_within_last |
{ "amount": 1–3650, "unit": "hours" | "days" } |
| mesmos campos de data | before, after |
data ISO ("2026-01-01", comparada como dias inteiros) ou data-hora ISO completa ("2026-01-01T14:30:00Z", comparada ao momento exato) |
| mesmos campos de data | is_set, not_set |
— |
has_interacted_with_ai |
is |
true / false — true corresponde a contatos para os quais a IA enviou pelo menos uma mensagem (alguma vez) |
is_bot_active, do_not_disturb, is_private, has_ever_responded |
is |
true / false |
email, phone_number, first_name, last_name |
is_set, not_set, contains, not_contains |
string para os formulários contains |
current_campaign_id, assigned_agent |
is_any, is_none, is_set, not_set |
matriz de IDs para os formulários is_any / is_none |
custom_field (mais um key) |
eq, neq, contains, not_contains, is_set, not_set |
string para os formulários de valor |
not_within_last também corresponde a contatos para os quais a data nunca foi definida (“mais de N atrás, ou nunca”), e as comparações de texto ignoram maiúsculas/minúsculas.
Engajamento da IA. has_interacted_with_ai é o sinalizador de tempo de vida: true para cada contato para o qual sua IA enviou pelo menos uma mensagem, false para todos os outros (incluindo contatos que apenas sua equipe respondeu). Ele é marcado na primeira mensagem da IA para um contato e nunca é limpo, portanto, desativar as respostas da IA do contato ou movê-lo para outra campanha não o redefine. Para um período — “os contatos que minha IA atendeu este mês”, a pergunta de faturamento usual — use o intervalo em last_ai_interaction_at:
{ "field": "last_ai_interaction_at", "op": "within_last", "value": { "amount": 30, "unit": "days" } }
Não confunda nenhum dos dois com is_bot_active (a IA tem permissão para responder, não que ela tenha respondido) ou has_ever_responded (o contato respondeu, para qualquer pessoa). Os mesmos dois selos são retornados em cada contato como first_ai_interaction_at / last_ai_interaction_at, e todo o conjunto de regras também funciona em GET /contacts?rules=, para que você possa contar correspondências sem criar uma lista.
Visualizar um conjunto de regras
POST /lists/preview
Conta e amostra os contatos que um conjunto de regras corresponderia, sem criar ou alterar nada. Use isso para verificar a integridade das regras antes de salvá-las.
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/lists/preview?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "smart_rules": { "match": "all", "conditions": [ { "field": "tags", "op": "has_any", "value": ["tagHotLead"] } ] } }'
Resposta
{
"success": true,
"count": 3,
"sample": [
{
"id": "contact_abc123",
"first_name": "Sofia",
"last_name": "Martinez",
"phone_number": "+31600000000",
"email": "sofia@example.com",
"channel": "whatsapp"
}
]
}
sample mantém até 10 contatos, com os mais recentemente ativos primeiro.
Executar novamente uma lista inteligente agora
POST /lists/{listId}/evaluate
Força uma reavaliação imediata (a mesma coisa que Atualizar agora faz no painel). As listas inteligentes já são atualizadas quando um contato muda e a cada 15 minutos para regras baseadas em tempo, portanto, isso só é necessário quando você deseja o resultado agora mesmo.
Resposta
{
"success": true,
"list_id": "list_abc123",
"evaluation": { "added": 2, "removed": 1, "total": 4 }
}
evaluation.skipped: true significa que outra avaliação da mesma lista já estava em execução e esta chamada não fez nada.
Listas inteligentes recusam membros escolhidos manualmente
Os endpoints de associação retornam 409 com "This is a smart list — its members are computed from its rules. Edit the rules instead." quando a lista de destino é inteligente. Isso cobre POST /contacts/lists, DELETE /contacts/lists, POST /contacts/lists/batch, contact_ids em POST /lists e PUT /lists/{listId}, e a escolha de uma lista inteligente como destino de importação CSV. Altere as regras em vez disso.
Chamar POST /lists/{listId}/evaluate em uma lista estática também é um 409 — ela não tem regras para executar.
Erros da API de Contatos
Os endpoints de contato retornam o envelope de erro padrão:
{
"success": false,
"error": "Contact not found"
}
Alguns endpoints também incluem error_code, que geralmente corresponde ao status HTTP — a única exceção é o caso de contato duplicado abaixo, onde o status HTTP é 200 e apenas error_code carrega o 409. Os códigos específicos para endpoints de contato:
| Código | Quando ocorre em um endpoint de contato |
|---|---|
400 |
Solicitação inválida — um campo ausente/inválido, corpo vazio, cursor incorreto ou mais de 500 IDs em um lote. |
402 |
Créditos insuficientes para concluir uma execução de marcação por IA em um contato (error_code: "insufficient_credits"). |
404 |
O contato, lista ou tag não foi encontrado na sua conta. |
409 |
Um contato com esse número de telefone já existe (ao criar). Retornado como error_code no corpo com um status HTTP de 200, portanto, verifique error_code aqui. Também retornado quando uma execução de marcação automática em massa já está em andamento (error_code: "auto_tag_run_in_progress"), ou quando vincular um contato a outro canal uniria dois contatos já vinculados a duas pessoas diferentes. |
422 |
O contato não pode receber uma mensagem no momento (não perturbe, privado ou canal não suportado). No endpoint de vinculação de canal, também cobre a ausência de número de telefone, um emparelhamento de canal não suportado ou a ausência de um remetente conectado para o canal de destino. |
Um 403 em um endpoint de contato também pode significar um problema de limite de contatos ou permissão de lista, em vez de acesso ao plano. Os códigos compartilhados que todos os endpoints podem retornar — 401, 403 (seu plano não inclui acesso à API), 429 (limite de taxa) e 500 — estão listados com orientações de nova tentativa em Erros e Paginação.
Próximos passos
- API de Mensagens — envie mensagens por identidade de canal e gerencie conversas.
- Referência da API — lista completa de endpoints, incluindo tags e listas.
- Acesso à API — autenticação, limites de taxa e tratamento de erros.