Your AI Connector Docs

API Contatti

Un contatto è una singola persona a cui invii messaggi: il suo nome, numero di telefono, email, canale, tag, campi personalizzati e le liste e campagne a cui appartiene. L’API Contatti ti consente di creare contatti, cercarli, aggiornarli, etichettarli, importarli in blocco e rimuoverli, il tutto senza utilizzare la dashboard.

Tutti i percorsi in questa pagina sono relativi all’URL di base:

https://api.youraiconnector.com/v1

Quindi /contacts significa https://api.youraiconnector.com/v1/contacts.

Nuovo dell’API? Leggi prima Accesso API: spiega come generare la tua chiave API, i tre modi per autenticarsi, i limiti di frequenza e il formato degli errori. Tutto ciò che è presente in questa pagina presuppone che tu abbia già una chiave API funzionante.


Informazioni sugli ID contatto

Ogni contatto ha un ID univoco. L’ID che ricevi quando crei un contatto (in data.contactId) è lo stesso ID che utilizzi ovunque: per recuperare, aggiornare, etichettare, inviare un messaggio o eliminare quel contatto. Salvalo una volta e riutilizzalo.

Non è necessario creare un contatto per ottenerne l’ID. Puoi anche cercarlo tramite numero di telefono o email (vedi Ottieni un contatto), oppure scorrere tutti i tuoi contatti (vedi Elenca contatti). Ognuno di questi restituisce lo stesso ID.


Crea un contatto

POST /contacts

Aggiunge un nuovo contatto al tuo account. È richiesto un numero di telefono con prefisso internazionale: un’email da sola non è sufficiente. Tutto il resto è facoltativo.

Puoi facoltativamente inserire il nuovo contatto direttamente in una o più liste con listId (una singola lista) o listIds (un array). Se vengono inviati entrambi, listIds ha la precedenza.

Qualsiasi campo inviato che non sia uno dei campi di creazione standard elencati nella tabella dei campi Crea un contatto qui sotto (phoneNumber, firstName, lastName, email, channel, is_bot_active, is_private, lead_profile, listId, listIds, custom_fields) viene archiviato automaticamente come campo personalizzato; pertanto, un payload flat proveniente da uno strumento come Make o Zapier funziona senza nidificazione. È anche possibile passare un oggetto custom_fields esplicito.

Campo Obbligatorio Descrizione
phoneNumber Il numero di telefono del contatto, con prefisso internazionale (es. +15551234567).
firstName No Nome.
lastName No Cognome.
email No Indirizzo email.
channel No Canale di messaggistica. Uno tra whatsapp, sms, whatsapp_web. L’impostazione predefinita è whatsapp.
is_bot_active No Indica se l’assistente AI risponde a questo contatto. L’impostazione predefinita è true.
is_private No Contrassegna il contatto come privato. Quando è true, l’assistente AI viene disattivato per lui. L’impostazione predefinita è false.
lead_profile No Note a testo libero sul lead.
listId No Un singolo ID lista a cui aggiungere il contatto.
listIds No Un array di ID lista a cui aggiungere il contatto (ha la precedenza su listId).
custom_fields No Un oggetto con i tuoi campi chiave/valore. Puoi anche passarli come chiavi di primo livello.

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"])

Risposta

{
  "success": true,
  "data": {
    "message": "Successfully created new contact",
    "contactId": "contact_abc123",
    "listsAdded": ["list123", "list456"]
  }
}

L’ID del nuovo contatto si trova in data.contactId. Gli elenchi a cui è stato aggiunto vengono riportati in data.listsAdded.

I duplicati non vengono creati. Se esiste già un contatto con lo stesso numero di telefono, la chiamata di creazione non lo crea né lo restituisce. La risposta viene restituita con stato HTTP 200 e un error_code di 409 nel corpo, quindi esegui il branching su error_code anziché sullo stato HTTP:

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

Per lavorare con un contatto esistente dopo un error_code di 409, cercalo con Ottieni un contatto tramite telefono o emailGET /contacts?phoneNumber=... — e riutilizza l’ID restituito.

Le grafie equivalenti di WhatsApp contano come lo stesso numero. Alcuni paesi hanno due grafie valide per la stessa linea mobile e WhatsApp può segnalarne una qualsiasi: Messico (+52… e il precedente +521…), Brasile (con o senza la nona cifra) e Argentina (con o senza il 9 dopo il +54). Il controllo dei duplicati alla creazione e la corrispondenza GET /contacts?phoneNumber= funzionano con entrambe le grafie, quindi otterrai il contatto esistente indipendentemente dalla forma inviata. Il phone_number memorizzato sul contatto non viene mai sovrascritto.


Ottieni un contatto tramite telefono o email

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

Cerca un singolo contatto e restituisce l’oggetto contatto completo e arricchito, inclusi i suoi elenchi, tag e campagne risolti in coppie { id, name }, oltre all’ultimo messaggio scambiato.

Passa o phoneNumber (in formato internazionale) o email. Se non ne passi nessuno, questo stesso endpoint passa alla modalità Elenca contatti.

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"])

Risposta

