Your AI Connector Docs

API de Contactos

Um contacto é uma pessoa individual com quem comunica — o seu nome, número de telefone, e-mail, canal, etiquetas, campos personalizados e as listas e campanhas a que pertence. A API de Contactos permite-lhe criar contactos, pesquisá-los, atualizá-los, etiquetá-los, importá-los em massa e removê-los, tudo sem utilizar o painel de controlo.

Todos os caminhos nesta página são relativos ao URL base:

https://api.youraiconnector.com/v1

Portanto, /contacts significa https://api.youraiconnector.com/v1/contacts.

Novo na API? Leia primeiro o Acesso à API — este cobre como gerar a sua chave de API, as três formas de autenticação, os limites de taxa e o formato de erro. Tudo nesta página pressupõe que já possui uma chave de API funcional.


Sobre os IDs de contacto

Cada contacto tem um ID único. O ID que recebe quando cria um contacto (em data.contactId) é o mesmo ID que utiliza em qualquer outro lugar — para obter, atualizar, etiquetar, enviar uma mensagem ou eliminar esse contacto. Guarde-o uma vez e reutilize-o.

Não precisa de criar um contacto para obter o seu ID. Também pode pesquisar um pelo número de telefone ou e-mail (consulte Obter um contacto), ou percorrer todos os seus contactos (consulte Listar contactos). Cada um desses métodos devolve o mesmo ID.


Criar um contacto

POST /contacts

Adiciona um novo contacto à sua conta. É obrigatório um número de telefone com código de país — um e-mail por si só não é suficiente. Tudo o resto é opcional.

Pode, opcionalmente, adicionar o novo contacto diretamente a uma ou mais listas com listId (uma única lista) ou listIds (uma matriz). Se ambos forem enviados, listIds tem prioridade.

Qualquer campo que envie que não seja um dos campos de criação padrão listados na tabela de campos Criar um contacto abaixo (phoneNumber, firstName, lastName, email, channel, is_bot_active, is_private, lead_profile, listId, listIds, custom_fields) é automaticamente guardado como um campo personalizado — por isso, um payload simples de uma ferramenta como o Make ou o Zapier funciona sem necessidade de aninhamento. Também pode passar um objeto custom_fields explícito.

Campo Obrigatório Descrição
phoneNumber Sim O número de telefone do contacto, com código de país (por exemplo, +15551234567).
firstName Não Nome próprio.
lastName Não Apelido.
email Não Endereço de e-mail.
channel Não Canal de mensagens. Um dos seguintes: whatsapp, sms, whatsapp_web. O padrão é whatsapp.
is_bot_active Não Se o assistente de IA responde a este contacto. O padrão é true.
is_private Não Marcar o contacto como privado. Quando true, o assistente de IA é desativado para o mesmo. O padrão é false.
lead_profile Não Notas de texto livre sobre o potencial cliente.
listId Não Um ID de lista único para adicionar o contacto.
listIds Não Uma matriz de IDs de lista para adicionar o contacto (tem prioridade sobre listId).
custom_fields Não Um objeto com os seus próprios campos de chave/valor. 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 contacto encontra-se em data.contactId. As listas às quais foi adicionado são devolvidas em data.listsAdded.

Não são criadas duplicatas. Se um contacto com o mesmo número de telefone já existir, a chamada de criação não o cria nem o devolve. A resposta é devolvida com o estado HTTP 200 e um error_code de 409 no corpo, por isso baseie a sua lógica no error_code em vez do estado HTTP:

{ "success": false, "error_code": 409, "error": "A contact with this phone number already exists for the current user." }

Para trabalhar com um contacto existente após um error_code de 409, procure-o com Obter um contacto por telefone ou e-mailGET /contacts?phoneNumber=... — e reutilize o ID que este devolve.

