Your AI Connector Docs

API Contacts

Un contact est une personne unique à qui vous envoyez des messages : son nom, son numéro de téléphone, son e-mail, son canal, ses tags, ses champs personnalisés, ainsi que les listes et campagnes auxquelles il appartient. L’API Contacts vous permet de créer des contacts, de les rechercher, de les mettre à jour, de les taguer, de les importer en masse et de les supprimer, le tout sans utiliser le tableau de bord.

Tous les chemins sur cette page sont relatifs à l’URL de base :

https://api.youraiconnector.com/v1

Ainsi, /contacts signifie https://api.youraiconnector.com/v1/contacts.

Nouveau sur l’API ? Lisez d’abord Accès à l’API — cela couvre la façon de générer votre clé API, les trois méthodes d’authentification, les limites de débit et le format des erreurs. Tout ce qui figure sur cette page suppose que vous disposez déjà d’une clé API fonctionnelle.


À propos des identifiants de contact

Chaque contact possède un identifiant unique. L’identifiant que vous obtenez lorsque vous créez un contact (dans data.contactId) est le même que celui que vous utilisez partout ailleurs — pour récupérer, mettre à jour, taguer, envoyer un message ou supprimer ce contact. Enregistrez-le une fois et réutilisez-le.

Vous n’êtes pas obligé de créer un contact pour obtenir son identifiant. Vous pouvez également en rechercher un par numéro de téléphone ou par e-mail (voir Obtenir un contact), ou parcourir tous vos contacts (voir Lister les contacts). Chacune de ces méthodes renvoie le même identifiant.


Créer un contact

POST /contacts

Ajoute un nouveau contact à votre compte. Un numéro de téléphone avec l’indicatif pays est requis — un e-mail seul ne suffit pas. Tout le reste est facultatif.

Vous pouvez éventuellement ajouter le nouveau contact directement dans une ou plusieurs listes avec listId (une seule liste) ou listIds (un tableau). Si les deux sont envoyés, listIds est prioritaire.

Tout champ envoyé qui ne fait pas partie des champs de création standard listés dans le tableau des champs Créer un contact ci-dessous (phoneNumber, firstName, lastName, email, channel, is_bot_active, is_private, lead_profile, listId, listIds, custom_fields) est automatiquement stocké en tant que champ personnalisé — ainsi, une charge utile plate provenant d’un outil comme Make ou Zapier fonctionne sans imbrication. Vous pouvez également transmettre un objet custom_fields explicite.

Champ Requis Description
phoneNumber Oui Le numéro de téléphone du contact, avec l’indicatif pays (par ex. +15551234567).
firstName Non Prénom.
lastName Non Nom de famille.
email Non Adresse e-mail.
channel Non Canal de messagerie. L’un des suivants : whatsapp, sms, whatsapp_web. Par défaut : whatsapp.
is_bot_active Non Indique si l’assistant IA répond à ce contact. Par défaut : true.
is_private Non Marquer le contact comme privé. Lorsque true, l’assistant IA est désactivé pour lui. Par défaut : false.
lead_profile Non Notes en texte libre sur le prospect.
listId Non Un identifiant de liste unique pour ajouter le contact.
listIds Non Un tableau d’identifiants de liste pour ajouter le contact (prioritaire sur listId).
custom_fields Non Un objet contenant vos propres champs clé/valeur. Vous pouvez également les transmettre en tant que clés de premier niveau.

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

Réponse

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

L’ID du nouveau contact se trouve dans data.contactId. Les listes auxquelles il a été ajouté sont renvoyées dans data.listsAdded.

Les doublons ne sont pas créés. Si un contact avec le même numéro de téléphone existe déjà, l’appel de création ne le crée pas et ne le renvoie pas. La réponse renvoie un statut HTTP 200 et un error_code de 409 dans le corps de la réponse ; basez donc votre logique sur error_code plutôt que sur le statut HTTP :

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

Pour travailler avec un contact existant après un error_code de 409, recherchez-le avec Obtenir un contact par téléphone ou e-mailGET /contacts?phoneNumber=... — et réutilisez l’ID qu’il renvoie.

Les orthographes équivalentes WhatsApp comptent comme le même numéro. Certains pays ont deux orthographes valides pour la même ligne mobile et WhatsApp peut signaler l’une ou l’autre : le Mexique (+52… et l’ancien +521…), le Brésil (avec ou sans le neuvième chiffre) et l’Argentine (avec ou sans le 9 après le +54). La vérification des doublons lors de la création et la correspondance GET /contacts?phoneNumber= fonctionnent avec les deux orthographes, vous récupérez donc le contact existant quelle que soit la forme envoyée. Le phone_number enregistré sur le contact n’est jamais réécrit.


Obtenir un contact par téléphone ou e-mail

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

Recherche un contact unique et renvoie l’objet contact complet et enrichi — incluant ses listes, tags et campagnes résolus en paires { id, name }, ainsi que le dernier message échangé.

