Your AI Connector Docs

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 wraz 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 ma odpowiadać temu kontaktowi. 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 Pojedynczy identyfikator 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. Pola z określonym typem (data, liczba, lista rozwijana, pole wyboru) są walidowane — zobacz Typy pól niestandardowych.

Powszechne alternatywne nazwy są akceptowane, gdy brakuje nazwy standardowej: phone lub phone_number dla numeru, first_name oraz last_name dla nazwy, a także full_name lub name, która jest podzielona na imię i nazwisko. Błąd Missing required fields: phoneNumber oznacza zatem, że nie dotarła żadna wartość telefonu, a nie że klucz został zapisany inaczej.

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 w kanale, w którym go tworzysz, wywołanie tworzenia nie utworzy drugiego. Odpowiedź zwraca status HTTP 200 oraz error_code o wartości 409 w treści, więc należy rozgałęziać logikę na podstawie error_code, a nie statusu HTTP. Identyfikator istniejącego kontaktu jest zwracany jako contactId (oraz data.contactId), dzięki czemu możesz od razu kontynuować pracę z nim:

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

To samo dotyczy zduplikowanego adresu e-mail w kanale Email. Jeśli Twoje stanowisko w zespole widzi tylko własne kontakty, a istniejący kontakt do nich nie należy, identyfikator jest pomijany; w takim przypadku wyszukaj go za pomocą Pobierz kontakt według numeru telefonu lub adresu e-mail.

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 (z 9 po +54 lub bez). Sprawdzanie duplikatów podczas tworzenia i GET /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_number zapisany 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"
    },
    "adAttribution": {
      "visit_at": "2026-06-09T10:14:02.000Z",
      "matched_at": "2026-06-09T10:14:20.000Z",
      "match_method": "reference",
      "reference": "4827",
      "fbc": "fb.1.1749463000000.IwAR...",
      "fbp": "fb.1.1749000000000.123456789",
      "fbclid": "IwAR...",
      "gclid": null,
      "gbraid": null,
      "wbraid": null,
      "utm_source": "facebook",
      "utm_medium": "paid",
      "utm_campaign": "spring-promo",
      "utm_content": null,
      "utm_term": null,
      "landing_url": "https://yoursite.com/quiz?utm_source=facebook&utm_campaign=spring-promo",
      "referrer": "https://l.facebook.com/",
      "client_ip": "203.0.113.7",
      "user_agent": "Mozilla/5.0 (iPhone; ...)",
      "site_key": "YOUR_SITE_KEY",
      "visit_id": "visit_abc123"
    }
  }
}

adAttribution to kliknięcie w reklamę, które doprowadziło do Twojej witryny, dopasowane do tego kontaktu przez skrypt kliknięcia w reklamę, lub null, gdy go nie ma. Pola zostały wyjaśnione w Atrybucja kliknięć w reklamy dla WhatsApp.

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

avatarUrl to 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 ono null dla 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.


Kontakty z ukrytym numerem

Kontakt w WhatsApp Web może pojawić się bez numeru telefonu, gdy WhatsApp ukrywa go przed powiązanym urządzeniem (zobacz Kontakty z ukrytym numerem). Każdy odczytany kontakt zawiera dwa dodatkowe pola w tym celu: number_hidden (numberHidden w kształcie pojedynczego kontaktu) oraz whatsapp_lid (whatsappLid).

  • W przypadku kontaktu z ukrytym numerem, phone_number ma wartość null, number_hidden ma wartość true, a whatsapp_lid przechowuje wewnętrzny identyfikator WhatsApp w formacie 153055538446346@lid. Nie jest to numer, pod który można zadzwonić. Dopasuj kontakt na podstawie tego identyfikatora w swoim systemie i przekaż go jako phoneNumber do tego wyszukiwania, aby ponownie znaleźć kontakt.
  • W przypadku każdego innego kontaktu, number_hidden ma wartość false, a whatsapp_lid to identyfikator zgłoszony przez WhatsApp dla tego kontaktu lub null.