Grafias equivalentes no WhatsApp contam como o mesmo número. Alguns países têm duas grafias válidas para a mesma linha móvel e o WhatsApp pode comunicar 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 duplicados na criação e a correspondência GET /contacts?phoneNumber= funcionam em ambas as grafias, pelo que obtém o contacto existente independentemente da forma que enviar. O phone_number guardado no contacto nunca é reescrito.


Obter um contacto por telefone ou e-mail

GET /contacts?phoneNumber=... ou GET /contacts?email=...

Procura um único contacto e devolve o objeto de contacto completo e enriquecido — incluindo as suas listas, etiquetas e campanhas resolvidas em pares { id, name }, além da última mensagem trocada.

Passe ou phoneNumber (em formato internacional) ou email. Se não passar nenhum, este mesmo endpoint muda para o modo Listar contactos.

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 contacto é devolvido tanto ao nível superior (contactId) como dentro do objeto (contact.id). Se nada corresponder, recebe um 404 com { "success": false, "message": "Contact not found" }.

avatarUrl é a fotografia de perfil do contacto, obtida a partir do WhatsApp ou da Meta quando lhe enviam uma mensagem. É apenas de leitura: não a pode definir e fica null para contactos que não tenham fotografia ou que o contactem através de um canal que não a partilhe. Trate a ligação como temporária em vez de a guardar, uma vez que algumas destas ligações de fotografias expiram e são atualizadas automaticamente. (No endpoint da lista abaixo, o mesmo valor é designado por avatar_url.)

Números de telefone em URLs. Um sinal + numa query string deve ser codificado como URL %2B, caso contrário, é lido como um espaço. Os exemplos acima fazem isto por si.


Obter um contacto por ID

GET /contacts/{contactId}

Quando já tiver o ID de um contacto, obtenha-o diretamente. A estrutura da resposta é idêntica à 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 contacto que não exista na sua conta devolve um 404.


Obter estatísticas de contacto

GET /contacts/{contactId}/stats

Devolve estatísticas agregadas de mensagens para um contacto: totais, respostas de IA vs. 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 “repor” na aplicação, num contacto, coloca a zero. creditsUsed é o total de créditos acumulados para este contacto, não apenas os números desta resposta. Um ID de contacto que não exista na sua conta devolve um 404.


Listar contactos

GET /contacts

Chame GET /contacts sem phoneNumber nem email para percorrer todos os seus contactos, do mais recente para o mais antigo. Cada página devolve resumos compactos dos contactos (as listas, etiquetas e campanhas são devolvidas como matrizes 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. Devolver apenas os contactos que pertencem a esta lista.

Para percorrer todas as páginas: faça a primeira chamada sem um cursor e, em seguida, continue a passar o next_cursor devolvido como cursor. Pare quando next_cursor for null — isso significa que não existem 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 na sua conta devolve um 404. Um cursor inválido devolve um 400.


Contar contactos

GET /contacts/count

Devolve quantos contactos correspondem a um filtro, além de uma divisão por canal, sem necessidade de paginação. Esta é a chamada correta para qualquer pergunta do tipo “quantos” — um elemento de dashboard, uma automatização ou uma pergunta ao Champ. Todos os filtros são opcionais e a combinação de vários reduz a contagem (um contacto tem de corresponder a todos os que enviar).

Parâmetro de consulta Descrição
agentId Apenas contactos atribuídos a este agente de IA. Utilize none para contactos sem agente atribuído (esses são respondidos pelo agente predefinido do canal).
channel Apenas contactos neste canal, p. ex., whatsapp, messenger, instagram, sms, email, chat_widget.
tag Apenas contactos com esta etiqueta, pelo nome da etiqueta (maiúsculas/minúsculas não importam). Um nome de etiqueta que não possua devolve um 404.
listId Apenas contactos nesta lista.
botActive true ou false — apenas contactos cujo assistente de IA está ligado ou desligado.
status Apenas contactos com este estado, p. ex., Lead.
rules Um objeto de regras JSON codificado em URL, usando a mesma forma que uma lista inteligente (ver A forma smart_rules mais abaixo). Não pode ser combinado com os outros filtros.

Se não enviar qualquer filtro, obterá o número total de contactos na 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; os contactos que não estão em nenhum canal são contados em none. filters reflete os filtros que foram aplicados, para que possa verificar se a chamada fez o que pretendia.

Nota: Enviar rules juntamente com qualquer outro filtro, ou um valor rules que não seja JSON válido, devolve um 400. Um nome de etiqueta ou ID de lista que não exista na sua conta devolve um 404.


Atualizar um contacto

PUT /contacts/{contactId}

Atualiza um contacto existente. Apenas os campos que incluir são alterados — omita tudo o que não pretender modificar. Tem de enviar pelo menos um campo, caso contrário receberá um 400 (“No fields to update”).

Campo Descrição
firstName Nome próprio.
lastName Apelido.
email Endereço de e-mail.
is_bot_active Se o assistente de IA responde a este contacto.
is_private Marcar como privado. Definir isto como true também desativa o assistente de IA.
do_not_disturb Pausar o contacto automatizado para este contacto. Também impede a IA de responder.
follow_ups_disabled Parar todos os seguimentos automatizados para este contacto (rápidos, de ciclo e de leads frias) enquanto a IA continua a responder às mensagens que eles enviam. Útil após uma compra. Permanece desativado até que o defina novamente para false.
lead_profile Notas de lead em texto livre.
custom_fields Um objeto de campos personalizados. Fundido por chave — apenas as chaves que enviar são escritas, o resto dos campos personalizados existentes são mantidos. Também pode passar chaves de campos personalizados ao 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"
}