Passez soit phoneNumber (au format international), soit email. Si vous ne passez aucun des deux, ce même point de terminaison bascule en mode Lister les contacts.

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

Réponse

{
  "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 du contact est renvoyé à la fois au niveau supérieur (contactId) et à l’intérieur de l’objet (contact.id). Si aucune correspondance n’est trouvée, vous recevez un 404 avec { "success": false, "message": "Contact not found" }.

avatarUrl est la photo de profil du contact, extraite de WhatsApp ou de Meta lorsqu’il vous envoie un message. Elle est en lecture seule : vous ne pouvez pas la définir, et elle est null pour les contacts qui n’ont pas de photo ou qui vous contactent via un canal qui n’en partage pas. Considérez le lien comme temporaire plutôt que de le stocker, car certains de ces liens de photos expirent et sont actualisés automatiquement. (Dans le point de terminaison de liste ci-dessous, la même valeur est appelée avatar_url.)

Numéros de téléphone dans les URL. Un signe + dans une chaîne de requête doit être encodé en URL sous la forme %2B, sinon il est lu comme un espace. Les exemples ci-dessus le font pour vous.


Obtenir un contact par ID

GET /contacts/{contactId}

Lorsque vous disposez déjà de l’ID d’un contact, récupérez-le directement. La forme de la réponse est identique à celle de la recherche ci-dessus.

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 de contact qui n’existe pas dans votre compte renvoie une 404.


Obtenir les statistiques d’un contact

GET /contacts/{contactId}/stats

Renvoie les statistiques globales des messages pour un contact : totaux, réponses IA vs humaines, crédits dépensés et horodatages du premier et du dernier message.

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

Réponse

{
  "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 est le même compteur de messages IA que le bouton « réinitialiser » dans l’application remet à zéro pour un contact. creditsUsed est le total cumulé des crédits pour ce contact, et non seulement les chiffres de cette réponse. Un identifiant de contact qui n’existe pas dans votre compte renvoie une 404.


Lister les contacts

GET /contacts

Appelez GET /contacts sans phoneNumber ni email pour parcourir tous vos contacts, du plus récent au plus ancien. Chaque page renvoie des résumés de contacts compacts (les listes, les tags et les campagnes sont renvoyés sous forme de tableaux d’ID plutôt que d’objets complets) ainsi qu’un next_cursor.

Paramètre de requête Description
limit Taille de la page. Par défaut 50, maximum 100.
cursor La valeur next_cursor de la page précédente. À omettre sur la première page.
listId Optionnel. Ne renvoie que les contacts appartenant à cette liste.

Pour parcourir chaque page : effectuez le premier appel sans curseur, puis continuez à transmettre le next_cursor renvoyé en tant que cursor. Arrêtez-vous lorsque next_cursor est null — cela signifie qu’il n’y a plus de résultats.

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

Réponse

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

Remarque : Le filtrage par un listId qui n’existe pas sur votre compte renvoie une 404. Un cursor non valide renvoie une 400.


Compter les contacts

GET /contacts/count

Renvoie le nombre de contacts correspondant à un filtre, avec une répartition par canal, sans avoir à parcourir les pages. C’est l’appel idéal pour toute question de type « combien » : une tuile de tableau de bord, une automatisation ou une demande à Champ. Tous les filtres sont facultatifs, et la combinaison de plusieurs d’entre eux affine le résultat (un contact doit correspondre à chacun des filtres envoyés).

Paramètre de requête Description
agentId Uniquement les contacts assignés à cet agent IA. Passez none pour les contacts sans agent assigné (ceux-ci sont pris en charge par l’agent par défaut du canal).
channel Uniquement les contacts sur ce canal, par ex. whatsapp, messenger, instagram, sms, email, chat_widget.
tag Uniquement les contacts portant ce tag, par nom de tag (la casse n’a pas d’importance). Un nom de tag inexistant renvoie 404.
listId Uniquement les contacts sur cette liste.
botActive true ou false — uniquement les contacts dont l’assistant IA est activé ou désactivé.
status Uniquement les contacts ayant ce statut, par ex. Lead.
rules Un objet de règles JSON encodé en URL, utilisant la même structure qu’une liste intelligente (voir La structure smart_rules plus bas). Ne peut pas être combiné avec les autres filtres.

N’envoyez aucun filtre pour obtenir le nombre total de contacts sur votre compte.

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

Réponse

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

by_channel répartit ce même total par canal ; les contacts qui ne sont sur aucun canal sont comptabilisés sous none. filters renvoie les filtres qui ont été appliqués, afin que vous puissiez vérifier que l’appel a fait ce que vous souhaitiez.

Remarque : L’envoi de rules avec tout autre filtre, ou d’une valeur rules qui n’est pas un JSON valide, renvoie 400. Un nom de tag ou un ID de liste qui n’existe pas sur votre compte renvoie 404.


Mettre à jour un contact

PUT /contacts/{contactId}

Met à jour un contact existant. Seuls les champs que vous incluez sont modifiés — omettez tout ce que vous ne souhaitez pas toucher. Vous devez envoyer au moins un champ, sinon vous recevrez un 400 (« Aucun champ à mettre à jour »).

Champ Description
firstName Prénom.
lastName Nom de famille.
email Adresse e-mail.
is_bot_active Indique si l’assistant IA répond à ce contact.
is_private Marquer comme privé. Définir ceci sur true désactive également l’assistant IA.
do_not_disturb Suspendre la prospection automatisée pour ce contact. Arrête également les réponses de l’IA.
follow_ups_disabled Arrêter tous les suivis automatisés pour ce contact (rapides, cycles et prospects froids) tout en permettant à l’IA de continuer à répondre aux messages qu’ils envoient. Utile une fois qu’une personne a acheté. Reste désactivé jusqu’à ce que vous le remettiez sur false.
lead_profile Notes de prospect en texte libre.
custom_fields Un objet de champs personnalisés. Fusionné par clé — seules les clés que vous envoyez sont écrites, le reste des champs personnalisés existants est conservé. Vous pouvez également transmettre des clés de champs personnalisés au niveau supérieur.

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

Réponse

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

Les champs personnalisés sont fusionnés, et non remplacés. L’envoi de { "custom_fields": { "tier": "gold" } } définit uniquement tier — tous les autres champs personnalisés du contact restent exactement tels qu’ils étaient. Pour supprimer entièrement un champ personnalisé sur tous les contacts, utilisez Supprimer un champ personnalisé.


Ajouter ou supprimer des tags

POST /contacts/{contactId}/tags

Ajoute et/ou supprime des tags sur un seul contact en un seul appel. Transmettez les ID des tags dans addTagIds et removeTagIds. Au moins l’un des deux doit être non vide.

Les tags doivent déjà exister sur votre compte — créez-les d’abord via le point de terminaison des tags. Si le contact ou l’un des tags référencés n’existe pas, vous recevrez un 404.

Champ Description
addTagIds Tableau des identifiants de tags à ajouter au contact.
removeTagIds Tableau des identifiants de tags à supprimer du contact.

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

Réponse

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

Gérer votre bibliothèque de tags

Ces points de terminaison gèrent le tag lui-même — le renommer ou le supprimer de votre compte — contrairement à l’application ou à la suppression d’un tag sur un contact (voir Ajouter ou supprimer des tags ci-dessus). Chaque tag de votre compte possède un identifiant (tagId) : celui affiché dans le gestionnaire de tags de votre tableau de bord, et celui renvoyé en tant que data.tag_id lorsque vous créez un tag avec POST /tags et un corps JSON { "name": "..." } (sans phoneNumber, email ou contactId).

Mettre à jour un tag

PUT /tags/{tagId}

Envoyez uniquement les champs que vous modifiez.

Champ Description
name Le nom du 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)" }'

Réponse

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

Un tagId qui n’existe pas dans votre compte renvoie une 404.

Supprimer un tag

DELETE /tags/{tagId}

Supprime un tag par son identifiant. Cette action est irréversible — les contacts portant ce tag le perdent simplement. La suppression d’un tag déjà supprimé (ou qui n’a jamais existé) renvoie 200 avec deleted: 0 plutôt qu’une 404, car il n’y a rien à énumérer.

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

Réponse

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

Supprimer plusieurs tags à la fois

DELETE /tags

Champ Description
tagIds Tableau des ID de tags à supprimer (1000 max).
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"] }'

Réponse

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

Les ID qui n’existent pas, ou qui appartiennent à un autre compte, sont ignorés silencieusement et ne sont pas comptabilisés dans deleted.


Définir un indicateur en masse

POST /contacts/bulk-flag

Définit un indicateur booléen sur plusieurs contacts à la fois. Jusqu’à 500 identifiants de contact par requête. Les identifiants qui n’existent pas dans votre compte sont ignorés et comptabilisés dans skipped.

Champ Description
contactIds Tableau des identifiants de contact à mettre à jour (max 500).
field Quel indicateur définir. L’un des suivants : bot_active (assistant IA activé/désactivé), dnd (suspendre la prospection automatisée), spam, private.
value La valeur booléenne à attribuer à l’indicateur.

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

Réponse

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

Importation en masse de contacts

POST /contacts/import

Crée jusqu’à 500 contacts en un seul appel à partir d’un tableau JSON. Chaque enregistrement nécessite un phone_number au format international ; tout le reste est facultatif. Les enregistrements avec des numéros de téléphone invalides ou des canaux non pris en charge sont ignorés (non créés), et chaque enregistrement ignoré est signalé avec son index et sa raison — vous pouvez donc corriger uniquement les échecs et réessayer.

Les numéros de téléphone qui existent déjà sur votre compte sont ignorés en tant que duplicate par défaut. Envoyez updateExisting: true pour mettre à jour ces contacts à la place : les champs présents dans l’enregistrement écrasent ceux du contact (first_name, last_name, email, lead_profile et custom_fields fusionnés clé par clé), les tags sont ajoutés, et le contact est ajouté à listId. Le canal, le numéro de téléphone et les indicateurs de bot ne sont jamais modifiés sur un contact existant.

Vous pouvez éventuellement ajouter chaque contact importé (ou mis à jour) à une liste avec listId, définir un defaultChannel pour les enregistrements qui n’en spécifient pas, et étiqueter les enregistrements avec tags (noms des étiquettes — les étiquettes manquantes sont créées, les existantes sont mises en correspondance sans tenir compte de la casse).

Champs de premier niveau

Champ Requis Description
contacts Oui Tableau d’enregistrements de contacts (max 500).
listId Non Liste à laquelle ajouter chaque contact importé (et mis à jour). Doit être une liste sur votre compte.
defaultChannel Non Canal appliqué aux enregistrements qui omettent channel. L’un des whatsapp, sms, whatsapp_web. Par défaut à whatsapp.
updateExisting Non true pour mettre à jour les contacts dont le numéro de téléphone existe déjà au lieu de les ignorer en tant que duplicate. Par défaut à false.

Champs par enregistrement

Champ Requis Description
phone_number Oui Numéro de téléphone au format international (un + initial est ajouté s’il manque).
first_name Non Prénom.
last_name Non Nom de famille.
email Non Adresse e-mail.
channel Non L’un des whatsapp, sms, whatsapp_web. Utilise defaultChannel par défaut.
is_bot_active Non Si l’assistant IA répond. Par défaut à true.
is_private Non Marquer comme privé. Par défaut à false.
lead_profile Non Notes de prospect en texte libre.
custom_fields Non Objet de clés et valeurs de champs personnalisés.
tags Non Tableau de noms d’étiquettes (une seule chaîne "a; b" fonctionne également). Les étiquettes qui n’existent pas sont créées ; les existantes sont mises en correspondance sans tenir compte de la casse. Max 25 par enregistrement.

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

Réponse

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

Si certains enregistrements ne peuvent pas être créés, ils apparaissent dans skipped avec la raison (ici sans updateExisting, donc le numéro existant est ignoré) :

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

Avec updateExisting: true, la même requête signale le contact existant sous updated / updated_contact_ids à la place.

Raisons possibles pour lesquelles un enregistrement est ignoré : invalid_record, missing_phone_number, invalid_phone_number, invalid_channel, duplicate_in_request, duplicate, contact_limit_reached, create_failed.

Limites du forfait. Si la limite de contacts de votre forfait ne permet pas d’ajouter autant de nouveaux contacts, la requête entière est rejetée dès le départ avec une erreur 403. Si la limite est atteinte en cours de traitement, les enregistrements restants sont renvoyés comme ignorés avec la raison contact_limit_reached.


Importer des contacts depuis un fichier CSV

Pour des importations plus volumineuses que ce que permet l’ importation en masse (jusqu’à environ 50 000 lignes), mettez en file d’attente une tâche d’importation asynchrone pour un fichier CSV déjà présent dans le stockage de votre compte, puis interrogez-la jusqu’à ce qu’elle soit terminée.

Démarrer l’importation

POST /contacts/import-csv

Champ Requis Description
csvStoragePath Oui Chemin de stockage du fichier CSV, sous users/{your account id}/imports/, se terminant par .csv.
listName Oui Crée (ou réutilise) une liste avec ce nom et y ajoute chaque contact importé.
existingListRefs Non Tableau des ID de listes existantes auxquelles ajouter également chaque contact importé.
defaultChannel Non Canal appliqué aux lignes qui n’en spécifient pas.
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"]

Réponse (202 — l’importation est mise en file d’attente, pas encore terminée)

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

Placer le fichier dans le stockage. Ce point de terminaison démarre et suit la tâche d’importation ; il n’accepte pas lui-même de téléchargement. Le fichier CSV doit déjà se trouver à csvStoragePath avant que vous ne l’appeliez — l’outil d’importation CSV du tableau de bord effectue cette opération comme première étape.

Interroger la tâche d’importation

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"

Réponse

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

status passe par queuedprocessingcompleted, ou failed avec la raison dans error_message. Un jobId qui n’existe pas sur votre compte renvoie une 404.


Exporter des contacts

Lance une exportation CSV asynchrone de vos contacts et renvoie une tâche que vous pouvez interroger pour vérifier son achèvement.

Lancer l’exportation

POST /contacts/export

Champ Requis Description
listId Non Exporter uniquement les contacts appartenant à cette liste.
contactIds Non Exporter uniquement ces identifiants de contact spécifiques.

Si vous ne remplissez aucun des deux champs, tous les contacts de votre compte seront exportés.

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

Réponse (202 — l’exportation est mise en file d’attente)

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

Interroger le travail d’exportation

GET /contacts/export/{jobId}

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

Réponse

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

Une fois que status est "completed", vous recevez export_id et contact_count. Le téléchargement du fichier CSV généré s’effectue depuis la page Exportations de votre tableau de bord.


Envoyer un message à un contact

POST /contacts/{contactId}/send-message

Envoie un message à un contact existant sur le canal qu’il utilise déjà. Le message est mis en file d’attente et envoyé en arrière-plan — la réponse confirme qu’il a été accepté, et non qu’il a déjà été remis.

Champ Requis Description
body Oui Le texte du message à envoyer.
mediaUrl Non URL d’un fichier multimédia à joindre.
mediaContentType Non Type MIME du média joint (par ex. 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"])

Réponse

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

Impossible d’envoyer pour le moment ? Si le contact a activé le mode « ne pas déranger » ou le mode privé, ou s’il n’est pas sur un canal capable de recevoir des messages sortants, la requête est rejetée avec un 422 et un error explicatif.

Pour envoyer via un numéro de téléphone, un identifiant Instagram ou une autre identité de canal au lieu d’un identifiant de contact — et pour en savoir plus sur la messagerie en général — consultez l’API Messages.


Assigner un agent IA à un contact

POST /contacts/{contactId}/assign-agent

Déplace une conversation existante vers un agent IA différent, à partir du message suivant. Cela équivaut à Assigner un agent IA dans le menu d’une discussion, et c’est la même étape que celle utilisée par l’action Assigner un agent IA ou une campagne dans les automatisations.

Champ Requis Description
agentId Oui L’identifiant de l’agent IA qui doit prendre le relais, ou null pour supprimer l’assignation afin que la conversation revienne dans la boîte de réception de votre équipe.
triggerAIResponse Non true permet à l’agent nouvellement assigné de répondre immédiatement aux derniers messages sans réponse du contact. La valeur par défaut est false.

Attention avec triggerAIResponse: true — cela envoie un message au contact immédiatement, ne l’utilisez donc que lorsque vous voulez qu’il soit contacté sur le moment. Sur Messenger et Instagram, ce message échoue si le contact ne vous a pas écrit depuis plus de 24 heures.

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

Réponse

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

L’agent doit appartenir au même compte que le contact ; sinon, la demande est rejetée avec une erreur 404 ou 403. Trouvez les identifiants des agents sur la page Agents IA (l’URL de chaque agent se termine par son identifiant).


Assigner un agent IA à plusieurs contacts

POST /contacts/bulk-assign-agent

Déplace plusieurs conversations vers un agent IA différent en un seul appel — ou efface l’assignation pour tous avec null. Il s’agit purement d’un changement de routage : aucun message n’est envoyé et l’agent ne répond à personne. Chaque contact reçoit simplement le nouvel agent la prochaine fois qu’il écrit. (C’est pourquoi il n’y a pas de triggerAIResponse ici.)

Champ Requis Description
agentId Oui L’agent IA qui doit prendre le relais, ou null pour effacer l’assignation.
contactIds L’un des trois Jusqu’à 500 identifiants de contact à déplacer.
filter L’un des trois Sélectionne les contacts sur le serveur au lieu de les lister, du plus récent au plus ancien. Accepte les mêmes clés que les filtres du point de terminaison de comptage : agentId (ou none), channel, tag, listId, botActive, status.
rules L’un des trois Un objet de règles de liste intelligente — voir La forme smart_rules.
limit Non Nombre de contacts à déplacer dans cet appel lorsque vous sélectionnez avec filter ou rules. De 1 à 500, par défaut 500.

Envoyez exactement l’un des paramètres contactIds, filter ou rules.

cURL

curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-assign-agent?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "agent_xyz789",
    "filter": { "agentId": "agent_abc123", "channel": "messenger" }
  }'

JavaScript

const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-assign-agent", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    agentId: "agent_xyz789",
    filter: { agentId: "agent_abc123", channel: "messenger" },
  }),
});
const data = await res.json();
console.log(data.updated, data.remaining);