{
  "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"
    }
  }
}

L’ID del contatto viene restituito sia al livello principale (contactId) che all’interno dell’oggetto (contact.id). Se non ci sono corrispondenze, riceverai un 404 con { "success": false, "message": "Contact not found" }.

avatarUrl è la foto del profilo del contatto, presa da WhatsApp o Meta quando ti inviano un messaggio. È di sola lettura: non puoi impostarla ed è null per i contatti che non hanno una foto o che ti raggiungono su un canale che non ne condivide una. Considera il link come temporaneo invece di memorizzarlo, poiché alcuni di questi link alle foto scadono e vengono aggiornati automaticamente. (Nell’endpoint dell’elenco qui sotto, lo stesso valore è chiamato avatar_url.)

Numeri di telefono negli URL. Un segno + in una stringa di query deve essere codificato come URL %2B, altrimenti viene letto come uno spazio. Gli esempi sopra lo fanno per te.


Ottieni un contatto tramite ID

GET /contacts/{contactId}

Quando disponi già dell’ID di un contatto, recuperalo direttamente. La struttura della risposta è identica a quella della ricerca precedente.

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"])

Un ID contatto che non esiste nel tuo account restituisce un 404.


Ottieni le statistiche del contatto

GET /contacts/{contactId}/stats

Restituisce le statistiche aggregate dei messaggi per un contatto: totali, risposte AI vs umane, crediti spesi e timestamp del primo/ultimo messaggio.

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"])

Risposta