Os campos personalizados são fundidos, não substituídos. Enviar { "custom_fields": { "tier": "gold" } } apenas define tier — quaisquer outros campos personalizados no contacto permanecem exatamente como estavam. Para remover um campo personalizado por completo em todos os contactos, utilize Eliminar um campo personalizado.


Adicionar ou remover etiquetas

POST /contacts/{contactId}/tags

Adiciona e/ou remove etiquetas num único contacto numa única chamada. Passe os IDs das etiquetas em addTagIds e removeTagIds. Pelo menos um dos dois tem de estar preenchido.

As etiquetas têm de existir previamente na sua conta — crie-as primeiro através do endpoint de etiquetas. Se o contacto ou qualquer etiqueta referenciada não existir, receberá um 404.

Campo Descrição
addTagIds Matriz de IDs de etiquetas a adicionar ao contacto.
removeTagIds Matriz de IDs de etiquetas a remover do contacto.

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
}

Gerir a sua biblioteca de etiquetas

Estes endpoints gerem a própria etiqueta — renomeando-a ou eliminando-a na sua conta — ao contrário de aplicar ou remover uma etiqueta num contacto (consulte Adicionar ou remover etiquetas acima). Cada etiqueta na sua conta tem um ID (tagId): aquele que é apresentado no gestor de etiquetas do seu painel de controlo e o que é devolvido como data.tag_id quando cria uma etiqueta com POST /tags e um corpo JSON de { "name": "..." } (sem phoneNumber, email ou contactId).

Atualizar uma etiqueta

PUT /tags/{tagId}

Envie apenas os campos que pretende alterar.

Campo Descrição
name O nome da etiqueta.
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 exista na sua conta devolve um 404.

Eliminar uma etiqueta

DELETE /tags/{tagId}

Elimina uma etiqueta por ID. Isto não pode ser anulado — os contactos que possuem a etiqueta simplesmente perdem-na. Eliminar uma etiqueta que já não existe (ou que nunca existiu) devolve 200 com deleted: 0 em vez de um 404, uma vez 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 }

Eliminar várias etiquetas de uma só vez

DELETE /tags

Campo Descrição
tagIds Matriz de IDs de etiquetas a eliminar (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 }

Os IDs que não existem, ou que pertencem a outra conta, são ignorados silenciosamente e não contam para deleted.


Definir um sinalizador em massa

POST /contacts/bulk-flag