Python

import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-assign-agent",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "agentId": "agent_xyz789",
        "filter": {"agentId": "agent_abc123", "channel": "messenger"},
    },
)
data = res.json()
print(data["updated"], data["remaining"])

Réponse

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

matched correspond au nombre total de contacts trouvés par la sélection, updated au nombre de contacts déplacés par cet appel, skipped au nombre d’ID envoyés qui n’ont pas été trouvés sur votre compte, et remaining au nombre de contacts qui correspondent encore une fois cet appel terminé.

Déplacer tout le monde. Comme un appel déplace au maximum 500 contacts, un grand groupe nécessite plusieurs appels. Utilisez un filtre qui cesse de correspondre à un contact une fois qu’il a été déplacé — par exemple filter: { "agentId": "agent_abc123" } lors de l’assignation à agent_xyz789 — et répétez exactement le même appel jusqu’à ce que remaining renvoie 0. Lorsque vous passez contactIds à la place, remaining est toujours 0.


Assigner un contact à un département

POST /contacts/{contactId}/department

“Assigner ce prospect aux ventes” — classe un contact sous un département nommé et, par défaut, le confie à la personne de ce département qui a actuellement le moins de contacts. Ceci est distinct de l’assignation d’un agent IA : un département répond à la question « quelle équipe est responsable de ceci », un agent répond à « quelle IA traite ceci », et définir l’un n’efface jamais l’autre.