{
  "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 è lo stesso contatore di messaggi AI che il pulsante “reset” in-app su un contatto azzera. creditsUsed è il totale dei crediti correnti per questo contatto, non solo i numeri di questa risposta. Un ID contatto che non esiste nel tuo account restituisce un 404.


Elenca contatti

GET /contacts

Chiama GET /contacts senza phoneNumberemail per scorrere tutti i tuoi contatti, partendo dai più recenti. Ogni pagina restituisce riepiloghi compatti dei contatti (elenchi, tag e campagne vengono restituiti come array di ID anziché come oggetti completi) e un next_cursor.

Parametro di query Descrizione
limit Dimensione della pagina. Il valore predefinito è 50, il massimo è 100.
cursor Il valore next_cursor della pagina precedente. Ometterlo nella prima pagina.
listId Opzionale. Restituisce solo i contatti che appartengono a questo elenco.

Per scorrere ogni pagina: effettua la prima chiamata senza un cursore, quindi continua a passare il next_cursor restituito come cursor. Fermati quando next_cursor è null: significa che non ci sono più risultati.

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

Risposta

{
  "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: Il filtraggio tramite un listId che non esiste nel tuo account restituisce un 404. Un cursor non valido restituisce un 400.


Conta i contatti

GET /contacts/count

Restituisce il numero di contatti che corrispondono a un filtro, con una suddivisione per canale, senza doverli impaginare. Questa è la chiamata corretta per qualsiasi domanda del tipo “quanti sono”: un riquadro della dashboard, un’automazione o una richiesta a Champ. Tutti i filtri sono facoltativi e combinarne diversi restringe il conteggio (un contatto deve corrispondere a ognuno di quelli inviati).

Parametro di query Descrizione
agentId Solo i contatti assegnati a questo agente AI. Passa none per i contatti senza un agente assegnato (a questi risponde l’agente predefinito del canale).
channel Solo i contatti su questo canale, ad es. whatsapp, messenger, instagram, sms, email, chat_widget.
tag Solo i contatti che portano questo tag, tramite il nome del tag (le maiuscole/minuscole non contano). Un nome di tag che non possiedi restituisce un 404.
listId Solo i contatti in questo elenco.
botActive true o false — solo i contatti il cui assistente AI è attivo o disattivo.
status Solo i contatti con questo stato, ad es. Lead.
rules Un oggetto regole JSON codificato in URL, che utilizza la stessa forma di un elenco intelligente (vedi La forma smart_rules più avanti). Non può essere combinato con gli altri filtri.

Non inviare alcun filtro per ottenere il numero totale di contatti sul tuo account.

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"])

Risposta

{
  "success": true,
  "total": 3423,
  "by_channel": { "messenger": 2744, "instagram": 667, "none": 12 },
  "filters": { "agentId": "agent_xyz789" }
}

by_channel suddivide lo stesso totale per canale; i contatti che non si trovano su alcun canale vengono conteggiati sotto none. filters riporta i filtri che sono stati applicati, così puoi verificare che la chiamata abbia fatto ciò che intendevi.

Nota: L’invio di rules insieme a qualsiasi altro filtro, o un valore rules che non sia un JSON valido, restituisce un 400. Un nome di tag o un ID elenco che non esiste sul tuo account restituisce un 404.


Aggiorna un contatto

PUT /contacts/{contactId}

Aggiorna un contatto esistente. Vengono modificati solo i campi inclusi: tralascia tutto ciò che non vuoi toccare. Devi inviare almeno un campo, altrimenti riceverai un 400 (“Nessun campo da aggiornare”).

Campo Descrizione
firstName Nome.
lastName Cognome.
email Indirizzo email.
is_bot_active Indica se l’assistente AI risponde a questo contatto.
is_private Contrassegna come privato. Impostare questo valore su true disattiva anche l’assistente AI.
do_not_disturb Metti in pausa l’attività di outreach automatizzata verso questo contatto. Interrompe anche le risposte dell’AI.
follow_ups_disabled Interrompi tutti i follow-up automatizzati per questo contatto (rapidi, ciclici e cold-lead) mentre l’AI continua a rispondere ai messaggi inviati. Utile una volta effettuato un acquisto. Rimane disattivato finché non lo reimposti su false.
lead_profile Note sul lead in formato testo libero.
custom_fields Un oggetto di campi personalizzati. Uniti per chiave: vengono scritti solo i campi inviati, mentre i restanti campi personalizzati esistenti vengono mantenuti. È anche possibile passare le chiavi dei campi personalizzati al livello principale.

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"])

Risposta

{
  "success": true,
  "message": "Contact updated successfully"
}

I campi personalizzati vengono uniti, non sostituiti. L’invio di { "custom_fields": { "tier": "gold" } } imposta solo tier: tutti gli altri campi personalizzati sul contatto rimangono esattamente come erano. Per rimuovere completamente un campo personalizzato da tutti i contatti, utilizza Elimina un campo personalizzato.


Aggiungi o rimuovi tag

POST /contacts/{contactId}/tags

Aggiunge e/o rimuove tag su un singolo contatto in un’unica chiamata. Passa gli ID dei tag in addTagIds e removeTagIds. Almeno uno dei due deve essere non vuoto.

I tag devono già esistere nel tuo account: creali prima tramite l’endpoint dei tag. Se il contatto o uno qualsiasi dei tag di riferimento non esiste, riceverai un 404.

Campo Descrizione
addTagIds Array di ID tag da aggiungere al contatto.
removeTagIds Array di ID tag da rimuovere dal contatto.

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"])

Risposta

{
  "success": true,
  "contact_id": "contact_abc123",
  "added": 1,
  "removed": 1
}

Gestisci la tua libreria di tag

Questi endpoint gestiscono il tag stesso — rinominandolo o eliminandolo dal tuo account — al contrario dell’applicazione o rimozione di un tag su un singolo contatto (vedi Aggiungi o rimuovi tag sopra). Ogni tag sul tuo account ha un ID (tagId): quello mostrato nel gestore tag della tua dashboard e quello restituito come data.tag_id quando crei un tag con POST /tags e un corpo JSON di { "name": "..." } (senza phoneNumber, email o contactId).

Aggiorna un tag

PUT /tags/{tagId}

Invia solo i campi che stai modificando.

Campo Descrizione
name Il nome del 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)" }'

Risposta

{ "success": true, "tag_id": "tagHotLead" }

Un tagId che non esiste nel tuo account restituisce un 404.

Elimina un tag

DELETE /tags/{tagId}

Elimina un tag tramite ID. Questa operazione non può essere annullata — i contatti che possiedono il tag lo perderanno semplicemente. L’eliminazione di un tag già rimosso (o mai esistito) restituisce 200 con deleted: 0 invece di un 404, poiché non c’è nulla da enumerare.

curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/tags/tagColdLead?apiKey=YOUR_API_KEY"

Risposta

{ "success": true, "deleted": 1 }

Elimina diversi tag contemporaneamente

DELETE /tags

Campo Descrizione
tagIds Array di ID tag da eliminare (massimo 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"] }'

Risposta

{ "success": true, "deleted": 2 }

Gli ID che non esistono o che appartengono a un altro account vengono ignorati silenziosamente e non conteggiati in deleted.


Imposta un flag in blocco

POST /contacts/bulk-flag

Imposta un flag booleano su molti contatti contemporaneamente. Fino a 500 ID contatto per richiesta. Gli ID che non esistono nel tuo account vengono ignorati e conteggiati in skipped.

Campo Descrizione
contactIds Array di ID contatto da aggiornare (max 500).
field Quale flag impostare. Uno tra bot_active (assistente AI attivo/disattivo), dnd (sospendi outreach automatizzato), spam, private.
value Il valore booleano a cui impostare il flag.

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"])

Risposta

{
  "success": true,
  "updated": 2,
  "skipped": 0
}

Importazione contatti in blocco

POST /contacts/import

Crea fino a 500 contatti in una sola chiamata da un array JSON. Ogni record necessita di un phone_number in formato internazionale; tutto il resto è facoltativo. I record con numeri di telefono non validi o canali non supportati vengono saltati (non creati) e ogni record saltato viene segnalato con il relativo indice e motivo: in questo modo puoi correggere solo gli errori e riprovare.

I numeri di telefono già esistenti nel tuo account vengono saltati come duplicate per impostazione predefinita. Invia updateExisting: true per aggiornare invece quei contatti: i campi presenti nel record sovrascrivono quelli del contatto (first_name, last_name, email, lead_profile e custom_fields uniti chiave per chiave), i tags vengono aggiunti e il contatto viene inserito in listId. Il canale, il numero di telefono e i flag del bot non vengono mai modificati su un contatto esistente.

Puoi facoltativamente aggiungere ogni contatto importato (o aggiornato) a un elenco con listId, impostare un defaultChannel per i record che non ne specificano uno e taggare i record con tags (nomi dei tag: i tag mancanti vengono creati, quelli esistenti vengono abbinati senza distinzione tra maiuscole e minuscole).

Campi di primo livello

Campo Obbligatorio Descrizione
contacts Array di record di contatto (max 500).
listId No Elenco a cui aggiungere ogni contatto importato (e aggiornato). Deve essere un elenco presente nel tuo account.
defaultChannel No Canale applicato ai record che omettono channel. Uno tra whatsapp, sms, whatsapp_web. L’impostazione predefinita è whatsapp.
updateExisting No true per aggiornare i contatti il cui numero di telefono esiste già invece di saltarli come duplicate. L’impostazione predefinita è false.

Campi per record

Campo Obbligatorio Descrizione
phone_number Numero di telefono in formato internazionale (se manca, viene aggiunto un + iniziale).
first_name No Nome.
last_name No Cognome.
email No Indirizzo email.
channel No Uno tra whatsapp, sms, whatsapp_web. Ricade su defaultChannel.
is_bot_active No Indica se l’assistente AI risponde. L’impostazione predefinita è true.
is_private No Contrassegna come privato. L’impostazione predefinita è false.
lead_profile No Note sul lead in testo libero.
custom_fields No Oggetto contenente chiavi e valori dei campi personalizzati.
tags No Array di nomi di tag (funziona anche una singola stringa "a; b"). I tag che non esistono vengono creati; quelli esistenti vengono abbinati ignorando le maiuscole/minuscole. Max 25 per record.

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'])}")

Risposta

{
  "success": true,
  "imported": 2,
  "contact_ids": ["contact_abc123", "contact_def456"],
  "updated": 0,
  "updated_contact_ids": [],
  "skipped": []
}

Se alcuni record non possono essere creati, appaiono in skipped con il motivo (qui senza updateExisting, quindi il numero esistente viene saltato):

{
  "success": true,
  "imported": 1,
  "contact_ids": ["contact_abc123"],
  "updated": 0,
  "updated_contact_ids": [],
  "skipped": [
    { "index": 1, "phone_number": "+12025551235", "reason": "duplicate" }
  ]
}

Con updateExisting: true la stessa richiesta segnala il contatto esistente sotto updated / updated_contact_ids.

Possibili motivi di esclusione: invalid_record, missing_phone_number, invalid_phone_number, invalid_channel, duplicate_in_request, duplicate, contact_limit_reached, create_failed.

Limiti del piano. Se il limite di contatti del tuo piano non consente un numero così elevato di nuovi contatti, l’intera richiesta viene rifiutata in anticipo con un 403. Se il limite viene raggiunto durante l’elaborazione, i record rimanenti vengono restituiti come saltati con il motivo contact_limit_reached.


Importare contatti da un file CSV

Per importazioni più grandi di quanto supportato dall’importazione massiva (fino a circa 50.000 righe), accoda un processo di importazione asincrono per un file CSV già presente nello spazio di archiviazione del tuo account, quindi esegui il polling finché non viene completato.

Avviare l’importazione

POST /contacts/import-csv

Campo Obbligatorio Descrizione
csvStoragePath Percorso di archiviazione del file CSV, sotto users/{your account id}/imports/, che termina con .csv.
listName Crea (o riutilizza) un elenco con questo nome e vi aggiunge ogni contatto importato.
existingListRefs No Array di ID di elenchi esistenti a cui aggiungere anche ogni contatto importato.
defaultChannel No Canale applicato alle righe che non ne specificano uno.
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"]

Risposta (202 — l’importazione è in coda, non ancora terminata)

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

Caricamento del file nell’archiviazione. Questo endpoint avvia e traccia il processo di importazione; non accetta direttamente un caricamento. Il file CSV deve già trovarsi in csvStoragePath prima di chiamarlo: l’importatore CSV della dashboard esegue questa operazione come primo passaggio.

Interroga il processo di importazione

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"

Risposta

{
  "success": true,
  "job_id": "csvimp_abc123",
  "status": "completed",
  "imported": 812,
  "updated": 0,
  "skipped": 14,
  "errors": [],
  "error_message": null
}

status passa attraverso queuedprocessingcompleted, oppure failed con il motivo in error_message. Un jobId che non esiste nel tuo account restituisce un 404.


Esportare contatti

Avvia un’esportazione CSV asincrona dei tuoi contatti e restituisce un processo di cui eseguire il polling per il completamento.

Avvia l’esportazione

POST /contacts/export

Campo Obbligatorio Descrizione
listId No Esporta solo i contatti che appartengono a questo elenco.
contactIds No Esporta solo questi ID contatto specifici.

Se non viene specificato nessuno dei due, verranno esportati tutti i contatti presenti nel tuo account.

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"]

Risposta (202 — l’esportazione è in coda)

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

Verifica lo stato del processo di esportazione

GET /contacts/export/{jobId}

curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export/export_abc123?apiKey=YOUR_API_KEY"

Risposta

{
  "success": true,
  "job_id": "export_abc123",
  "status": "completed",
  "export_id": "exp_xyz789",
  "contact_count": 812,
  "error_message": null
}

Una volta che status è "completed" riceverai export_id e contact_count. Il download del file CSV generato avviene dalla pagina Esportazioni della tua dashboard.


Invia un messaggio a un contatto

POST /contacts/{contactId}/send-message

Invia un messaggio a un contatto esistente sul canale che sta già utilizzando. Il messaggio viene messo in coda e consegnato in background: la risposta conferma che è stato accettato, non che sia già stato consegnato.

Campo Obbligatorio Descrizione
body Il testo del messaggio da inviare.
mediaUrl No URL di un file multimediale da allegare.
mediaContentType No Tipo MIME del file multimediale allegato (ad es. 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"])

Risposta

{
  "success": true,
  "messageId": "aB3dE5fG7hI9jK1lM2nO",
  "contactId": "contact_abc123",
  "channel": "whatsapp",
  "message": "Message created successfully. Delivery is being processed."
}

Non è possibile inviare il messaggio in questo momento? Se il contatto ha attivato la modalità non disturbare o privata, o non si trova su un canale in grado di ricevere messaggi in uscita, la richiesta viene rifiutata con un 422 e un error esplicativo.

Per l’invio tramite numero di telefono, ID Instagram o altra identità di canale invece di un ID contatto — e per ulteriori informazioni sulla messaggistica in generale — consulta le API Messaggi.


Assegna un agente IA a un contatto

POST /contacts/{contactId}/assign-agent

Sposta una conversazione esistente su un agente IA diverso, a partire dal messaggio successivo. È la stessa operazione di Assegna agente IA nel menu di una chat, e lo stesso passaggio utilizzato dall’azione Assegna agente IA o campagna nelle Automazioni.

Campo Obbligatorio Descrizione
agentId L’ID dell’agente IA che deve subentrare, oppure null per rimuovere l’assegnazione in modo che la conversazione torni alla posta in arrivo del tuo team.
triggerAIResponse No true fa sì che l’agente appena assegnato risponda immediatamente agli ultimi messaggi senza risposta del contatto. Il valore predefinito è false.

Attenzione con triggerAIResponse: true — invia un messaggio al contatto immediatamente, quindi usalo solo quando vuoi che ricevano il messaggio subito. Su Messenger e Instagram, il messaggio non viene recapitato se il contatto ti ha scritto l’ultima volta più di 24 ore fa.

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"])

Risposta

{
  "success": true,
  "data": {
    "contactId": "contact_abc123",
    "agentId": "agent_xyz789",
    "aiResponseTriggered": false
  }
}

L’agente deve appartenere allo stesso account del contatto; in caso contrario, la richiesta viene rifiutata con un 404 o 403. Trova gli ID degli agenti nella pagina Agenti IA (l’URL di ogni agente termina con il suo ID).


Assegna un agente AI a molti contatti

POST /contacts/bulk-assign-agent

Sposta molte conversazioni su un agente AI diverso con una sola chiamata, oppure cancella l’assegnazione per tutti loro con null. Si tratta puramente di una modifica di instradamento: non viene inviato alcun messaggio e l’agente non risponde a nessuno. Ogni contatto riceve semplicemente il nuovo agente la prossima volta che scrive. (Ecco perché qui non c’è triggerAIResponse.)

Campo Obbligatorio Descrizione
agentId L’agente AI che dovrebbe subentrare, o null per cancellare l’assegnazione.
contactIds Uno dei tre Fino a 500 ID contatto da spostare.
filter Uno dei tre Seleziona i contatti sul server invece di elencarli, dal più recente al meno recente. Accetta le stesse chiavi dei filtri dell’endpoint di conteggio: agentId (o none), channel, tag, listId, botActive, status.
rules Uno dei tre Un oggetto regole per elenchi intelligenti — vedi La forma smart_rules.
limit No Quanti contatti spostare in questa chiamata quando selezioni con filter o rules. Da 1 a 500, il valore predefinito è 500.

Invia esattamente uno tra contactIds, filter o 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"])

Risposta

{
  "success": true,
  "agentId": "agent_xyz789",
  "matched": 3415,
  "updated": 500,
  "skipped": 0,
  "remaining": 2915,
  "filters": { "agentId": "agent_abc123" }
}

matched è il numero totale di contatti trovati dalla selezione, updated quanti ne sono stati spostati da questa chiamata, skipped quanti degli ID inviati non sono stati trovati sul tuo account e remaining quanti corrispondono ancora ora che la chiamata è terminata.

Spostare tutti. Poiché una chiamata sposta al massimo 500 contatti, un gruppo numeroso richiede alcune chiamate. Usa un filtro che smette di corrispondere a un contatto una volta che è stato spostato — ad esempio filter: { "agentId": "agent_abc123" } durante l’assegnazione a agent_xyz789 — e ripeti esattamente la stessa chiamata finché remaining non torna come 0. Quando passi contactIds invece, remaining è sempre 0.


Assegna un contatto a un dipartimento

POST /contacts/{contactId}/department

“Assegna questo lead alle Vendite” — archivia un contatto sotto un dipartimento specifico e, per impostazione predefinita, lo assegna alla persona di quel dipartimento che attualmente ha meno contatti. Questa operazione è distinta dall’assegnazione di un agente AI: un dipartimento risponde alla domanda “quale team è responsabile di questo”, un agente risponde alla domanda “quale AI gestisce questo”, e l’impostazione di uno non cancella mai l’altro.

Campo Obbligatorio Descrizione
department_id Il dipartimento sotto cui archiviare il contatto. Passa null per cancellarlo.
hand_to_member No Assegna il contatto anche alla persona meno occupata di quel dipartimento. Il valore predefinito è true. Non riassegna mai un contatto già posseduto da qualcuno.

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"])

Risposta

{
  "success": true,
  "department_id": "dept_sales",
  "assigned_to": "member_uid_123"
}

assigned_to è null quando il contatto era già posseduto da qualcuno, o hai passato hand_to_member: false.


Collega un contatto tra diversi canali

“Continua su WhatsApp” (o SMS) trova o crea il contatto di questa persona su un altro canale basato su telefono e collega i due profili, in modo che il resto dell’app li riconosca come la stessa persona.

Collega a un altro canale

POST /contacts/{contactId}/link-channel

Campo Obbligatorio Descrizione
channel Il canale a cui collegarsi. Uno tra whatsapp, whatsapp_web, sms.
phoneNumber No Numero di telefono da utilizzare sul nuovo canale. Per impostazione predefinita utilizza il numero del contatto di origine.
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" }'

Risposta

{
  "success": true,
  "data": {
    "contact_id": "contact_def456",
    "person_id": "person_xyz789",
    "created": true
  }
}

created indica se è stato creato un nuovo contatto per il canale di destinazione o se ne è stato trovato uno esistente e collegato. Chiamare questo metodo una seconda volta è sicuro: restituisce lo stesso contact_id con created: false invece di creare un duplicato.

Un 422 significa che l’account non può eseguire questo collegamento al momento: il contatto è già presente in quella famiglia di canali, non ha un numero di telefono da utilizzare o non c’è alcun mittente connesso per il canale di destinazione. Un 409 significa che i due contatti sono già collegati a due persone diverse: scollegane prima uno.

Elenca le conversazioni collegate di un contatto

GET /contacts/{contactId}/linked

Restituisce le altre conversazioni che corrispondono alla stessa persona di questo contatto. Un contatto non collegato restituisce un array vuoto, non un 404: “questa persona non ha altri canali” è uno stato normale.

curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/linked?apiKey=YOUR_API_KEY"

Risposta

{
  "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"
      }
    }
  ]
}