Define um sinalizador booleano em vários contactos de uma só vez. Até 500 IDs de contacto por pedido. Os IDs que não existirem na sua conta serão ignorados e contados em skipped.

Campo Descrição
contactIds Matriz de IDs de contacto a atualizar (máx. 500).
field Que sinalizador definir. Um de bot_active (assistente de IA ligado/desligado), dnd (pausar divulgação automatizada), spam, private.
value O valor booleano para o qual 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 contactos em massa

POST /contacts/import

Cria até 500 contactos numa única chamada a partir de uma matriz JSON. Cada registo necessita de um phone_number em formato internacional; tudo o resto é opcional. Os registos com números de telefone inválidos ou canais não suportados são ignorados (não criados), e cada registo ignorado é reportado com o seu índice e motivo — para que possa corrigir apenas as falhas e tentar novamente.

Os números de telefone que já existem na sua conta são ignorados como duplicate por predefinição. Envie updateExisting: true para atualizar esses contactos: os campos presentes no registo substituem os do contacto (first_name, last_name, email, lead_profile e custom_fields fundidos chave a chave), os tags são adicionados e o contacto é adicionado à listId. O canal, o número de telefone e as flags do bot nunca são alterados num contacto existente.

Pode opcionalmente adicionar cada contacto importado (ou atualizado) a uma lista com listId, definir um defaultChannel para registos que não especifiquem um, e etiquetar registos com tags (nomes das etiquetas — as etiquetas em falta são criadas, as existentes são correspondidas sem distinção entre maiúsculas e minúsculas).

Campos de nível superior

Campo Obrigatório Descrição
contacts Sim Matriz de registos de contactos (máx. 500).
listId Não Lista à qual adicionar cada contacto importado (e atualizado). Tem de ser uma lista na sua conta.
defaultChannel Não Canal aplicado a registos que omitam channel. Um de whatsapp, sms, whatsapp_web. O predefinido é whatsapp.
updateExisting Não true para atualizar contactos cujo número de telefone já exista em vez de os ignorar como duplicate. O predefinido é false.

Campos por registo

Campo Obrigatório Descrição
phone_number Sim Número de telefone em formato internacional (é adicionado um + inicial se estiver em falta).
first_name Não Nome próprio.
last_name Não Apelido.
email Não Endereço de e-mail.
channel Não Um de whatsapp, sms, whatsapp_web. Recorre a defaultChannel.
is_bot_active Não Se o assistente de IA responde. O predefinido é true.
is_private Não Marcar como privado. O predefinido é 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 Matriz de nomes de etiquetas (uma única string "a; b" também funciona). As etiquetas que não existem são criadas; as existentes são correspondidas ignorando maiúsculas/minúsculas. Máx. 25 por registo.

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 registos não puderem ser criados, aparecem em skipped com o motivo (aqui sem updateExisting, pelo que 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, o mesmo pedido reporta o contacto existente em updated / updated_contact_ids.

Possíveis motivos de exclusão: 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 contactos do seu plano não permitir este número de novos contactos, todo o pedido é rejeitado à partida com um 403. Se o limite for atingido a meio do processo, os registos restantes são devolvidos como ignorados com o motivo contact_limit_reached.


Importar contactos a partir de um ficheiro CSV

Para importações maiores do que o que a importação em massa suporta (até cerca de 50 000 linhas), coloque em fila um trabalho de importação assíncrono para um ficheiro CSV que já se encontre no armazenamento da sua conta e, em seguida, consulte-o até que seja concluído.

Iniciar a importação

POST /contacts/import-csv

Campo Obrigatório Descrição
csvStoragePath Sim Caminho de armazenamento do ficheiro CSV, em users/{your account id}/imports/, terminado em .csv.
listName Sim Cria (ou reutiliza) uma lista com este nome e adiciona-lhe todos os contactos importados.
existingListRefs Não Matriz de IDs de listas existentes às quais também adicionar todos os contactos 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 terminou)

{
  "success": true,
  "job_id": "csvimp_abc123",
  "status": "queued"
}