Champ Requis Description
department_id Oui Le département sous lequel classer le contact. Passez null pour effacer cette valeur.
hand_to_member Non Confier également le contact à la personne la moins chargée de ce département. La valeur par défaut est true. Ne réassigne jamais un contact déjà possédé par quelqu’un.

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

Réponse

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

assigned_to est null lorsque le contact était déjà possédé par quelqu’un, ou si vous avez passé hand_to_member: false.


Lier un contact entre les canaux

“Continuer sur WhatsApp” (ou SMS) trouve ou crée le contact de cette personne sur un autre canal basé sur le téléphone et lie les deux ensemble, afin que le reste de l’application les reconnaisse comme étant la même personne.

Lier à un autre canal

POST /contacts/{contactId}/link-channel

Champ Requis Description
channel Oui Le canal auquel se lier. L’un des éléments whatsapp, whatsapp_web, sms.
phoneNumber Non Numéro de téléphone à utiliser sur le nouveau canal. Utilise par défaut le numéro du contact source.
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" }'

Réponse

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

created vous indique si un nouveau contact a été créé pour le canal cible ou si un contact existant a été trouvé et lié. Appeler cette fonction une seconde fois est sans risque : elle renvoie le même contact_id avec created: false au lieu de créer un doublon.

Une erreur 422 signifie que le compte ne peut pas effectuer cette liaison pour le moment : le contact appartient déjà à cette famille de canaux, il n’a pas de numéro de téléphone à utiliser, ou aucun expéditeur n’est connecté pour le canal cible. Une erreur 409 signifie que les deux contacts sont déjà liés à deux personnes différentes ; dissociez-en un d’abord.

