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 |
Sì | 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
200e unerror_codedi409nel corpo, quindi esegui il branching suerror_codeanziché 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_codedi409, cercalo con Ottieni un contatto tramite telefono o email —GET /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 il9dopo il+54). Il controllo dei duplicati alla creazione e la corrispondenzaGET /contacts?phoneNumber=funzionano con entrambe le grafie, quindi otterrai il contatto esistente indipendentemente dalla forma inviata. Ilphone_numbermemorizzato 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 ènullper 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 è chiamatoavatar_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 phoneNumber né email 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 solotier: 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 |
Sì | 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 |
Sì | 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 motivocontact_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 |
Sì | Percorso di archiviazione del file CSV, sotto users/{your account id}/imports/, che termina con .csv. |
listName |
Sì | 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
csvStoragePathprima 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 queued → processing → completed, 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"riceveraiexport_idecontact_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 |
Sì | 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
422e unerroresplicativo.
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 |
Sì | 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
404o403. 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 |
Sì | 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 |
Sì | 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 |
Sì | 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 |
Sì | "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" }
]
}
match—all(ogni condizione deve essere vera) oany(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 / false — true 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.