Colocar o ficheiro no armazenamento. Este endpoint inicia e acompanha o trabalho de importação; não aceita o carregamento em si. O ficheiro CSV precisa de já estar em csvStoragePath antes de o chamar — o próprio importador de CSV do painel de controlo faz isto como 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 progride através de queuedprocessingcompleted, ou failed com o motivo em error_message. Um jobId que não exista na sua conta devolve um 404.


Exportar contactos

Inicia uma exportação CSV assíncrona dos seus contactos e devolve um trabalho que pode consultar para verificar a conclusão.

Iniciar a exportação

POST /contacts/export

Campo Obrigatório Descrição
listId Não Exportar apenas os contactos que pertencem a esta lista.
contactIds Não Exportar apenas estes IDs de contacto específicos.

Se deixar ambos em branco, exportará todos os contactos 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 estado da tarefa 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", receberá export_id e contact_count. O descarregamento do ficheiro CSV gerado é feito a partir da página de Exportações do seu painel de controlo.


Enviar uma mensagem a um contacto

POST /contacts/{contactId}/send-message

Envia uma mensagem para um contacto existente no canal em que este se encontra. A mensagem é colocada numa fila e entregue em segundo plano — a resposta confirma que foi aceite, não que já foi entregue.

Campo Obrigatório Descrição
body Sim O texto da mensagem a enviar.
mediaUrl Não URL de um ficheiro multimédia a anexar.
mediaContentType Não Tipo MIME do conteúdo multimédia anexado (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 contacto tiver o modo de não incomodar ou o modo privado ativado, ou não estiver num canal que possa receber mensagens de saída, o pedido é rejeitado 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 contacto — e para mais informações sobre mensagens em geral — consulte a API de Mensagens.


Atribuir um agente de IA a um contacto

POST /contacts/{contactId}/assign-agent

Move uma conversação existente para um agente de IA diferente, a partir da mensagem seguinte. É o mesmo que Atribuir Agente de IA no menu de uma conversação, e o mesmo passo que a ação Atribuir agente de IA ou campanha utiliza nas Automações.

Campo Obrigatório Descrição
agentId Sim O ID do agente de IA que deve assumir o controlo, ou null para limpar a atribuição para que a conversação volte para a caixa de entrada da sua equipa.
triggerAIResponse Não true faz com que o agente recém-atribuído responda imediatamente às últimas mensagens não respondidas do contacto. O valor predefinido é false.

Cuidado com triggerAIResponse: true — envia uma mensagem ao contacto imediatamente, por isso utilize-a apenas quando quiser que a mensagem seja enviada agora. No Messenger e no Instagram, essa mensagem falha se o contacto lhe tiver escrito 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 contacto; caso contrário, o pedido é rejeitado com um 404 ou 403. Encontre os IDs dos agentes na página Agentes de IA (o URL de cada agente termina com o seu ID).


Atribuir um agente de IA a vários contactos

POST /contacts/bulk-assign-agent

Move várias conversas para um agente de IA diferente numa única chamada — ou limpa a atribuição de todas elas com null. É puramente uma alteração de encaminhamento: não é enviada nenhuma mensagem e o agente não responde a ninguém. Cada contacto recebe simplesmente o novo agente na próxima vez que escrever. (É por isso que não existe triggerAIResponse aqui.)

Campo Obrigatório Descrição
agentId Sim O agente de IA que deve assumir o controlo, ou null para limpar a atribuição.
contactIds Um dos três Até 500 IDs de contacto para mover.
filter Um dos três Selecione os contactos no servidor em vez de os listar, começando pelos mais recentes. Aceita as mesmas chaves que os 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 — ver A forma smart_rules.
limit Não Quantos contactos mover nesta chamada quando seleciona com filter ou rules. De 1 a 500, o padrão é 500.

Envie exatamente um de 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 contactos a seleção encontrou no total, updated quantos foram movidos por esta chamada, skipped quantos dos IDs que enviou não foram encontrados na sua conta e remaining quantos ainda correspondem agora que esta chamada terminou.

Mover todos. Como uma chamada move no máximo 500 contactos, um grupo grande requer algumas chamadas. Utilize um filtro que deixe de corresponder a um contacto assim que este for movido — por exemplo filter: { "agentId": "agent_abc123" } enquanto atribui a agent_xyz789 — e repita exatamente a mesma chamada até que remaining devolva 0. Quando passa contactIds em vez disso, remaining é sempre 0.


Atribuir um contacto a um departamento

POST /contacts/{contactId}/department

“Atribuir este lead a Vendas” — regista um contacto num departamento específico e, por predefinição, entrega-o a quem, nesse departamento, tiver atualmente menos contactos. Isto é diferente de atribuir um agente de IA: um departamento responde a “que equipa é responsável por isto”, um agente responde a “que IA responde a isto”, e definir um nunca elimina o outro.

Campo Obrigatório Descrição
department_id Sim O departamento onde registar o contacto. Utilize null para limpar.
hand_to_member Não Atribuir também o contacto à pessoa com menos carga de trabalho nesse departamento. O valor predefinido é true. Nunca reatribui um contacto que já pertença a alguém.

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 contacto já pertencia a alguém, ou se tiver utilizado hand_to_member: false.


Ligar um contacto entre canais

“Continuar no WhatsApp” (ou SMS) encontra ou cria o contacto desta pessoa noutro canal baseado em telefone e liga os dois, para que o resto da aplicação os reconheça como a mesma pessoa.

Ligar a outro canal

POST /contacts/{contactId}/link-channel

Campo Obrigatório Descrição
channel Sim O canal a ligar. Um de whatsapp, whatsapp_web, sms.
phoneNumber Não Número de telefone a utilizar no novo canal. Por predefinição, utiliza o número do próprio contacto 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 indica se foi criado um novo contacto para o canal de destino ou se foi encontrado e ligado um contacto existente. Chamar isto uma segunda vez é seguro — devolve o mesmo contact_id com created: false em vez de criar um duplicado.

Um 422 significa que a conta não pode efetuar esta ligação neste momento: o contacto já se encontra nessa família de canais, não tem número de telefone para utilizar ou não existe nenhum remetente ligado para o canal de destino. Um 409 significa que os dois contactos já estão ligados a duas pessoas diferentes — desligue um primeiro.

Listar as conversas ligadas de um contacto

GET /contacts/{contactId}/linked

Devolve as outras conversas que correspondem à mesma pessoa que este contacto. Um contacto não ligado devolve uma matriz vazia, 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"
      }
    }
  ]
}

