API kontaktów
Kontakt to pojedyncza osoba, do której wysyłasz wiadomości — obejmuje jej imię, numer telefonu, adres e-mail, kanał komunikacji, tagi, pola niestandardowe oraz listy i kampanie, do których należy. API kontaktów umożliwia tworzenie kontaktów, wyszukiwanie ich, aktualizowanie, tagowanie, importowanie masowe oraz usuwanie, a wszystko to bez konieczności korzystania z panelu nawigacyjnego.
Wszystkie ścieżki na tej stronie są względne względem bazowego adresu URL:
https://api.youraiconnector.com/v1
Zatem /contacts oznacza https://api.youraiconnector.com/v1/contacts.
Dopiero zaczynasz pracę z API? Najpierw przeczytaj Dostęp do API — zawiera informacje o tym, jak wygenerować klucz API, trzy sposoby uwierzytelniania, limity zapytań oraz format błędów. Wszystkie informacje na tej stronie zakładają, że masz już działający klucz API.
Informacje o identyfikatorach kontaktów
Każdy kontakt ma unikalny identyfikator (ID). Identyfikator, który otrzymujesz podczas tworzenia kontaktu (w data.contactId), jest tym samym identyfikatorem, którego używasz wszędzie indziej — do pobierania, aktualizowania, tagowania, wysyłania wiadomości lub usuwania tego kontaktu. Zapisz go raz i używaj ponownie.
Nie musisz tworzyć kontaktu, aby uzyskać jego identyfikator. Możesz go również wyszukać według numeru telefonu lub adresu e-mail (zobacz Pobierz kontakt) lub przeglądać wszystkie swoje kontakty (zobacz Lista kontaktów). Każda z tych metod zwraca ten sam identyfikator.
Tworzenie kontaktu
POST /contacts
Dodaje nowy kontakt do Twojego konta. Wymagany jest numer telefonu z kodem kraju — sam adres e-mail nie wystarczy. Wszystkie pozostałe pola są opcjonalne.
Możesz opcjonalnie dodać nowy kontakt bezpośrednio do jednej lub wielu list za pomocą listId (pojedyncza lista) lub listIds (tablica). Jeśli wysłane zostaną oba, listIds ma pierwszeństwo.
Każde pole, które wyślesz, a które nie jest jednym ze standardowych pól tworzenia wymienionych w poniższej tabeli pól Tworzenie kontaktu (phoneNumber, firstName, lastName, email, channel, is_bot_active, is_private, lead_profile, listId, listIds, custom_fields), jest automatycznie zapisywane jako pole niestandardowe — dzięki czemu płaska struktura danych z narzędzi takich jak Make czy Zapier działa bez konieczności zagnieżdżania. Możesz również przekazać jawny obiekt custom_fields.
| Pole | Wymagane | Opis |
|---|---|---|
phoneNumber |
Tak | Numer telefonu kontaktu z kodem kraju (np. +15551234567). |
firstName |
Nie | Imię. |
lastName |
Nie | Nazwisko. |
email |
Nie | Adres e-mail. |
channel |
Nie | Kanał komunikacji. Jedna z wartości: whatsapp, sms, whatsapp_web. Domyślnie whatsapp. |
is_bot_active |
Nie | Czy asystent AI odpowiada na wiadomości tego kontaktu. Domyślnie true. |
is_private |
Nie | Oznacz kontakt jako prywatny. Gdy true, asystent AI jest dla niego wyłączony. Domyślnie false. |
lead_profile |
Nie | Notatki tekstowe dotyczące leada. |
listId |
Nie | Identyfikator pojedynczej listy, do której ma zostać dodany kontakt. |
listIds |
Nie | Tablica identyfikatorów list, do których ma zostać dodany kontakt (ma pierwszeństwo przed listId). |
custom_fields |
Nie | Obiekt zawierający własne pola klucz/wartość. Możesz je również przekazać jako klucze najwyższego poziomu. |
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"])
Odpowiedź
{
"success": true,
"data": {
"message": "Successfully created new contact",
"contactId": "contact_abc123",
"listsAdded": ["list123", "list456"]
}
}
Identyfikator nowego kontaktu znajduje się w data.contactId. Listy, do których został dodany, są zwracane w data.listsAdded.
Duplikaty nie są tworzone. Jeśli kontakt o tym samym numerze telefonu już istnieje, wywołanie tworzenia nie utworzy go ani nie zwróci. Odpowiedź wraca z kodem statusu HTTP
200orazerror_codeo wartości409w treści, dlatego należy rozgałęziać logikę na podstawieerror_code, a nie statusu HTTP:{ "success": false, "error_code": 409, "error": "A contact with this phone number already exists for the current user." }Aby pracować z istniejącym kontaktem po otrzymaniu
error_codeo wartości409, wyszukaj go za pomocą Pobierz kontakt według numeru telefonu lub adresu e-mail —GET /contacts?phoneNumber=...— i użyj ponownie zwróconego identyfikatora.
Równoważne zapisy numerów WhatsApp są traktowane jako ten sam numer. Niektóre kraje mają dwa poprawne sposoby zapisu tego samego numeru telefonu komórkowego, a WhatsApp może zgłaszać dowolny z nich: Meksyk (
+52…i starszy+521…), Brazylia (z dziewiątą cyfrą lub bez) oraz Argentyna (z9po+54lub bez). Sprawdzanie duplikatów podczas tworzenia iGET /contacts?phoneNumber=działa dla obu zapisów, więc otrzymasz istniejący kontakt niezależnie od tego, w jakiej formie go wyślesz.phone_numberzapisany w kontakcie nigdy nie jest nadpisywany.
Pobierz kontakt według numeru telefonu lub adresu e-mail
GET /contacts?phoneNumber=... lub GET /contacts?email=...
Wyszukuje pojedynczy kontakt i zwraca pełny, wzbogacony obiekt kontaktu — w tym jego listy, tagi i kampanie rozwiązane do par { id, name }, a także ostatnią wymienioną wiadomość.
Przekaż albo phoneNumber (w formacie międzynarodowym), albo email. Jeśli nie przekażesz żadnego z nich, ten sam punkt końcowy przełączy się w tryb Listowania kontaktów.
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"])
Odpowiedź
{
"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"
}
}
}
Identyfikator kontaktu jest zwracany zarówno na najwyższym poziomie (contactId), jak i wewnątrz obiektu (contact.id). Jeśli nic nie pasuje, otrzymasz 404 z { "success": false, "message": "Contact not found" }.
avatarUrlto zdjęcie profilowe kontaktu, pobrane z WhatsApp lub Meta, gdy użytkownik wyśle do Ciebie wiadomość. Jest ono tylko do odczytu: nie możesz go ustawić i jest ononulldla kontaktów, które nie mają zdjęcia lub kontaktują się przez kanał, który go nie udostępnia. Traktuj ten link jako tymczasowy, zamiast go przechowywać, ponieważ niektóre z tych linków do zdjęć wygasają i są odświeżane automatycznie. (W poniższym punkcie końcowym listy ta sama wartość nazywa sięavatar_url.)
Numery telefonów w adresach URL. Znak
+w ciągu zapytania musi być zakodowany jako%2B, w przeciwnym razie zostanie odczytany jako spacja. Powyższe przykłady robią to za Ciebie.
Pobierz kontakt według identyfikatora
GET /contacts/{contactId}
Jeśli masz już identyfikator kontaktu, pobierz go bezpośrednio. Struktura odpowiedzi jest identyczna jak w przypadku wyszukiwania powyżej.
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"])
Identyfikator kontaktu, który nie istnieje na Twoim koncie, zwraca 404.
Pobierz statystyki kontaktu
GET /contacts/{contactId}/stats
Zwraca zagregowane statystyki wiadomości dla jednego kontaktu: sumy, odpowiedzi AI kontra ludzkie, zużyte kredyty oraz znaczniki czasu pierwszej i ostatniej wiadomości.
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"])
Odpowiedź
{
"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 to ten sam licznik wiadomości AI, który zeruje przycisk „reset” w aplikacji dla danego kontaktu. creditsUsed to bieżąca suma kredytów dla tego kontaktu, a nie tylko liczby z tej odpowiedzi. Identyfikator kontaktu, który nie istnieje na Twoim koncie, zwraca 404.
Listowanie kontaktów
GET /contacts
Wywołaj GET /contacts bez phoneNumber ani email, aby przeglądać wszystkie kontakty, zaczynając od najnowszych. Każda strona zwraca skrócone podsumowania kontaktów (listy, tagi i kampanie są zwracane jako tablice identyfikatorów, a nie pełne obiekty) oraz next_cursor.
| Parametr zapytania | Opis |
|---|---|
limit |
Rozmiar strony. Domyślnie 50, maksymalnie 100. |
cursor |
Wartość next_cursor z poprzedniej strony. Pomiń ją na pierwszej stronie. |
listId |
Opcjonalne. Zwróć tylko kontakty należące do tej listy. |
Aby przejść przez wszystkie strony: wykonaj pierwsze wywołanie bez kursora, a następnie przekazuj zwrócony next_cursor jako cursor. Zatrzymaj się, gdy next_cursor będzie null — oznacza to, że nie ma więcej wyników.
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
Odpowiedź
{
"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"
}
Uwaga: Filtrowanie według listId, który nie istnieje na Twoim koncie, zwraca 404. Nieprawidłowy cursor zwraca 400.
Liczba kontaktów
GET /contacts/count
Zwraca liczbę kontaktów pasujących do filtra oraz podział na kanały, bez konieczności stronicowania. Jest to właściwe wywołanie dla każdego pytania typu „ile” — kafelka na pulpicie nawigacyjnym, automatyzacji lub zapytania do Champa. Wszystkie filtry są opcjonalne, a łączenie kilku z nich zawęża wynik (kontakt musi spełniać każdy z nich).
| Parametr zapytania | Opis |
|---|---|
agentId |
Tylko kontakty przypisane do tego agenta AI. Przekaż none dla kontaktów bez przypisanego agenta (są one obsługiwane przez domyślnego agenta kanału). |
channel |
Tylko kontakty na tym kanale, np. whatsapp, messenger, instagram, sms, email, chat_widget. |
tag |
Tylko kontakty z tą etykietą, według nazwy etykiety (wielkość liter nie ma znaczenia). Nazwa etykiety, której nie posiadasz, zwróci 404. |
listId |
Tylko kontakty na tej liście. |
botActive |
true lub false — tylko kontakty, których asystent AI jest włączony lub wyłączony. |
status |
Tylko kontakty o tym statusie, np. Lead. |
rules |
Obiekt reguł JSON zakodowany w formacie URL, używający tego samego kształtu co lista inteligentna (zobacz Kształt smart_rules poniżej). Nie można łączyć z innymi filtrami. |
Jeśli nie wyślesz żadnego filtra, otrzymasz całkowitą liczbę kontaktów na swoim koncie.
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"])
Odpowiedź
{
"success": true,
"total": 3423,
"by_channel": { "messenger": 2744, "instagram": 667, "none": 12 },
"filters": { "agentId": "agent_xyz789" }
}
by_channel dzieli tę samą sumę według kanałów; kontakty, które nie znajdują się na żadnym kanale, są liczone w none. filters zwraca zastosowane filtry, dzięki czemu możesz sprawdzić, czy wywołanie zadziałało zgodnie z oczekiwaniami.
Uwaga: Wysłanie rules wraz z jakimkolwiek innym filtrem lub wartością rules, która nie jest poprawnym kodem JSON, zwróci 400. Nazwa etykiety lub identyfikator listy, które nie istnieją na Twoim koncie, zwrócą 404.
Aktualizacja kontaktu
PUT /contacts/{contactId}
Aktualizuje istniejący kontakt. Zmieniane są tylko uwzględnione pola — pomiń wszystko, czego nie chcesz zmieniać. Musisz wysłać co najmniej jedno pole, w przeciwnym razie otrzymasz 400 („Brak pól do aktualizacji”).
| Pole | Opis |
|---|---|
firstName |
Imię. |
lastName |
Nazwisko. |
email |
Adres e-mail. |
is_bot_active |
Czy asystent AI odpowiada na wiadomości od tego kontaktu. |
is_private |
Oznacz jako prywatny. Ustawienie tej wartości na true powoduje również wyłączenie asystenta AI. |
do_not_disturb |
Wstrzymaj zautomatyzowaną komunikację z tym kontaktem. Powoduje również zatrzymanie odpowiedzi AI. |
follow_ups_disabled |
Zatrzymaj wszystkie zautomatyzowane działania następcze dla tego kontaktu (szybkie, cykliczne i zimne leady), podczas gdy AI nadal odpowiada na wysyłane przez niego wiadomości. Przydatne po dokonaniu zakupu. Pozostaje wyłączone, dopóki nie ustawisz tego z powrotem na false. |
lead_profile |
Notatki dotyczące leada w formie dowolnego tekstu. |
custom_fields |
Obiekt pól niestandardowych. Scalane według klucza — zapisywane są tylko przesłane klucze, reszta istniejących pól niestandardowych zostaje zachowana. Możesz również przekazać klucze pól niestandardowych na najwyższym poziomie. |
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"])
Odpowiedź
{
"success": true,
"message": "Contact updated successfully"
}
Pola niestandardowe są scalane, a nie zastępowane. Wysłanie
{ "custom_fields": { "tier": "gold" } }ustawia tylkotier— wszelkie inne pola niestandardowe w kontakcie pozostają bez zmian. Aby całkowicie usunąć pole niestandardowe ze wszystkich kontaktów, użyj Usuń pole niestandardowe.
Dodawanie lub usuwanie tagów
POST /contacts/{contactId}/tags
Dodaje i/lub usuwa tagi dla pojedynczego kontaktu w jednym wywołaniu. Przekaż identyfikatory tagów w addTagIds i removeTagIds. Co najmniej jedno z tych pól musi być niepuste.
Tagi muszą już istnieć na Twoim koncie — utwórz je najpierw za pomocą punktu końcowego tagów. Jeśli kontakt lub jakikolwiek powiązany tag nie istnieje, otrzymasz 404.
| Pole | Opis |
|---|---|
addTagIds |
Tablica identyfikatorów tagów do dodania do kontaktu. |
removeTagIds |
Tablica identyfikatorów tagów do usunięcia z kontaktu. |
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"])
Odpowiedź
{
"success": true,
"contact_id": "contact_abc123",
"added": 1,
"removed": 1
}
Zarządzaj biblioteką tagów
Te punkty końcowe służą do zarządzania samym tagiem — jego zmianą nazwy lub usunięciem z Twojego konta — w przeciwieństwie do przypisywania lub usuwania tagu u konkretnego kontaktu (zobacz Dodawanie lub usuwanie tagów powyżej). Każdy tag na Twoim koncie ma identyfikator (tagId): ten widoczny w menedżerze tagów w panelu nawigacyjnym oraz ten zwracany jako data.tag_id podczas tworzenia tagu za pomocą POST /tags i treści JSON { "name": "..." } (bez phoneNumber, email lub contactId).
Aktualizuj tag
PUT /tags/{tagId}
Wyślij tylko te pola, które zmieniasz.
| Pole | Opis |
|---|---|
name |
Nazwa tagu. |
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)" }'
Odpowiedź
{ "success": true, "tag_id": "tagHotLead" }
tagId, który nie istnieje na Twoim koncie, zwraca 404.
Usuń tag
DELETE /tags/{tagId}
Usuwa jeden tag według identyfikatora. Tej operacji nie można cofnąć — kontakty posiadające ten tag po prostu go tracą. Usunięcie tagu, którego już nie ma (lub nigdy nie istniał), zwraca 200 z deleted: 0 zamiast 404, ponieważ nie ma czego wyliczać.
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/tags/tagColdLead?apiKey=YOUR_API_KEY"
Odpowiedź
{ "success": true, "deleted": 1 }
Usuń kilka tagów jednocześnie
DELETE /tags
| Pole | Opis |
|---|---|
tagIds |
Tablica identyfikatorów tagów do usunięcia (maks. 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"] }'
Odpowiedź
{ "success": true, "deleted": 2 }
Identyfikatory, które nie istnieją lub należą do innego konta, są pomijane bez powiadomienia i nie są wliczane do deleted.
Masowe ustawianie flagi
POST /contacts/bulk-flag
Ustawia jedną flagę logiczną dla wielu kontaktów jednocześnie. Maksymalnie 500 identyfikatorów kontaktów na żądanie. Identyfikatory, które nie istnieją na Twoim koncie, są pomijane i zliczane w skipped.
| Pole | Opis |
|---|---|
contactIds |
Tablica identyfikatorów kontaktów do zaktualizowania (maks. 500). |
field |
Flaga do ustawienia. Jedna z bot_active (asystent AI włączony/wyłączony), dnd (wstrzymaj zautomatyzowany kontakt), spam, private. |
value |
Wartość logiczna, na którą ma zostać ustawiona flaga. |
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"])
Odpowiedź
{
"success": true,
"updated": 2,
"skipped": 0
}
Masowy import kontaktów
POST /contacts/import
Tworzy do 500 kontaktów w jednym wywołaniu z tablicy JSON. Każdy rekord wymaga phone_number w formacie międzynarodowym; wszystko inne jest opcjonalne. Rekordy z nieprawidłowymi numerami telefonów lub nieobsługiwanymi kanałami są pomijane (nie są tworzone), a każdy pominięty rekord jest raportowany wraz z indeksem i powodem — dzięki temu możesz poprawić tylko te, które nie zostały przetworzone, i ponowić próbę.
Numery telefonów, które już istnieją na Twoim koncie, są domyślnie pomijane jako duplicate. Wyślij updateExisting: true, aby zamiast tego zaktualizować te kontakty: pola obecne w rekordzie nadpisują dane kontaktu (first_name, last_name, email, lead_profile i custom_fields są scalane klucz po kluczu), tags są dodawane, a kontakt jest dodawany do listId. Kanał, numer telefonu oraz flagi bota nigdy nie są zmieniane w istniejącym kontakcie.
Możesz opcjonalnie dodać każdy zaimportowany (lub zaktualizowany) kontakt do listy za pomocą listId, ustawić defaultChannel dla rekordów, które go nie określają, oraz otagować rekordy za pomocą tags (nazwy tagów — brakujące tagi są tworzone, istniejące są dopasowywane bez uwzględniania wielkości liter).
Pola najwyższego poziomu
| Pole | Wymagane | Opis |
|---|---|---|
contacts |
Tak | Tablica rekordów kontaktów (maks. 500). |
listId |
Nie | Lista, do której ma zostać dodany każdy zaimportowany (i zaktualizowany) kontakt. Musi być listą na Twoim koncie. |
defaultChannel |
Nie | Kanał zastosowany do rekordów, które pomijają channel. Jeden z whatsapp, sms, whatsapp_web. Domyślnie whatsapp. |
updateExisting |
Nie | true, aby zaktualizować kontakty, których numer telefonu już istnieje, zamiast pomijać je jako duplicate. Domyślnie false. |
Pola dla poszczególnych rekordów
| Pole | Wymagane | Opis |
|---|---|---|
phone_number |
Tak | Numer telefonu w formacie międzynarodowym (wiodący + jest dodawany, jeśli go brakuje). |
first_name |
Nie | Imię. |
last_name |
Nie | Nazwisko. |
email |
Nie | Adres e-mail. |
channel |
Nie | Jeden z whatsapp, sms, whatsapp_web. W razie braku używa defaultChannel. |
is_bot_active |
Nie | Czy asystent AI odpowiada. Domyślnie true. |
is_private |
Nie | Oznacz jako prywatny. Domyślnie false. |
lead_profile |
Nie | Notatki o leadzie w formie dowolnego tekstu. |
custom_fields |
Nie | Obiekt z kluczami i wartościami pól niestandardowych. |
tags |
Nie | Tablica nazw tagów (działa również pojedynczy ciąg "a; b"). Tagi, które nie istnieją, są tworzone; istniejące są dopasowywane bez uwzględniania wielkości liter. Maks. 25 na rekord. |
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'])}")
Odpowiedź
{
"success": true,
"imported": 2,
"contact_ids": ["contact_abc123", "contact_def456"],
"updated": 0,
"updated_contact_ids": [],
"skipped": []
}
Jeśli niektóre rekordy nie mogą zostać utworzone, pojawią się w skipped wraz z powodem (tutaj bez updateExisting, więc istniejący numer jest pomijany):
{
"success": true,
"imported": 1,
"contact_ids": ["contact_abc123"],
"updated": 0,
"updated_contact_ids": [],
"skipped": [
{ "index": 1, "phone_number": "+12025551235", "reason": "duplicate" }
]
}
Z updateExisting: true to samo żądanie raportuje istniejący kontakt w sekcji updated / updated_contact_ids.
Możliwe przyczyny pominięcia: invalid_record, missing_phone_number, invalid_phone_number, invalid_channel, duplicate_in_request, duplicate, contact_limit_reached, create_failed.
Limity planu. Jeśli limit kontaktów w Twoim planie nie pozwala na dodanie tak dużej liczby nowych kontaktów, całe żądanie zostanie odrzucone na wstępie z kodem
403. Jeśli limit zostanie osiągnięty w trakcie przetwarzania, pozostałe rekordy zostaną zwrócone jako pominięte z przyczynącontact_limit_reached.
Importowanie kontaktów z pliku CSV
W przypadku importów większych niż obsługuje import masowy (do około 50 000 wierszy), należy dodać asynchroniczne zadanie importu dla pliku CSV znajdującego się już w pamięci masowej konta, a następnie odpytywać o jego status do momentu zakończenia.
Rozpoczęcie importu
POST /contacts/import-csv
| Pole | Wymagane | Opis |
|---|---|---|
csvStoragePath |
Tak | Ścieżka w pamięci masowej do pliku CSV, w ramach users/{your account id}/imports/, kończąca się na .csv. |
listName |
Tak | Tworzy (lub ponownie wykorzystuje) listę o tej nazwie i dodaje do niej każdy zaimportowany kontakt. |
existingListRefs |
Nie | Tablica identyfikatorów istniejących list, do których również należy dodać każdy zaimportowany kontakt. |
defaultChannel |
Nie | Kanał przypisany do wierszy, które go nie określają. |
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"]
Odpowiedź (202 — import został dodany do kolejki, jeszcze nie zakończony)
{
"success": true,
"job_id": "csvimp_abc123",
"status": "queued"
}
Umieszczanie pliku w pamięci masowej. Ten punkt końcowy uruchamia i śledzi zadanie importu; sam w sobie nie przyjmuje przesyłanego pliku. Plik CSV musi już znajdować się w
csvStoragePathprzed wywołaniem tego punktu — własny importer CSV w panelu nawigacyjnym wykonuje to jako pierwszy krok.
Odpytywanie zadania importu
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"
Odpowiedź
{
"success": true,
"job_id": "csvimp_abc123",
"status": "completed",
"imported": 812,
"updated": 0,
"skipped": 14,
"errors": [],
"error_message": null
}
status przechodzi przez etapy queued → processing → completed lub failed z podaniem przyczyny w error_message. jobId, który nie istnieje na Twoim koncie, zwraca 404.
Eksportowanie kontaktów
Uruchamia asynchroniczny eksport kontaktów do pliku CSV i zwraca zadanie, którego status należy sprawdzać w celu potwierdzenia zakończenia.
Rozpocznij eksport
POST /contacts/export
| Pole | Wymagane | Opis |
|---|---|---|
listId |
Nie | Eksportuj tylko kontakty należące do tej listy. |
contactIds |
Nie | Eksportuj tylko te konkretne identyfikatory kontaktów. |
Pozostawienie obu pól pustych spowoduje wyeksportowanie wszystkich kontaktów na Twoim koncie.
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"]
Odpowiedź (202 — eksport został dodany do kolejki)
{
"success": true,
"job_id": "export_abc123",
"status": "queued"
}
Sprawdź status zadania eksportu
GET /contacts/export/{jobId}
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export/export_abc123?apiKey=YOUR_API_KEY"
Odpowiedź
{
"success": true,
"job_id": "export_abc123",
"status": "completed",
"export_id": "exp_xyz789",
"contact_count": 812,
"error_message": null
}
Gdy
statusbędzie"completed", otrzymaszexport_idorazcontact_count. Pobraniu wygenerowanego pliku CSV odbywa się ze strony Eksporty w Twoim panelu nawigacyjnym.
Wyślij wiadomość do kontaktu
POST /contacts/{contactId}/send-message
Wysyła wiadomość do istniejącego kontaktu za pośrednictwem kanału, z którego już korzysta. Wiadomość jest kolejkowana i dostarczana w tle — odpowiedź potwierdza jedynie przyjęcie żądania, a nie fakt dostarczenia wiadomości.
| Pole | Wymagane | Opis |
|---|---|---|
body |
Tak | Treść wysyłanej wiadomości. |
mediaUrl |
Nie | URL pliku multimedialnego do załączenia. |
mediaContentType |
Nie | Typ MIME załączonych mediów (np. 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"])
Odpowiedź
{
"success": true,
"messageId": "aB3dE5fG7hI9jK1lM2nO",
"contactId": "contact_abc123",
"channel": "whatsapp",
"message": "Message created successfully. Delivery is being processed."
}
Nie można teraz wysłać? Jeśli kontakt ma włączony tryb „nie przeszkadzać” lub tryb prywatny, albo nie korzysta z kanału, który może odbierać wiadomości wychodzące, żądanie zostanie odrzucone z kodem
422oraz wyjaśnieniem w poluerror.
Aby wysłać wiadomość za pomocą numeru telefonu, identyfikatora Instagram lub innego identyfikatora kanału zamiast identyfikatora kontaktu — oraz aby dowiedzieć się więcej o przesyłaniu wiadomości — zobacz Messages API.
Przypisz agenta AI do kontaktu
POST /contacts/{contactId}/assign-agent
Przenosi istniejącą konwersację do innego agenta AI, począwszy od następnej wiadomości. Jest to to samo, co Przypisz agenta AI w menu czatu, oraz ten sam krok, którego używa akcja Przypisz agenta AI lub kampanię w Automatyzacjach.
| Pole | Wymagane | Opis |
|---|---|---|
agentId |
Tak | Identyfikator agenta AI, który ma przejąć konwersację, lub null, aby usunąć przypisanie, dzięki czemu konwersacja wróci do skrzynki odbiorczej zespołu. |
triggerAIResponse |
Nie | true sprawia, że nowo przypisany agent natychmiast odpowiada na ostatnie nieodebrane wiadomości kontaktu. Wartość domyślna to false. |
Zachowaj ostrożność przy
triggerAIResponse: true— wysyła on wiadomość do kontaktu natychmiast, więc używaj go tylko wtedy, gdy chcesz, aby wiadomość została dostarczona teraz. W przypadku Messengera i Instagrama wiadomość nie zostanie wysłana, jeśli kontakt ostatnio napisał do Ciebie ponad 24 godziny temu.
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"])
Odpowiedź
{
"success": true,
"data": {
"contactId": "contact_abc123",
"agentId": "agent_xyz789",
"aiResponseTriggered": false
}
}
Agent musi należeć do tego samego konta co kontakt; w przeciwnym razie żądanie zostanie odrzucone z błędem
404lub403. Identyfikatory agentów można znaleźć na stronie Agentów AI (adres URL każdego agenta kończy się jego identyfikatorem).
Przypisz agenta AI do wielu kontaktów
POST /contacts/bulk-assign-agent
Przenosi wiele konwersacji do innego agenta AI w jednym wywołaniu — lub usuwa przypisanie dla nich wszystkich za pomocą null. Jest to czysta zmiana routingu: żadna wiadomość nie jest wysyłana, a agent nikomu nie odpowiada. Każdy kontakt po prostu otrzymuje nowego agenta, gdy napisze następnym razem. (Dlatego nie ma tutaj triggerAIResponse).
| Pole | Wymagane | Opis |
|---|---|---|
agentId |
Tak | Agent AI, który powinien przejąć obsługę, lub null, aby usunąć przypisanie. |
contactIds |
Jedno z trzech | Do 500 identyfikatorów kontaktów do przeniesienia. |
filter |
Jedno z trzech | Wybierz kontakty na serwerze zamiast ich wypisywania, od najnowszych. Przyjmuje te same klucze co filtry punktu końcowego liczby: agentId (lub none), channel, tag, listId, botActive, status. |
rules |
Jedno z trzech | Obiekt reguł listy inteligentnej — zobacz Kształt smart_rules. |
limit |
Nie | Ile kontaktów przenieść w tym wywołaniu przy wyborze za pomocą filter lub rules. Od 1 do 500, domyślnie 500. |
Wyślij dokładnie jeden z parametrów contactIds, filter lub 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"])
Odpowiedź
{
"success": true,
"agentId": "agent_xyz789",
"matched": 3415,
"updated": 500,
"skipped": 0,
"remaining": 2915,
"filters": { "agentId": "agent_abc123" }
}
matched to liczba kontaktów znalezionych w sumie, updated to liczba kontaktów przeniesionych tym wywołaniem, skipped to liczba przesłanych identyfikatorów, których nie znaleziono na koncie, a remaining to liczba kontaktów, które nadal pasują do kryteriów po zakończeniu wywołania.
Przenoszenie wszystkich. Ponieważ jedno wywołanie przenosi maksymalnie 500 kontaktów, duża grupa wymaga kilku wywołań. Użyj filtra, który przestaje pasować do kontaktu po jego przeniesieniu — na przykład filter: { "agentId": "agent_abc123" } podczas przypisywania do agent_xyz789 — i powtarzaj to samo wywołanie, aż remaining zwróci 0. Gdy zamiast tego przekażesz contactIds, remaining zawsze wynosi 0.
Przypisz kontakt do działu
POST /contacts/{contactId}/department
„Przypisz ten lead do działu sprzedaży” — przypisuje kontakt do nazwanego działu i domyślnie przekazuje go osobie w tym dziale, która ma obecnie najmniej kontaktów. Jest to oddzielne działanie od przypisywania agenta AI: dział odpowiada na pytanie „który zespół jest właścicielem tego kontaktu”, agent odpowiada na pytanie „który agent AI odpowiada za ten kontakt”, a ustawienie jednego nigdy nie usuwa drugiego.
| Pole | Wymagane | Opis |
|---|---|---|
department_id |
Tak | Dział, do którego ma zostać przypisany kontakt. Przekaż null, aby wyczyścić to pole. |
hand_to_member |
Nie | Dodatkowo przekaż kontakt osobie z najmniejszą liczbą zadań w tym dziale. Wartość domyślna to true. Nigdy nie zmienia przypisania kontaktu, który ma już właściciela. |
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"])
Odpowiedź
{
"success": true,
"department_id": "dept_sales",
"assigned_to": "member_uid_123"
}
assigned_to jest null, gdy kontakt miał już właściciela lub przekazano hand_to_member: false.
Połącz kontakt między kanałami
„Kontynuuj na WhatsApp” (lub SMS) znajduje lub tworzy kontakt tej osoby w innym kanale opartym na numerze telefonu i łączy je ze sobą, dzięki czemu reszta aplikacji rozpoznaje je jako tę samą osobę.
Łączenie z innym kanałem
POST /contacts/{contactId}/link-channel
| Pole | Wymagane | Opis |
|---|---|---|
channel |
Tak | Kanał, z którym należy nawiązać połączenie. Jeden z whatsapp, whatsapp_web, sms. |
phoneNumber |
Nie | Numer telefonu używany w nowym kanale. Domyślnie jest to własny numer kontaktu źródłowego. |
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" }'
Odpowiedź
{
"success": true,
"data": {
"contact_id": "contact_def456",
"person_id": "person_xyz789",
"created": true
}
}
created informuje, czy dla kanału docelowego utworzono nowy kontakt, czy znaleziono i połączono istniejący. Ponowne wywołanie tej metody jest bezpieczne — zwraca ten sam contact_id z created: false zamiast tworzyć duplikat.
422 oznacza, że konto nie może obecnie wykonać tego połączenia: kontakt znajduje się już w tej rodzinie kanałów, nie ma numeru telefonu do użycia lub nie ma połączonego nadawcy dla kanału docelowego. 409 oznacza, że oba kontakty są już powiązane z dwiema różnymi osobami — najpierw należy rozłączyć jeden z nich.
Wyświetlanie listy połączonych konwersacji kontaktu
GET /contacts/{contactId}/linked
Zwraca pozostałe konwersacje, które należą do tej samej osoby co dany kontakt. Rozłączony kontakt zwraca pustą tablicę, a nie 404 — „ta osoba nie ma innych kanałów” jest normalnym stanem.
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/linked?apiKey=YOUR_API_KEY"
Odpowiedź
{
"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"
}
}
]
}
Rozłączanie kontaktu
DELETE /contacts/{contactId}/link
Usuwa ten kontakt z jego osoby jednostronnie — wszelkie inne kontakty nadal powiązane z tą osobą zachowują swoje połączenie, więc rozłączenie jednego z trzech nie powoduje rozwiązania grupy.
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/link?apiKey=YOUR_API_KEY"
Odpowiedź
{ "success": true }
Pobieranie zdjęcia profilowego kontaktu
POST /contacts/{contactId}/profile-pic
Pobiera (i buforuje) zdjęcie profilowe kontaktu z WhatsApp lub Meta na żądanie — to samo zdjęcie, które jest zwracane jako avatarUrl w Pobierz kontakt, po odświeżeniu.
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/profile-pic?apiKey=YOUR_API_KEY"
Odpowiedź
{
"success": true,
"avatar_url": "https://example.com/photo.jpg",
"cached": false
}
cached: true oznacza, że adres URL pochodzi z niedawnego pobrania, a nie ze świeżego wyszukiwania u dostawcy — zdjęcia są buforowane przez 7 dni, a kontakt, dla którego dostawca zgłasza brak dostępnego zdjęcia, jest buforowany jako niedostępny przez 24 godziny. Gdy nie ma zdjęcia do pobrania, avatar_url jest pomijane, a message wyjaśnia przyczynę.
Automatyczne tagowanie kontaktów za pomocą AI
Uruchamia reguły tagowania Twojego konta dla pełnej historii konwersacji jednego lub większej liczby kontaktów i stosuje (lub usuwa) tagi dokładnie tak samo, jak tagowanie w czasie rzeczywistym podczas czatu na żywo — te same reguły, ten sam koszt kredytów za tag.
Rozpocznij uruchomienie
POST /contacts/auto-tag
| Pole | Wymagane | Opis |
|---|---|---|
scope |
Tak | "contacts", aby otagować określone kontakty, lub "agent", aby otagować każdą konwersację obsługiwaną obecnie przez jednego agenta AI. |
contact_ids |
Wymagane, gdy scope to "contacts" |
Tablica identyfikatorów kontaktów, od 1 do 500. |
agent_id |
Wymagane, gdy scope to "agent" |
Agent AI, którego konwersacje mają zostać otagowane. Gdy scope to "contacts", jest to opcjonalne i jedynie zawęża zakres reguł tagowania agenta, które zostaną uruchomione. |
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"] }'
Dla pojedynczego kontaktu uruchomienie następuje w trybie inline i zwraca wynik natychmiast:
{ "success": true, "result": { "tags_applied": 2, "tags_removed": 0 } }
Dwa lub więcej kontaktów (lub scope: "agent") uruchamianych jest jako zadanie w tle i zwraca 202 natychmiast:
{ "success": true, "run_id": "m1x2y3-a1b2c3d4", "total": 214 }
Odpytywanie o stan uruchomienia
GET /contacts/auto-tag/run
Zwraca bieżące (lub ostatnie) uruchomienie konta, dzięki czemu możesz odpytywać o postęp bez samodzielnego śledzenia run_id.
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/auto-tag/run?apiKey=YOUR_API_KEY"
Odpowiedź
{
"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 to null, gdy konto nigdy nie rozpoczęło żadnego uruchomienia. status zmienia się z "running" na "completed" lub "failed".
Na koncie może trwać tylko jedno uruchomienie masowe jednocześnie — rozpoczęcie drugiego, gdy inne jest w toku, zwraca 409 z error_code: "auto_tag_run_in_progress". Brak kredytów przy uruchomieniu dla pojedynczego kontaktu zwraca 402 z error_code: "insufficient_credits"; uruchomienie masowe natomiast zatrzymuje się wcześniej i raportuje postęp w run.
Usuwanie kontaktu
DELETE /contacts/{contactId}
Trwale usuwa jeden kontakt według identyfikatora, wraz z jego historią wiadomości. Tej operacji nie można cofnąć. Aby usunąć kilka kontaktów w jednym wywołaniu, użyj Usuń kontakty poniżej.
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"])
Odpowiedź
{
"success": true
}
Identyfikator kontaktu, który nie istnieje na Twoim koncie lub należy do innego konta, zwraca 404.
Usuń kontakty
DELETE /contacts
Trwale usuwa jeden lub więcej kontaktów według identyfikatora w jednym wywołaniu (do 500 identyfikatorów). Identyfikatory, które nie istnieją na Twoim koncie, zostaną pominięte i uwzględnione w skipped. Tej operacji nie można cofnąć.
| Pole | Opis |
|---|---|
contactIds |
Tablica identyfikatorów kontaktów do usunięcia (maks. 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']}")
Odpowiedź
{
"success": true,
"deleted": 2,
"skipped": 0
}
Usuwanie pola niestandardowego
DELETE /contacts/custom-fields/{fieldKey}
Usuwa jeden klucz pola niestandardowego z każdego kontaktu na Twoim koncie. Użyj tej funkcji, aby posprzątać po zmianie nazwy lub wycofaniu pola niestandardowego. Klucz może zawierać tylko litery, cyfry, podkreślniki i myślniki. Zwraca liczbę zaktualizowanych kontaktów. Tej operacji nie można cofnąć.
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")
Odpowiedź
{
"success": true,
"updated": 42
}
Uwaga: Klucz pola zawierający niedozwolone znaki zwróci 400.
Listy
Listy grupują kontakty. Lista może być statyczna (sam decydujesz, kto się na niej znajduje) lub inteligentna (członkostwo jest obliczane na podstawie reguł i automatycznie aktualizowane — zobacz Organizowanie list i kontaktów).
| Pole | Opis |
|---|---|
name |
Wymagane przy tworzeniu. Maksymalnie 100 znaków. |
status |
live (domyślnie) lub draft. Małe litery. |
contact_ids |
Tablica identyfikatorów kontaktów do umieszczenia na liście. Tylko listy statyczne. |
type |
static (domyślnie) lub smart. |
smart_rules |
Zestaw reguł — wymagany, gdy type to smart. Zobacz poniżej. |
Tworzenie listy
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" } }
]
}
}'
Odpowiedź
{
"success": true,
"list_id": "list_abc123",
"evaluation": { "added": 3, "removed": 0, "total": 3 }
}
Lista inteligentna jest oceniana wewnątrz tego samego żądania, więc evaluation informuje dokładnie, kto się na niej znalazł. W przypadku listy statycznej evaluation to null.
Aktualizacja listy
PUT /lists/{listId}
Prześlij tylko te pola, które zmieniasz. Zmiana smart_rules powoduje natychmiastową ponowną ocenę listy i zwraca ten sam obiekt 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"] } ] } }'
Możesz przełączać listę między dwoma rodzajami:
- Statyczna → inteligentna: wyślij
{ "type": "smart", "smart_rules": { … } }. Reguły zaczną działać natychmiast. - Inteligentna → statyczna: wyślij
{ "type": "static" }. Reguły zostaną usunięte, a osoby znajdujące się na liście pozostaną na niej.
Struktura 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(każdy warunek musi być spełniony) lubany(przynajmniej jeden).conditions— od 1 do 20 warunków, każdy z maksymalnie 100 wartościami, ciągi znaków do 200 znaków.
field |
op |
value |
|---|---|---|
tags |
has_any, has_all, has_none |
tablica identyfikatorów tagów |
lists |
in_any, not_in_any |
tablica identyfikatorów list (tylko listy statyczne — inteligentna lista nie może być utworzona na podstawie innej inteligentnej listy) |
channel |
is_any, is_none |
tablica kanałów |
status |
is_any, is_none |
tablica statusów kontaktu |
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" } |
| te same pola daty | before, after |
data ISO ("2026-01-01", porównywana jako pełne dni) lub pełna data i godzina ISO ("2026-01-01T14:30:00Z", porównywana z dokładnym momentem) |
| te same pola daty | is_set, not_set |
— |
has_interacted_with_ai |
is |
true / false — true dopasowuje kontakty, do których AI wysłało wiadomość przynajmniej raz (kiedykolwiek) |
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 |
ciąg znaków dla formularzy contains |
current_campaign_id, assigned_agent |
is_any, is_none, is_set, not_set |
tablica identyfikatorów dla formularzy is_any / is_none |
custom_field (plus key) |
eq, neq, contains, not_contains, is_set, not_set |
ciąg znaków dla formularzy wartości |
not_within_last dopasowuje również kontakty, dla których data nigdy nie została ustawiona („więcej niż N temu, lub nigdy”), a porównania tekstowe ignorują wielkość liter.
Zaangażowanie AI. has_interacted_with_ai to flaga dożywotnia: true dla każdego kontaktu, do którego Twoje AI wysłało przynajmniej jedną wiadomość, false dla wszystkich pozostałych (w tym kontaktów, na które odpowiadał tylko Twój zespół). Jest ona nadawana przy pierwszej wiadomości AI do kontaktu i nigdy nie jest usuwana, więc wyłączenie odpowiedzi AI dla kontaktu lub przeniesienie go do innej kampanii nie resetuje jej. W przypadku okresu — „kontakty, którymi moje AI zajmowało się w tym miesiącu”, co jest typowym pytaniem rozliczeniowym — należy użyć zakresu last_ai_interaction_at:
{ "field": "last_ai_interaction_at", "op": "within_last", "value": { "amount": 30, "unit": "days" } }
Nie należy mylić żadnego z nich z is_bot_active (AI może odpowiadać, co nie oznacza, że to zrobiło) ani has_ever_responded (kontakt odpisał, komukolwiek). Te same dwa znaczniki są zwracane przy każdym kontakcie jako first_ai_interaction_at / last_ai_interaction_at, a cały zestaw reguł działa również na GET /contacts?rules=, więc możesz zliczać dopasowania bez tworzenia listy.
Podgląd zestawu reguł
POST /lists/preview
Zlicza i pobiera próbki kontaktów, które pasowałyby do zestawu reguł, bez tworzenia ani zmieniania czegokolwiek. Użyj tego, aby sprawdzić poprawność reguł przed ich zapisaniem.
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"] } ] } }'
Odpowiedź
{
"success": true,
"count": 3,
"sample": [
{
"id": "contact_abc123",
"first_name": "Sofia",
"last_name": "Martinez",
"phone_number": "+31600000000",
"email": "sofia@example.com",
"channel": "whatsapp"
}
]
}
sample przechowuje do 10 kontaktów, zaczynając od tych najbardziej aktywnych.
Ponowne uruchomienie listy inteligentnej
POST /lists/{listId}/evaluate
Wymusza natychmiastową ponowną ocenę (to samo, co robi przycisk Odśwież teraz w panelu). Listy inteligentne są aktualizowane automatycznie po zmianie kontaktu oraz co 15 minut w przypadku reguł opartych na czasie, więc jest to potrzebne tylko wtedy, gdy chcesz uzyskać wynik natychmiast.
Odpowiedź
{
"success": true,
"list_id": "list_abc123",
"evaluation": { "added": 2, "removed": 1, "total": 4 }
}
evaluation.skipped: true oznacza, że inna ocena tej samej listy była już w toku i to wywołanie nie przyniosło żadnego efektu.
Listy inteligentne nie akceptują ręcznie dodawanych członków
Punkty końcowe członkostwa zwracają 409 z "This is a smart list — its members are computed from its rules. Edit the rules instead.", gdy lista docelowa jest inteligentna. Dotyczy to POST /contacts/lists, DELETE /contacts/lists, POST /contacts/lists/batch, contact_ids w POST /lists oraz PUT /lists/{listId}, a także wyboru listy inteligentnej jako celu importu CSV. Zamiast tego zmień reguły.
Wywołanie POST /lists/{listId}/evaluate na liście statycznej również kończy się 409 — nie ma ona żadnych reguł do uruchomienia.
Błędy API kontaktów
Punkty końcowe (endpoints) kontaktów zwracają standardową kopertę błędu:
{
"success": false,
"error": "Contact not found"
}
Niektóre punkty końcowe zawierają również error_code, który zazwyczaj odpowiada statusowi HTTP — jedynym wyjątkiem jest przypadek duplikatu kontaktu poniżej, gdzie status HTTP wynosi 200, a tylko error_code zawiera 409. Kody specyficzne dla punktów końcowych kontaktów:
| Kod | Kiedy występuje w punkcie końcowym kontaktu |
|---|---|
400 |
Nieprawidłowe żądanie — brakujące/nieprawidłowe pole, pusty komunikat, nieprawidłowy kursor lub ponad 500 identyfikatorów w partii. |
402 |
Brak wystarczającej liczby kredytów na wykonanie tagowania AI dla jednego kontaktu (error_code: "insufficient_credits"). |
404 |
Kontaktu, listy lub tagu nie znaleziono na Twoim koncie. |
409 |
Kontakt o takim numerze telefonu już istnieje (podczas tworzenia). Zwracane jako error_code w treści z kodem stanu HTTP 200, więc należy tutaj rozgałęzić na error_code. Zwracane również, gdy masowe automatyczne tagowanie jest już w toku (error_code: "auto_tag_run_in_progress") lub gdy połączenie kontaktu z innym kanałem spowodowałoby połączenie dwóch kontaktów już powiązanych z dwiema różnymi osobami. |
422 |
Kontakt nie może obecnie odebrać wiadomości (tryb nie przeszkadzać, profil prywatny lub nieobsługiwany kanał). W punkcie końcowym łączenia kanałów obejmuje również brak numeru telefonu, nieobsługiwaną parę kanałów lub brak podłączonego nadawcy dla kanału docelowego. |
403 w punkcie końcowym kontaktu może również oznaczać problem z limitem kontaktów lub uprawnieniami do listy, a nie z dostępem w ramach planu. Wspólne kody, które może zwrócić każdy punkt końcowy — 401, 403 (Twój plan nie obejmuje dostępu do API), 429 (limit szybkości) oraz 500 — zostały wymienione wraz ze wskazówkami dotyczącymi ponawiania prób w sekcji Błędy i stronicowanie.
Następne kroki
- API wiadomości — wysyłaj wiadomości według identyfikatora kanału i zarządzaj konwersacjami.
- Dokumentacja API — pełna lista punktów końcowych, w tym tagi i listy.
- Dostęp do API — uwierzytelnianie, limity szybkości i obsługa błędów.