Scollega un contatto

DELETE /contacts/{contactId}/link

Rimuove questo contatto dalla sua persona, in modo unilaterale: qualsiasi altro contatto ancora collegato a quella persona mantiene il proprio collegamento, quindi scollegare uno dei tre non scioglie il gruppo.

curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/link?apiKey=YOUR_API_KEY"

Risposta

{ "success": true }

Recupera l’immagine del profilo di un contatto

POST /contacts/{contactId}/profile-pic

Recupera (e memorizza nella cache) la foto del profilo WhatsApp o Meta del contatto su richiesta: la stessa foto restituita come avatarUrl in Ottieni un contatto, aggiornata.

curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/profile-pic?apiKey=YOUR_API_KEY"

Risposta

{
  "success": true,
  "avatar_url": "https://example.com/photo.jpg",
  "cached": false
}

cached: true significa che l’URL proviene da un recupero recente anziché da una nuova ricerca presso il provider: le immagini vengono memorizzate nella cache per 7 giorni e un contatto per il quale il provider segnala l’assenza di una foto raggiungibile viene memorizzato come non disponibile per 24 ore. Quando non c’è alcuna immagine da recuperare, avatar_url viene omesso e message ne spiega il motivo.


Assegna tag automaticamente ai contatti con l’IA