Desligar um contacto

DELETE /contacts/{contactId}/link

Remove este contacto da sua pessoa, de forma unilateral — quaisquer outros contactos ainda ligados a essa pessoa mantêm a sua ligação, pelo que desligar 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 }

Obter a fotografia de perfil de um contacto

POST /contacts/{contactId}/profile-pic

Obtém (e coloca em cache) a fotografia de perfil do WhatsApp ou Meta do contacto a pedido — a mesma fotografia devolvida como avatarUrl em Obter um contacto, 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 o URL provém de uma obtenção recente em vez de uma consulta direta ao fornecedor — as fotografias são colocadas em cache durante 7 dias, e um contacto que o fornecedor indica não ter fotografia acessível é colocado em cache como indisponível durante 24 horas. Quando não existe fotografia para obter, avatar_url é omitido e message explica o motivo.


Etiquetar contactos automaticamente com IA

Executa as regras de etiquetas da sua conta sobre o histórico completo de conversas de um ou mais contactos e aplica (ou remove) etiquetas exatamente como a etiquetagem em tempo real que ocorre durante um chat ao vivo — mesmas regras, mesmo custo de crédito por etiqueta.

Iniciar uma execução

POST /contacts/auto-tag

Campo Obrigatório Descrição
scope Sim "contacts" para etiquetar contactos específicos, ou "agent" para etiquetar todas as conversas atualmente geridas por um agente de IA.
contact_ids Obrigatório quando scope é "contacts" Matriz de IDs de contacto, de 1 a 500.
agent_id Obrigatório quando scope é "agent" O agente de IA cujas conversas devem ser etiquetadas. Quando scope é "contacts", isto é opcional e apenas restringe quais das regras de etiqueta do agente sã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 contacto é executado em linha e devolve o resultado imediatamente:

{ "success": true, "result": { "tags_applied": 2, "tags_removed": 0 } }

Dois ou mais contactos (ou scope: "agent") são executados como uma tarefa em segundo plano e devolvem 202 imediatamente:

{ "success": true, "run_id": "m1x2y3-a1b2c3d4", "total": 214 }

Consultar uma execução

GET /contacts/auto-tag/run

Devolve a execução atual (ou mais recente) da conta, para que possa consultar o progresso sem ter de controlar o run_id por si próprio.

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. O status passa de "running" para "completed" ou "failed".

Apenas uma execução em massa pode estar em curso por conta de cada vez — iniciar uma segunda enquanto outra está a decorrer devolve 409 com error_code: "auto_tag_run_in_progress". Ficar sem créditos numa execução de contacto único devolve 402 com error_code: "insufficient_credits"; uma execução em massa, pelo contrário, para antecipadamente e comunica até onde chegou em run.


Eliminar um contacto

DELETE /contacts/{contactId}

Elimina permanentemente um contacto por ID, juntamente com o seu histórico de mensagens. Isto não pode ser anulado. Para eliminar vários contactos numa única chamada, utilize Eliminar contactos 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 contacto que não existe na sua conta, ou que pertence a uma conta diferente, devolve um 404.


Eliminar contactos

DELETE /contacts

Elimina permanentemente um ou mais contactos por ID numa única chamada (até 500 IDs). Os IDs que não existirem na sua conta são ignorados e contabilizados em skipped. Esta ação não pode ser anulada.

Campo Descrição
contactIds Matriz de IDs de contacto a eliminar (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
}

Eliminar um campo personalizado

DELETE /contacts/custom-fields/{fieldKey}

Remove uma chave de campo personalizado de todos os contactos na sua conta. Utilize isto para limpar após mudar o nome ou retirar um campo personalizado. A chave pode conter apenas letras, números, sublinhados e hífenes. Devolve o número de contactos atualizados. Esta ação não pode ser desfeita.

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 devolve um 400.


Listas

As listas agrupam contactos. Uma lista pode ser estática (você decide quem a integra) ou inteligente (a adesão é calculada com base em regras e mantida atualizada automaticamente — consulte Organizar Listas e Contactos).

Campo Descrição
name Obrigatório na criação. Até 100 caracteres.
status live (predefinição) ou draft. Em minúsculas.
contact_ids Matriz de IDs de contacto a incluir na lista. Apenas listas estáticas.
type static (predefiniçã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 em linha, no mesmo pedido, pelo que evaluation lhe indica exatamente quem acabou por a integrar. Numa lista estática, evaluation é null.

Atualizar uma lista

PUT /lists/{listId}

Envie apenas os campos que pretende alterar. Alterar smart_rules reavalia a lista imediatamente e devolve 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"] } ] } }'

Pode alternar uma lista entre os dois tipos:

  • Estática → inteligente: envie { "type": "smart", "smart_rules": { … } }. As regras entram em vigor imediatamente.
  • Inteligente → estática: envie { "type": "static" }. As regras são removidas e quem estiver na lista permanece nela.

A estrutura 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 até 200 caracteres.
field op value
tags has_any, has_all, has_none matriz de IDs de etiquetas
lists in_any, not_in_any matriz de IDs de listas (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 estados de contacto
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 completos) ou data-hora ISO completa ("2026-01-01T14:30:00Z", comparada com o momento exato)
mesmos campos de data is_set, not_set
has_interacted_with_ai is true / falsetrue corresponde a contactos aos 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 contactos para os quais a data nunca foi definida (“há mais de N, ou nunca”), e as comparações de texto ignoram maiúsculas/minúsculas.

Interação da IA. has_interacted_with_ai é o sinalizador de ciclo de vida: true para cada contacto a quem a sua IA enviou pelo menos uma mensagem, false para todos os outros (incluindo contactos aos quais apenas a sua equipa respondeu). É marcado na primeira mensagem da IA para um contacto e nunca é apagado, pelo que desativar as respostas da IA do contacto ou movê-lo para outra campanha não o reinicia. Para um período — “os contactos que a minha IA geriu este mês”, a questão habitual de faturação — utilize o intervalo 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 o tenha feito) ou has_ever_responded (o contacto respondeu, a qualquer pessoa). As mesmas duas marcas são devolvidas em cada contacto como first_ai_interaction_at / last_ai_interaction_at, e todo o conjunto de regras também funciona em GET /contacts?rules=, pelo que pode contar correspondências sem criar uma lista.