Lister les conversations liées d’un contact

GET /contacts/{contactId}/linked

Renvoie les autres conversations qui correspondent à la même personne que ce contact. Un contact non lié renvoie un tableau vide, et non une erreur 404 — « cette personne n’a pas d’autres canaux » est un état normal.

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

Réponse

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

Dissocier un contact

DELETE /contacts/{contactId}/link

Supprime ce contact de sa personne, de manière unilatérale — tout autre contact toujours lié à cette personne conserve son lien, donc dissocier un contact sur trois ne dissout pas le groupe.

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

Réponse

{ "success": true }

Récupérer la photo de profil d’un contact

POST /contacts/{contactId}/profile-pic

Récupère (et met en cache) la photo de profil WhatsApp ou Meta du contact à la demande — la même photo que celle renvoyée par avatarUrl dans Obtenir un contact, actualisée.

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

Réponse

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

cached: true signifie que l’URL provient d’une récupération récente plutôt que d’une recherche directe auprès du fournisseur — les photos sont mises en cache pendant 7 jours, et un contact pour lequel le fournisseur indique qu’aucune photo n’est accessible est mis en cache comme indisponible pendant 24 heures. Lorsqu’il n’y a pas de photo à récupérer, avatar_url est omis et message explique pourquoi.


Étiquetage automatique des contacts avec l’IA