Wychodzące webhooki i ładunki automatyzacji zawierające kontakt przenoszą te same trzy pola, a eksport kontaktów do pliku CSV zawiera kolumny „Number Hidden” (Ukryty numer) oraz „WhatsApp LID” obok „Phone Number” (Numer telefonu). Gdy WhatsApp udostępni rzeczywisty numer, kontakt zaktualizuje się automatycznie, a pole phone_number zostanie wypełnione.

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.


Pobierz koszt kontaktu

GET /contacts/{contactId}/cost

Zwraca liczbę kredytów zużytych przez kontakt, z podziałem na konwersacje (sesje czatu), rodzaje działań oraz średni koszt konwersacji obsługiwanej wyłącznie przez AI w porównaniu z taką, w którą zaangażował się Twój zespół. Użyj tego, aby pokazać klientowi, ile kosztuje konwersacja.

cURL

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

JavaScript

const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/cost", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.total_credits, data.by_session.length);

Python

import requests

res = requests.get(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/cost",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["total_credits"], data["summary"]["contained"]["avg_credits"])

Odpowiedź

{
  "success": true,
  "contact_id": "contact_abc123",
  "total_credits": 23,
  "refunded_credits": 0,
  "unattributed_credits": 0,
  "by_session": [
    {
      "session_id": "hpWKxuTSXIKlylze5Ulx",
      "start": "2026-09-21T00:00:00.000Z",
      "end": "2026-09-24T17:41:52.052Z",
      "status": "ChatSessionClosed",
      "tag": null,
      "credits": 7,
      "actions": 7,
      "outcome": "handed_off"
    },
    {
      "session_id": "5kKnkI3DD4THIh2YVjey",
      "start": "2026-09-09T00:00:00.000Z",
      "end": "2026-09-11T22:42:34.056Z",
      "status": "ChatSessionClosed",
      "tag": null,
      "credits": 13,
      "actions": 14,
      "outcome": "contained"
    }
  ],
  "by_type": [
    { "type": "AI Chat Conclude Evaluation", "credits": 8, "actions": 8 },
    { "type": "AI Tool Use", "credits": 4, "actions": 4 },
    { "type": "AI Message", "credits": 2, "actions": 2 }
  ],
  "summary": {
    "contained": { "sessions": 1, "credits": 13, "avg_credits": 13 },
    "handed_off": { "sessions": 1, "credits": 7, "avg_credits": 7 },
    "no_ai": { "sessions": 0, "credits": 0, "avg_credits": 0 }
  },
  "sessions_truncated": false
}

Uwagi terenowe:

  • total_credits zlicza każdą opłatę przypisaną do kontaktu (odpowiedzi AI, wywołania narzędzi, tagi, działania następcze, podsumowania, kroki oceny w tle, opłaty za szablony i dostarczenie) po odjęciu zwrotów kosztów dla tego kontaktu. Przyznane kredyty, doładowania i odnowienia nigdy nie są przypisywane do kontaktu. Testy w środowisku Playground są pomijane.
  • Opłata trafia do konwersacji, w której oknie czasowym się mieści. Okno trwa od rozpoczęcia konwersacji do jej zamknięcia lub rozpoczęcia kolejnej, dzięki czemu żadna opłata nie jest liczona dwukrotnie. Opłaty spoza każdego okna znajdują się w unattributed_credits (oraz w sumie całkowitej).
  • outcome: contained oznacza, że AI odpowiedziało i nikt z Twojego zespołu nie musiał interweniować; handed_off oznacza, że ktoś wysłał wiadomość po odpowiedzi AI lub AI zaalarmowało człowieka; no_ai oznacza, że AI nigdy nie odpowiedziało w danej konwersacji.
  • Wyświetlanych jest do 200 konwersacji, od najnowszej; sessions_truncated to true, gdy jest ich więcej.
  • W przypadku klienta agencji przekaż sub_account_id; liczby zostaną podane w kredytach tego klienta.
  • creditsUsed w Pobierz statystyki kontaktu to bieżący licznik utrzymywany dla kontaktu. Ten punkt końcowy przelicza wartość na podstawie rejestru kredytów, więc obie wartości mogą się nieco różnić, głównie w przypadku starszych kontaktów.
  • Członkowie zespołu potrzebują uprawnień do rozliczeń. Kontakt, którego nie ma na Twoim koncie, zwróci 404; 503 oznacza, że obliczenie wartości nie jest obecnie możliwe, spróbuj ponownie za chwilę.

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",
      "number_hidden": false,
      "whatsapp_lid": null,
      "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",
      "ad_attribution": null
    }
  ],
  "next_cursor": "contact_abc123"
}