Esegue le regole di tagging del tuo account sull’intera cronologia delle conversazioni di uno o più contatti e applica (o rimuove) i tag esattamente come il tagging in tempo reale che avviene durante una chat dal vivo: stesse regole, stesso costo in crediti per tag.

Avvia un’esecuzione

POST /contacts/auto-tag

Campo Obbligatorio Descrizione
scope "contacts" per assegnare tag a contatti specifici, o "agent" per assegnare tag a ogni conversazione attualmente gestita da un agente IA.
contact_ids Obbligatorio quando scope è "contacts" Array di ID contatto, da 1 a 500.
agent_id Obbligatorio quando scope è "agent" L’agente IA le cui conversazioni devono essere taggate. Quando scope è "contacts", questo è facoltativo e serve solo a restringere le regole di tagging dell’agente da eseguire.
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"] }'

Un singolo contatto viene eseguito in linea e restituisce immediatamente il risultato:

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

Due o più contatti (o scope: "agent") vengono eseguiti come processo in background e restituiscono 202 immediatamente:

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

Monitora un’esecuzione

GET /contacts/auto-tag/run

Restituisce l’esecuzione corrente (o più recente) dell’account, in modo da poter monitorare l’avanzamento senza dover tracciare personalmente run_id.

curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/auto-tag/run?apiKey=YOUR_API_KEY"