Pré-visualizar um conjunto de regras

POST /lists/preview

Conta e amostra os contactos que um conjunto de regras corresponderia, sem criar ou alterar nada. Utilize-o para verificar a validade das regras antes de as guardar.

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 contém até 10 contactos, ordenados pelos mais recentemente ativos.

Voltar a executar uma lista inteligente agora

POST /lists/{listId}/evaluate

Força uma reavaliação imediata (o mesmo que Atualizar agora faz no painel). As listas inteligentes já são atualizadas quando um contacto é alterado e a cada 15 minutos para regras baseadas no tempo, por isso isto só é necessário quando pretende 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.

As listas inteligentes recusam membros selecionados manualmente

Os endpoints de associação devolvem 409 com "This is a smart list — its members are computed from its rules. Edit the rules instead." quando a lista de destino é inteligente. Isto abrange 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 numa lista estática também é um 409 — não tem regras para executar.


Erros da API de Contactos

Os endpoints de contactos devolvem o envelope de erro padrão:

{
  "success": false,
  "error": "Contact not found"
}

Alguns endpoints também incluem error_code, que geralmente corresponde ao estado HTTP — a única exceção é o caso de contacto duplicado abaixo, onde o estado HTTP é 200 e apenas o error_code transporta o 409. Os códigos específicos para os endpoints de contactos:

Código Quando ocorre num endpoint de contacto
400 Pedido inválido — um campo em falta/inválido, corpo vazio, cursor incorreto ou mais de 500 IDs num lote.
402 Créditos insuficientes para concluir uma execução de etiquetagem por IA num contacto (error_code: "insufficient_credits").
404 O contacto, lista ou etiqueta não foi encontrado na sua conta.
409 Já existe um contacto com esse número de telefone (ao criar). Devolvido como error_code no corpo com um estado HTTP de 200, por isso ramifique em error_code aqui. Também devolvido quando uma execução de etiquetagem automática em massa já está em curso (error_code: "auto_tag_run_in_progress"), ou quando a ligação de um contacto a outro canal uniria dois contactos já ligados a duas pessoas diferentes.
422 O contacto não pode receber uma mensagem neste momento (não incomodar, privado ou canal não suportado). No endpoint de ligação de canal, também abrange a ausência de número de telefone, um emparelhamento de canal não suportado ou a ausência de um remetente ligado para o canal de destino.

Um 403 num endpoint de contacto também pode significar um problema de limite de contactos ou de permissão de lista, em vez de acesso ao plano. Os códigos partilhados que todos os endpoints podem devolver — 401, 403 (o seu plano não inclui acesso à API), 429 (limite de taxa) e 500 — estão listados com orientações de repetição em Erros e Paginação.


Próximos passos

  • API de Mensagens — envie mensagens por identidade de canal e gira conversas.
  • Referência da API — lista completa de endpoints, incluindo etiquetas e listas.
  • Acesso à API — autenticação, limites de taxa e tratamento de erros.