Każdy kontakt zawiera ad_attribution: kliknięcie w reklamę, które doprowadziło do Twojej witryny, dopasowane do kontaktu, z tymi samymi polami co adAttribution w Pobierz kontakt według ID, lub null, gdy go nie ma.

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 ma odpowiadać temu kontaktowi.
is_private Oznacz jako prywatny. Ustawienie tej wartości na true wyłącza również 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 typu follow-up dla tego kontaktu (szybkie, cykliczne i dla zimnych leadów), podczas gdy AI nadal odpowiada na wiadomości od nich. Przydatne po dokonaniu zakupu. Pozostaje wyłączone, dopóki nie ustawisz z powrotem na false.
lead_profile Notatki tekstowe dotyczące leada.
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. Pola typowane są walidowane, a błędna wartość odrzuca żądanie z błędem field_errors — zobacz Typy pól niestandardowych.

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 tylko tier — 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 samą etykietą — zmiany jej nazwy lub usunięcia z konta — w przeciwieństwie do przypisywania lub usuwania etykiety u jednego kontaktu (zobacz Dodawanie lub usuwanie etykiet powyżej). Każda etykieta na Twoim koncie posiada identyfikator (tagId): ten widoczny w menedżerze etykiet w Twoim panelu oraz ten zwracany jako tag_id na najwyższym poziomie odpowiedzi podczas tworzenia etykiety 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 — jednak podczas wysyłania listId, kontakt, który już posiadasz, jest nadal dodawany do tej listy i liczony w ramach added_to_list, więc ponowny import wypełnia listę bez wprowadzania zmian w samym kontakcie. Wyślij updateExisting: true, aby zaktualizować te kontakty: pola obecne w rekordzie nadpisują dane kontaktu (first_name, last_name, email, lead_profile oraz custom_fields są scalane klucz po kluczu), tags są dodawane, a kontakt jest przypisywany 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 mają zostać dodane wszystkie kontakty z tego żądania — zarówno utworzone, zaktualizowane, jak i te pominięte jako duplikaty. Musi to być lista istniejąca na Twoim koncie.
defaultChannel Nie Kanał przypisany do rekordów, w których pominięto channel. Jedna z wartości: 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": [],
  "added_to_list": 0,
  "added_to_list_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": [],
  "added_to_list": 1,
  "added_to_list_contact_ids": ["contact_def456"],
  "skipped": [
    { "index": 1, "phone_number": "+12025551235", "reason": "duplicate" }
  ]
}

Pominięty wiersz nadal dołączył do listId, co jest tym, co zlicza added_to_list — żadne inne dane tego kontaktu nie zostały zmienione. Przy użyciu updateExisting: true to samo żądanie raportuje istniejący kontakt w ramach 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 csvStoragePath przed 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 status będzie "completed", otrzymasz export_id oraz contact_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 422 oraz wyjaśnieniem w polu error.

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.


Wyślij wiadomość uzupełniającą AI do kontaktu

POST /contacts/{contactId}/ai-follow-up

Sprawia, że agent AI pisze jedną wiadomość własnym głosem, na podstawie dotychczasowej konwersacji oraz podanej przez Ciebie instrukcji, a następnie wysyła ją na kanale kontaktu. Działa to tak samo jak krok automatyzacji Wyślij wiadomość uzupełniającą AI i kosztuje tyle samo kredytów co wiadomość uzupełniająca AI.