Risposta

{
  "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 l’account non ne ha mai avviata una. status passa da "running" a "completed" o "failed".

Può essere in corso solo un’esecuzione massiva per account alla volta: avviare una seconda esecuzione mentre un’altra è in corso restituisce 409 con error_code: "auto_tag_run_in_progress". L’esaurimento dei crediti durante un’esecuzione su un singolo contatto restituisce 402 con error_code: "insufficient_credits"; un’esecuzione massiva invece si interrompe anticipatamente e riporta a che punto è arrivata in run.


Elimina un contatto

DELETE /contacts/{contactId}

Elimina definitivamente un contatto tramite ID, insieme alla sua cronologia dei messaggi. Questa operazione non può essere annullata. Per eliminare diversi contatti in un’unica chiamata, utilizza Elimina contatti qui sotto.

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"])

Risposta

{
  "success": true
}

Un ID contatto che non esiste nel tuo account, o che appartiene a un account diverso, restituisce un 404.


Eliminare i contatti

DELETE /contacts

Elimina in modo permanente uno o più contatti tramite ID in un’unica chiamata (fino a 500 ID). Gli ID che non esistono nel tuo account vengono ignorati e conteggiati in skipped. Questa operazione non può essere annullata.

Campo Descrizione
contactIds Array di ID contatto da eliminare (max 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']}")

Risposta

{
  "success": true,
  "deleted": 2,
  "skipped": 0
}

Elimina un campo personalizzato

DELETE /contacts/custom-fields/{fieldKey}

Rimuove una chiave di campo personalizzato da ogni contatto nel tuo account. Utilizzalo per fare pulizia dopo aver rinominato o ritirato un campo personalizzato. La chiave può contenere solo lettere, numeri, trattini bassi e trattini. Restituisce il numero di contatti aggiornati. Questa operazione non può essere annullata.

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")

Risposta

{
  "success": true,
  "updated": 42
}

Nota: Una chiave di campo con caratteri non supportati restituisce un 400.


Liste

Le liste raggruppano i contatti. Una lista può essere statica (decidi tu chi ne fa parte) o smart (l’appartenenza viene calcolata in base a regole e mantenuta aggiornata automaticamente — vedi Organizzazione di liste e contatti).

Campo Descrizione
name Obbligatorio durante la creazione. Fino a 100 caratteri.
status live (predefinito) o draft. Minuscolo.
contact_ids Array di ID contatto da inserire nella lista. Solo per liste statiche.
type static (predefinito) o smart.
smart_rules Il set di regole — obbligatorio quando type è smart. Vedi sotto.

Creare una 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" } }
          ]
        }
      }'