Exécute les règles d’étiquetage de votre compte sur l’historique complet des conversations d’un ou plusieurs contacts et applique (ou supprime) les étiquettes exactement comme le fait l’étiquetage en temps réel lors d’un chat en direct — mêmes règles, même coût en crédits par étiquette.

Démarrer une exécution

POST /contacts/auto-tag

Champ Requis Description
scope Oui "contacts" pour étiqueter des contacts spécifiques, ou "agent" pour étiqueter chaque conversation actuellement gérée par un agent IA.
contact_ids Requis quand scope est "contacts" Tableau d’identifiants de contact, de 1 à 500.
agent_id Requis quand scope est "agent" L’agent IA dont les conversations doivent être étiquetées. Quand scope est "contacts", ceci est facultatif et permet simplement de restreindre les règles d’étiquetage de l’agent qui sont exécutées.
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 seul contact s’exécute en ligne et renvoie le résultat immédiatement :

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

Deux contacts ou plus (ou scope: "agent") s’exécutent en tant que tâche de fond et renvoient 202 immédiatement :

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

Interroger une exécution

GET /contacts/auto-tag/run

Renvoie l’exécution actuelle (ou la plus récente) du compte, afin que vous puissiez suivre la progression sans avoir à gérer run_id vous-même.

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

Réponse