Pole Wymagane Opis
instruction Tak Co wiadomość powinna zrobić, opisane prostymi słowami, do 2000 znaków. Na przykład: „Przypomnij im, że ich zarezerwowany link wygasa dziś wieczorem i zapytaj, czy chcą go zatwierdzić”.
agentId Nie Agent, który napisze wiadomość. Pozostaw puste, aby użyć agenta, który już obsługuje dany kontakt.
mustContain Nie Lista maksymalnie 5 fraz lub linków (każdy do 500 znaków), które wiadomość musi zawierać słowo w słowo. Jeśli AI pominie którykolwiek z nich, wiadomość nie zostanie wysłana, a skipReason będzie miało wartość text_check_failed.
respectMessagingWindow Nie Domyślnie true. W przypadku WhatsApp Business API, Instagrama i Messengera, pomiń, jeśli ostatnia wiadomość od kontaktu została wysłana ponad 24 godziny temu.
skipWhenAiPaused Nie Domyślnie true. Pomiń, jeśli AI jest wyłączone dla tego kontaktu.

cURL

curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/ai-follow-up" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instruction": "Remind them their reserved link expires tonight and ask if they want to lock it in",
    "mustContain": ["https://example.com/r/abc123"]
  }'

JavaScript

const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/ai-follow-up", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    instruction: "Remind them their reserved link expires tonight and ask if they want to lock it in",
    mustContain: ["https://example.com/r/abc123"],
  }),
});
const data = await res.json();
if (!data.sent) console.log("Skipped:", data.skipReason);

Odpowiedź po wysłaniu wiadomości:

{
  "sent": true,
  "messageId": "ai-follow-up-aB3dE5fG7hI9jK1l",
  "text": "Hi Ada, quick reminder: your reserved spot is held until 20:00 tonight. Want to lock it in? https://example.com/r/abc123",
  "agentId": "agent_abc123"
}

Odpowiedź po pominięciu:

{
  "sent": false,
  "skipReason": "window_closed"
}

Oba zwracają status 200. skipReason to jeden z no_agent (brak agenta obsługującego kontakt i nie podano żadnego), dnd (nie przeszkadzać), ai_paused, window_closed (poza 24-godzinnym oknem lub kontakt nigdy nie napisał do Ciebie na tym kanale), no_credits, text_check_failed (brakował elementu mustContain), no_text (AI nie napisało nic użytecznego) lub linkedin_gap (lead z LinkedIn otrzymał automatyczną wiadomość mniej niż 24 godziny temu; odpowiedź zawiera wtedy również nextAllowedAt, czas, kiedy może zostać wysłana kolejna). Pominięcie jest normalną odpowiedzią, a nie błędem, więc sprawdź sent, zanim założysz, że wiadomość została wysłana. Pominięte wywołanie nie zużywa kredytów.

Treść, w której brakuje instruction lub która zawiera pole o niewłaściwym typie, otrzyma 400. Kontakt lub agent, którego nie ma na Twoim koncie, otrzyma 404. Błędy są zwracane jako { "success": false, "error": "..." }. Klucz członka zespołu wymaga uprawnień do edycji kontaktów.


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 w automatyzacjach.

Pole Wymagane Opis
agentId Tak Identyfikator agenta AI, który powinien przejąć konwersację, lub null, aby wyczyścić przypisanie, dzięki czemu konwersacja wróci do skrzynki odbiorczej Twojego zespołu.
triggerAIResponse Nie true sprawia, że nowo przypisany agent natychmiast odpowiada na ostatnie nieodebrane wiadomości kontaktu. Wartością domyślną jest false. Jeśli kontakt był już przypisany do tego agenta, a jego ostatnia wiadomość została już odebrana, odpowiedź nie jest inicjowana: odpowiedź zawiera aiResponseTriggered: false oraz aiTriggerError z wyjaśnieniem przyczyny.

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 404 lub 403. 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
}

Wyświetl pola niestandardowe