Risposta

{
  "success": true,
  "list_id": "list_abc123",
  "evaluation": { "added": 3, "removed": 0, "total": 3 }
}

Una lista smart viene valutata inline, nella stessa richiesta, quindi evaluation ti indica esattamente chi ne fa parte. In una lista statica evaluation è null.

Aggiornare una lista

PUT /lists/{listId}

Invia solo i campi che stai modificando. La modifica di smart_rules rivaluta immediatamente la lista e restituisce lo stesso oggetto 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"] } ] } }'

Puoi convertire una lista da un tipo all’altro:

  • Statica → smart: invia { "type": "smart", "smart_rules": { … } }. Le regole diventano immediatamente operative.
  • Smart → statica: invia { "type": "static" }. Le regole vengono rimosse e chiunque sia presente nella lista vi rimane.

La struttura di 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 (ogni condizione deve essere vera) o any (almeno una).
  • conditions — da 1 a 20 condizioni, ciascuna con al massimo 100 valori, stringhe fino a 200 caratteri.
field op value
tags has_any, has_all, has_none array di ID tag
lists in_any, not_in_any array di ID elenco (solo elenchi statici — uno smart list non può essere creato a partire da un altro smart list)
channel is_any, is_none array di canali
status is_any, is_none array di stati del contatto
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" }
stessi campi data before, after data ISO ("2026-01-01", confrontata come giorni interi) o data-ora ISO completa ("2026-01-01T14:30:00Z", confrontata con il momento esatto)
stessi campi data is_set, not_set
has_interacted_with_ai is true / falsetrue corrisponde ai contatti a cui l’IA ha inviato almeno un messaggio (in assoluto)
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 stringa per i moduli contains
current_campaign_id, assigned_agent is_any, is_none, is_set, not_set array di ID per i moduli is_any / is_none
custom_field (più un key) eq, neq, contains, not_contains, is_set, not_set stringa per i moduli di valore

not_within_last corrisponde anche ai contatti per i quali la data non è mai stata impostata (“più di N tempo fa, o mai”), e i confronti testuali ignorano maiuscole e minuscole.