{
  "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 est null lorsque le compte n’en a jamais démarré. status passe de "running" à "completed" ou "failed".

Une seule exécution en masse peut être en cours par compte à la fois — démarrer une seconde exécution alors qu’une autre est en cours renvoie 409 avec error_code: "auto_tag_run_in_progress". L’épuisement des crédits lors d’une exécution sur un seul contact renvoie 402 avec error_code: "insufficient_credits" ; une exécution en masse s’arrête d’elle-même prématurément et indique sa progression dans run.


Supprimer un contact

DELETE /contacts/{contactId}

Supprime définitivement un contact par son identifiant, ainsi que son historique de messages. Cette action est irréversible. Pour supprimer plusieurs contacts en un seul appel, utilisez Supprimer des contacts ci-dessous.

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

Réponse

{
  "success": true
}

Un ID de contact qui n’existe pas sur votre compte, ou qui appartient à un compte différent, renvoie une 404.


Supprimer des contacts

DELETE /contacts

Supprime définitivement un ou plusieurs contacts par identifiant en un seul appel (jusqu’à 500 identifiants). Les identifiants qui n’existent pas sur votre compte sont ignorés et comptabilisés dans skipped. Cette action est irréversible.

Champ Description
contactIds Tableau des identifiants de contact à supprimer (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']}")

Réponse

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

Supprimer un champ personnalisé

DELETE /contacts/custom-fields/{fieldKey}

Supprime une clé de champ personnalisé de chaque contact de votre compte. Utilisez cette fonction pour faire le ménage après avoir renommé ou retiré un champ personnalisé. La clé ne peut contenir que des lettres, des chiffres, des traits de soulignement et des traits d’union. Renvoie le nombre de contacts mis à jour. Cette action est irréversible.

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

Réponse

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

Remarque : Une clé de champ contenant des caractères non pris en charge renvoie une 400.


Listes

Les listes regroupent des contacts. Une liste est soit statique (vous décidez qui en fait partie), soit intelligente (l’appartenance est calculée à partir de règles et mise à jour automatiquement — voir Organisation des listes et des contacts).

Champ Description
name Requis lors de la création. Jusqu’à 100 caractères.
status live (par défaut) ou draft. En minuscules.
contact_ids Tableau d’identifiants de contacts à ajouter à la liste. Listes statiques uniquement.
type static (par défaut) ou smart.
smart_rules L’ensemble de règles — requis lorsque type est smart. Voir ci-dessous.

Créer une liste

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

Réponse

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

Une liste intelligente est évaluée en ligne, dans la même requête, donc evaluation vous indique exactement qui s’y trouve. Sur une liste statique, evaluation est null.

Mettre à jour une liste

PUT /lists/{listId}

Envoyez uniquement les champs que vous modifiez. La modification de smart_rules réévalue immédiatement la liste et renvoie le même objet 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"] } ] } }'

Vous pouvez faire passer une liste d’un type à l’autre :

  • Statique → intelligente : envoyez { "type": "smart", "smart_rules": { … } }. Les règles prennent le relais immédiatement.
  • Intelligente → statique : envoyez { "type": "static" }. Les règles sont supprimées et les personnes présentes sur la liste y restent.

La structure de smart_rules

{
  "match": "all",
  "conditions": [
    { "field": "tags", "op": "has_any", "value": ["tagHotLead"] },
    { "field": "channel", "op": "is_any", "value": ["whatsapp", "sms"] },
    { "field": "last_incoming_message_at", "op": "not_within_last", "value": { "amount": 7, "unit": "days" } },
    { "field": "created_at", "op": "after", "value": "2026-01-01" },
    { "field": "is_bot_active", "op": "is", "value": true },
    { "field": "email", "op": "is_set" },
    { "field": "custom_field", "key": "Plan", "op": "eq", "value": "pro" }
  ]
}
  • matchall (chaque condition doit être vraie) ou any (au moins une).
  • conditions — 1 à 20 conditions, chacune avec au plus 100 valeurs, chaînes de caractères jusqu’à 200 caractères.
field op value
tags has_any, has_all, has_none tableau d’identifiants de tags
lists in_any, not_in_any tableau d’identifiants de listes (listes statiques uniquement — une liste intelligente ne peut pas être créée à partir d’une autre liste intelligente)
channel is_any, is_none tableau de canaux
status is_any, is_none tableau de statuts de contact
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" }
mêmes champs de date before, after date ISO ("2026-01-01", comparée par jours entiers) ou date-heure ISO complète ("2026-01-01T14:30:00Z", comparée à l’instant précis)
mêmes champs de date is_set, not_set
has_interacted_with_ai is true / falsetrue correspond aux contacts auxquels l’IA a envoyé au moins un message (à tout moment)
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 chaîne pour les formulaires contains
current_campaign_id, assigned_agent is_any, is_none, is_set, not_set tableau d’identifiants pour les formulaires is_any / is_none
custom_field (plus un key) eq, neq, contains, not_contains, is_set, not_set chaîne pour les formulaires de valeur

not_within_last correspond également aux contacts pour lesquels la date n’a jamais été définie (“il y a plus de N, ou jamais”), et les comparaisons de texte ignorent la casse.

Engagement de l’IA. has_interacted_with_ai est l’indicateur de durée de vie : true pour chaque contact auquel votre IA a envoyé au moins un message, false pour tous les autres (y compris les contacts auxquels seule votre équipe a répondu). Il est apposé lors du premier message de l’IA à un contact et n’est jamais effacé ; ainsi, désactiver les réponses de l’IA pour le contact ou le déplacer vers une autre campagne ne le réinitialise pas. Pour une période — « les contacts que mon IA a gérés ce mois-ci », la question de facturation habituelle — utilisez plutôt last_ai_interaction_at :

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

Ne confondez pas l’un ou l’autre avec is_bot_active (l’IA est autorisée à répondre, ce qui ne signifie pas qu’elle l’a fait) ou has_ever_responded (le contact a répondu, à qui que ce soit). Les deux mêmes indicateurs sont renvoyés pour chaque contact sous la forme first_ai_interaction_at / last_ai_interaction_at, et l’ensemble des règles fonctionne également sur GET /contacts?rules=, vous pouvez donc compter les correspondances sans créer de liste.

Prévisualiser un ensemble de règles

POST /lists/preview

Compte et échantillonne les contacts qu’un ensemble de règles correspondrait, sans rien créer ni modifier. Utilisez cette fonction pour vérifier la cohérence des règles avant de les enregistrer.

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

Réponse

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

sample contient jusqu’à 10 contacts, classés du plus récemment actif au plus ancien.

Réexécuter une liste intelligente maintenant

POST /lists/{listId}/evaluate

Force une réévaluation immédiate (la même action que Actualiser maintenant dans le tableau de bord). Les listes intelligentes se mettent déjà à jour lorsqu’un contact change, et toutes les 15 minutes pour les règles basées sur le temps ; cette fonction n’est donc nécessaire que lorsque vous souhaitez obtenir le résultat immédiatement.

Réponse

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

evaluation.skipped: true signifie qu’une autre évaluation de la même liste était déjà en cours et que cet appel n’a rien fait.

Les listes intelligentes refusent les membres ajoutés manuellement

Les points de terminaison d’appartenance renvoient 409 avec "This is a smart list — its members are computed from its rules. Edit the rules instead." lorsque la liste cible est intelligente. Cela couvre POST /contacts/lists, DELETE /contacts/lists, POST /contacts/lists/batch, contact_ids sur POST /lists et PUT /lists/{listId}, ainsi que le choix d’une liste intelligente comme cible d’importation CSV. Modifiez plutôt les règles.

Appeler POST /lists/{listId}/evaluate sur une liste statique est également une 409 — elle ne contient aucune règle à exécuter.


Erreurs de l’API Contacts

Les points de terminaison (endpoints) de contact renvoient l’enveloppe d’erreur standard :

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

Certains points de terminaison incluent également error_code, qui correspond généralement au statut HTTP — la seule exception est le cas de doublon de contact ci-dessous, où le statut HTTP est 200 et où seul error_code contient le 409. Les codes spécifiques aux points de terminaison de contact :

Code Quand cela se produit sur un point de terminaison de contact
400 Mauvaise requête — un champ manquant/invalide, un corps vide, un curseur incorrect ou plus de 500 ID dans un lot.
402 Crédits insuffisants pour effectuer une exécution d’étiquetage IA sur un contact (error_code: "insufficient_credits").
404 Le contact, la liste ou l’étiquette n’a pas été trouvé(e) sur votre compte.
409 Un contact avec ce numéro de téléphone existe déjà (lors de la création). Renvoyé sous la forme error_code dans le corps avec un statut HTTP de 200, donc effectuez une bifurcation sur error_code ici. Également renvoyé lorsqu’une exécution d’étiquetage automatique en masse est déjà en cours (error_code: "auto_tag_run_in_progress"), ou lorsque la liaison d’un contact à un autre canal joindrait deux contacts déjà liés à deux personnes différentes.
422 Le contact ne peut pas recevoir de message pour le moment (ne pas déranger, privé ou canal non pris en charge). Sur le point de terminaison de liaison de canal, couvre également l’absence de numéro de téléphone, un couplage de canal non pris en charge ou l’absence d’expéditeur connecté pour le canal cible.

Un 403 sur un point de terminaison de contact peut également signifier un problème de limite de contacts ou d’autorisation de liste plutôt qu’un problème d’accès au forfait. Les codes partagés que chaque point de terminaison peut renvoyer — 401, 403 (votre forfait n’inclut pas l’accès à l’API), 429 (limite de débit) et 500 — sont listés avec des conseils de nouvelle tentative dans Erreurs et pagination.


Étapes suivantes

  • API Messages — envoyez des messages par identité de canal et gérez les conversations.
  • Référence API — liste complète des points de terminaison, y compris les tags et les listes.
  • Accès API — authentification, limites de débit et gestion des erreurs.