Your AI Connector Docs

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 200 e um error_code de 409 no corpo, portanto, crie uma ramificação baseada em error_code em 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_code de 409, procure-o com Obter um contato por telefone ou e-mailGET /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 o 9 após o +54). A verificação de duplicatas na criação e a correspondência GET /contacts?phoneNumber= funcionam em ambas as grafias, portanto, você recebe o contato existente de volta, independentemente da forma que enviar. O phone_number armazenado 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 é null para 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 de avatar_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 define tier — 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 motivo contact_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 csvStoragePath antes 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 queuedprocessingcompleted, 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 status estiver "completed", você receberá export_id e contact_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 422 e uma error explicativa.

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 404 ou 403. 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" }
  ]
}
  • matchall (todas as condições devem ser verdadeiras) ou any (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 / falsetrue 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