Coinvolgimento dell’IA. has_interacted_with_ai è il flag di durata: true per ogni contatto a cui la tua IA ha inviato almeno un messaggio, false per tutti gli altri (inclusi i contatti a cui ha risposto solo il tuo team). Viene impresso al primo messaggio dell’IA a un contatto e non viene mai cancellato, quindi disattivare le risposte dell’IA per il contatto o spostarlo in un’altra campagna non lo reimposta. Per un periodo — “i contatti gestiti dalla mia IA questo mese”, la solita domanda di fatturazione — utilizza invece l’intervallo last_ai_interaction_at:

{ "field": "last_ai_interaction_at", "op": "within_last", "value": { "amount": 30, "unit": "days" } }

Non confondere nessuno dei due con is_bot_active (l’IA è autorizzata a rispondere, non che lo abbia fatto) o has_ever_responded (il contatto ha risposto, a chiunque). Entrambi i timestamp vengono restituiti su ogni contatto come first_ai_interaction_at / last_ai_interaction_at, e l’intero set di regole funziona anche su GET /contacts?rules=, così puoi contare le corrispondenze senza creare un elenco.

Anteprima di un set di regole

POST /lists/preview

Conta e campiona i contatti che un set di regole corrisponderebbe, senza creare o modificare nulla. Usalo per verificare la correttezza delle regole prima di salvarle.

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"] } ] } }'

Risposta

{
  "success": true,
  "count": 3,
  "sample": [
    {
      "id": "contact_abc123",
      "first_name": "Sofia",
      "last_name": "Martinez",
      "phone_number": "+31600000000",
      "email": "sofia@example.com",
      "channel": "whatsapp"
    }
  ]
}

sample contiene fino a 10 contatti, ordinati dal più recentemente attivo.

Esegui di nuovo un elenco smart ora

POST /lists/{listId}/evaluate

Forza una rivalutazione immediata (la stessa operazione eseguita da Aggiorna ora nella dashboard). Gli elenchi smart si aggiornano già quando un contatto cambia e ogni 15 minuti per le regole basate sul tempo, quindi questa operazione è necessaria solo quando si desidera il risultato immediatamente.

Risposta

{
  "success": true,
  "list_id": "list_abc123",
  "evaluation": { "added": 2, "removed": 1, "total": 4 }
}

evaluation.skipped: true significa che un’altra valutazione dello stesso elenco era già in esecuzione e questa chiamata non ha prodotto alcun effetto.

Gli elenchi smart rifiutano i membri selezionati manualmente

Gli endpoint di appartenenza restituiscono 409 con "This is a smart list — its members are computed from its rules. Edit the rules instead." quando l’elenco di destinazione è smart. Ciò copre POST /contacts/lists, DELETE /contacts/lists, POST /contacts/lists/batch, contact_ids su POST /lists e PUT /lists/{listId}, nonché la scelta di un elenco smart come destinazione per un’importazione CSV. Modifica invece le regole.

Chiamare POST /lists/{listId}/evaluate su un elenco statico è anche un 409: non ha regole da eseguire.


Errori dell’API Contatti

Gli endpoint dei contatti restituiscono il pacchetto di errore standard:

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

Alcuni endpoint includono anche error_code, che solitamente corrisponde allo stato HTTP; l’unica eccezione è il caso del contatto duplicato qui sotto, in cui lo stato HTTP è 200 e solo error_code riporta il 409. I codici specifici per gli endpoint dei contatti:

Codice Quando si verifica su un endpoint di contatto
400 Richiesta non valida: campo mancante/non valido, corpo vuoto, cursore errato o più di 500 ID in un batch.
402 Crediti insufficienti per completare un’operazione di tagging AI su un contatto (error_code: "insufficient_credits").
404 Il contatto, l’elenco o il tag non è stato trovato nel tuo account.
409 Un contatto con quel numero di telefono esiste già (durante la creazione). Restituito come error_code nel corpo con uno stato HTTP 200, quindi esegui il branching su error_code qui. Restituito anche quando un’operazione di auto-tagging in blocco è già in corso (error_code: "auto_tag_run_in_progress"), o quando il collegamento di un contatto a un altro canale unirebbe due contatti già collegati a due persone diverse.
422 Il contatto non può ricevere un messaggio in questo momento (non disturbare, privato o canale non supportato). Sull’endpoint di collegamento del canale, copre anche l’assenza di un numero di telefono, un abbinamento di canali non supportato o l’assenza di un mittente collegato per il canale di destinazione.

Un 403 su un endpoint di contatto può anche indicare un problema relativo al limite di contatti o alle autorizzazioni della lista, piuttosto che all’accesso al piano. I codici condivisi che ogni endpoint può restituire — 401, 403 (il tuo piano non include l’accesso API), 429 (limite di frequenza) e 500 — sono elencati con indicazioni sui tentativi in Errori e Paginazione.


Passaggi successivi

  • API Messaggi — invia messaggi tramite identità del canale e gestisci le conversazioni.
  • Riferimento API — elenco completo degli endpoint, inclusi tag ed elenchi.
  • Accesso API — autenticazione, limiti di frequenza e gestione degli errori.