GET /users/me/custom-fields — zwraca klucze pól niestandardowych zarejestrowanych na Twoim koncie (tych, które są widoczne jako kolumny oraz w formularzu kontaktowym), dzięki czemu integracja może oferować je jako opcje do wyboru zamiast zgadywania.

curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/users/me/custom-fields?apiKey=YOUR_API_KEY"

Odpowiedź (200)

{ "success": true, "custom_fields": ["tier", "company", "birthday"] }

Ustaw listę za pomocą PUT /users/me/custom-fields i tego samego kształtu tablicy.


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.


Typy pól niestandardowych

Każde pole niestandardowe na koncie posiada typ: text (domyślny), number, date, select (lista rozwijana ze stałymi opcjami) lub boolean (pole wyboru). Pole typowane jest walidowane przy każdym zapisie — tworzeniu, aktualizacji, imporcie, w silniku automatyzacji oraz podczas zbierania pól przez AI — a jego wartość jest przechowywana w ujednoliconej formie, dzięki czemu filtry i warunki automatyzacji porównują wartości tego samego typu:

Typ Przechowywane jako Akceptowane na wejściu
text Cokolwiek wyślesz Cokolwiek (zachowanie bez zmian)
number Liczba JSON 42, "42", "19,99"
date "YYYY-MM-DD" 2026-02-01, data-godzina ISO (część daty jest zachowana), 01/02/2026 (dzień pierwszy lub miesiąc pierwszy zgodnie z formatem daty konta; jednoznaczna wartość taka jak 13/02/2026 zawsze wygrywa), February 1, 2026, 1 de febrero de 2026
select Jedna z opcji pola, w pisowni danej opcji Dowolne dopasowanie opcji bez rozróżniania wielkości liter
boolean true / false true/false, yes/no, 1/0, si/no, ja/nein …

Wysłanie null lub pustego ciągu znaków czyści pole typowane. Klucze, które nie są zarejestrowane na koncie, oraz pola text są przechowywane dokładnie tak, jak zostały wysłane.

Odczyt definicji pól

GET /users/me/custom-fields

{
  "success": true,
  "custom_fields": ["company", "birthday", "plan", "vip"],
  "definitions": [
    { "key": "company", "type": "text" },
    { "key": "birthday", "type": "date" },
    { "key": "plan", "type": "select", "options": ["Free", "Pro", "Enterprise"] },
    { "key": "vip", "type": "boolean" }
  ]
}

custom_fields to zwykła lista kluczy (niezmieniona dla starszych klientów); definitions zawiera typ dla każdego klucza.

Ustawianie definicji pól

PUT /users/me/custom-fields

Zastępuje całą listę. Każdy wpis to albo sam klucz (zachowuje typ, który pole już posiada, text dla nowego), albo obiekt z key, type oraz, dla select, options (od 1 do 100 unikalnych opcji, do 64 znaków każda). Maksymalnie 50 pól; klucze używają małych liter, cyfr i podkreślników oraz zaczynają się od litery lub podkreślnika.

curl -X PUT "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/users/me/custom-fields?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customFields": [
      "company",
      { "key": "birthday", "type": "date" },
      { "key": "plan", "type": "select", "options": ["Free", "Pro", "Enterprise"] },
      { "key": "vip", "type": "boolean" }
    ]
  }'

Zmiana typu pola nie powoduje nadpisania wartości już zapisanych w kontaktach; są one walidowane przy następnym zapisie.

Błędy walidacji

Tworzenie lub aktualizacja kontaktu, którego wartości pól niestandardowych nie pasują do ich typu, jest odrzucane w całości z błędem 400:

{
  "success": false,
  "error": "Invalid custom field value(s): birthday: \"birthday\" must be a date in YYYY-MM-DD format (for example 1990-02-01).",
  "field_errors": [
    { "key": "birthday", "message": "\"birthday\" must be a date in YYYY-MM-DD format (for example 1990-02-01)." }
  ]
}

W przypadku importu masowego rekord z nieprawidłową wartością jest zgłaszany jako nieudany z tym samym komunikatem, a reszta partii jest przetwarzana.


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) lub any (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.