Dokumentacja API
Połącz Convs z własnym CRM-em, sklepem lub hurtownią danych: czytaj osoby i leady, zmieniaj etapy, wysyłaj konwersje do kolejki Meta i odbieraj zdarzenia webhookami.
- Wersja
- 1.0.0
- Adres bazowy
- https://app.convs.io/api/v1
- OpenAPI
- Specyfikacja OpenAPI (JSON)
Spis treści
Szybki start
- Utwórz klucz w panelu: Konfiguracja → API. Klucze tworzą właściciele i administratorzy organizacji. Pełny klucz zobaczysz tylko raz, więc skopiuj go od razu.
- Każdy adres zaczyna się od
https://app.convs.io/api/v1. Odpowiedzi są w JSON. - Sprawdź klucz wywołaniem
GET /me. Nie wymaga żadnych uprawnień i zwraca organizację, nazwę klucza, uprawnienia i termin ważności.
curl -H "Authorization: Bearer cvs_live_…" \
https://app.convs.io/api/v1/meW pozostałych przykładach klucz jest w zmiennej środowiskowej API_KEY (export API_KEY=cvs_live_…). Nie umieszczaj klucza w kodzie strony ani aplikacji mobilnej: służy tylko do połączeń serwer–serwer.
Uwierzytelnianie
Każde żądanie wysyła klucz organizacji w nagłówku Authorization: Bearer cvs_live_…. Klucz należy do jednej organizacji i widzi tylko jej dane.
Pełny klucz pokazujemy tylko raz, przy tworzeniu. Przechowujemy wyłącznie jego skrót, więc nie da się go odzyskać: zgubiony klucz unieważnij i utwórz nowy.
Klucz możesz w każdej chwili unieważnić w panelu i możesz ustawić mu termin ważności. Unieważniony klucz dostaje 401 key_revoked, wygasły 401 key_expired.
Klucz ma uprawnienia (scopes). Uprawnienie :write (i leads:answers) obejmuje też :read tego samego obszaru. contacts:* i leads:answers zwracają dane osobowe. Brak uprawnienia to 403 insufficient_scope z polem details.required_scope.
| Uprawnienie | Na co pozwala | Endpointy |
|---|---|---|
contacts:read | Odczyt osób ze strony Klienci (imiona, telefony, e-maile — dane osobowe). | |
contacts:write | Dodawanie i zmiana osób: dane, etap, notatki, tagi, blokada SMS. | |
leads:read | Odczyt leadów z formularzy Meta, bez odpowiedzi z formularza. | |
leads:answers | Jak leads:read, a do tego odpowiedzi z formularza (answers) — dane osobowe. | |
events:read | Odczyt konwersji i statusu ich wysyłek do Meta. | |
events:write | Wysyłanie konwersji serwer–serwer do kolejki. | |
campaigns:read | Raport kampanii. | |
creatives:read | Raport kreacji. | |
jobs:read | Odczyt zadań w tle. | |
webhooks:read | Odczyt webhooków i historii ich wysyłek. | |
webhooks:write | Dodawanie, zmiana, usuwanie i testowanie webhooków. |
Błędy
Każdy błąd ma ten sam kształt: {"error": {"code", "message", "details?"}}.
code jest stały i nigdy nie jest tłumaczony, więc na nim opieraj obsługę błędów. message jest dla człowieka, w języku z nagłówka Accept-Language: domyślnie polski, en dla angielskiego. details pojawia się tylko tam, gdzie są dodatkowe dane, np. required_scope.
{
"error": {
"code": "insufficient_scope",
"message": "Klucz API nie ma uprawnienia contacts:write.",
"details": {
"required_scope": "contacts:write"
}
}
}| Kod | HTTP | Znaczenie |
|---|---|---|
unauthorized | 401 | Brak klucza, zły format albo nieznany klucz. |
key_revoked | 401 | Klucz został unieważniony. |
key_expired | 401 | Minął termin ważności klucza. |
insufficient_scope | 403 | Klucz nie ma potrzebnego uprawnienia (details.required_scope). |
rate_limited | 429 | Ponad 120 żądań na minutę tym kluczem; odczekaj Retry-After sekund. |
invalid_json | 400 | Treść nie jest poprawnym JSON-em albo zawiera nieznane pole. |
validation_error | 400 | Nieprawidłowa wartość pola lub parametru; opis mówi, co poprawić. |
invalid_cursor | 400 | cursor nie pochodzi z poprzedniej strony tej samej listy. |
not_found | 404 | Brak takiego rekordu w Twojej organizacji. |
route_not_found | 404 | Nie ma takiego endpointu. |
conflict | 409 | Operacja kłóci się z aktualnym stanem rekordu. |
contact_exists | 409 | Osoba z tym telefonem lub e-mailem już istnieje (details.contact_id). |
contact_merged | 409 | Karta została scalona z inną (details.merged_into). |
stage_conflict | 409 | Etapu nie da się teraz zmienić w ten sposób. |
event_conflict | 409 | Zdarzenie koliduje z już przyjętym. |
source_paused | 409 | Źródło jest wstrzymane. |
limit_reached | 409 | Osiągnięty limit, np. 10 webhooków na organizację. |
idempotency_key_reused | 422 | Ten sam Idempotency-Key z inną treścią żądania. |
idempotency_in_progress | 409 | Żądanie z tym Idempotency-Key jeszcze trwa; ponów za chwilę. |
payload_too_large | 413 | Treść żądania ponad 64 KB. |
internal_error | 500 | Błąd po naszej stronie; ponów żądanie później. |
Paginacja
Listy zwracają {"data": [...], "next_cursor", "has_more"}. Rozmiar strony ustawiasz parametrem limit (1–100, domyślnie 25).
Następną stronę pobierasz, przekazując next_cursor z poprzedniej odpowiedzi jako cursor. Gdy has_more jest false, to koniec listy.
Kolejność to updated_at, a przy remisie identyfikator: order=desc od najnowszych (domyślnie) albo order=asc.
updated_since (ISO 8601) zwraca tylko rekordy zmienione w tym czasie lub później. Do synchronizacji przyrostowej zapisz czas, w którym zaczynasz synchronizację, przejdź przez wszystkie strony do końca i użyj zapisanego czasu jako updated_since przy następnej synchronizacji.
Wszystkie osoby zmienione od wskazanego czasu
cursor=""
while :; do
page=$(curl -s -G "https://app.convs.io/api/v1/contacts" \
-H "Authorization: Bearer $API_KEY" \
--data-urlencode "limit=100" \
--data-urlencode "updated_since=2026-10-01T00:00:00Z" \
${cursor:+--data-urlencode "cursor=$cursor"})
echo "$page" | jq -c '.data[]'
[ "$(echo "$page" | jq -r '.has_more')" = "true" ] || break
cursor=$(echo "$page" | jq -r '.next_cursor')
doneconst records = []
let cursor = null
do {
const params = new URLSearchParams({ limit: '100', updated_since: '2026-10-01T00:00:00Z' })
if (cursor) params.set('cursor', cursor)
const response = await fetch(`https://app.convs.io/api/v1/contacts?${params}`, {
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
})
if (!response.ok) throw new Error((await response.json()).error.message)
const page = await response.json()
records.push(...page.data)
cursor = page.has_more ? page.next_cursor : null
} while (cursor)import os
import requests
records = []
params = {"limit": 100, "updated_since": "2026-10-01T00:00:00Z"}
while True:
response = requests.get(
"https://app.convs.io/api/v1/contacts",
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
params=params,
timeout=30,
)
response.raise_for_status()
page = response.json()
records.extend(page["data"])
if not page["has_more"]:
break
params["cursor"] = page["next_cursor"]<?php
$records = [];
$params = ['limit' => 100, 'updated_since' => '2026-10-01T00:00:00Z'];
do {
$ch = curl_init('https://app.convs.io/api/v1/contacts?' . http_build_query($params));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('API_KEY')],
]);
$page = json_decode(curl_exec($ch), true);
curl_close($ch);
if (isset($page['error'])) {
throw new RuntimeException($page['error']['message']);
}
$records = array_merge($records, $page['data']);
$params['cursor'] = $page['next_cursor'];
} while ($page['has_more']);Limity i formaty
- Limit: 120 żądań na minutę na klucz. Każda odpowiedź ma nagłówki
X-RateLimit-Limit,X-RateLimit-RemainingiX-RateLimit-Reset. - Po przekroczeniu dostajesz
429 rate_limitedz nagłówkiemRetry-After(sekundy). Odczekaj tyle i ponów. - Treść żądania może mieć najwyżej 64 KB, inaczej
413 payload_too_large. - Czasy w odpowiedziach są w ISO 8601 w UTC, np.
2026-10-08T10:00:00Z.
Idempotencja
- Każdy
POSTprzyjmuje nagłówekIdempotency-Key(1–255 widocznych znaków ASCII). Użyj wartości związanej z operacją, np. UUID zapisanego razem z rekordem po Twojej stronie. - Powtórzenie żądania z tym samym kluczem i tą samą treścią w ciągu 24 godzin zwraca zapisaną odpowiedź z nagłówkiem
Idempotent-Replayed: true, bez ponownego wykonania operacji. - Ten sam klucz z inną treścią to
422 idempotency_key_reused. Gdy pierwsze żądanie jeszcze trwa, dostajesz409 idempotency_in_progress. - Odpowiedzi 5xx i 429 nie są zapisywane, więc po nich możesz bezpiecznie ponowić żądanie z tym samym kluczem.
Endpointy
Klucze
Używany klucz.
/meOpis używanego klucza
Organizacja, nazwa klucza, uprawnienia i termin ważności. Bezpieczne pierwsze wywołanie do sprawdzenia nowego klucza; nie wymaga uprawnień.
Uprawnienie: bez uprawnień
Odpowiedzi
200OKPola odpowiedziNazwa Opis organizationobjectorganization.idstringorganization.namestringkeyobjectkey.idstringkey.namestringkey.prefixstringkey.scopesstring[]key.expires_atstring (date-time) | nullrate_limitobjectrate_limit.per_minuteinteger400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/me" \
-H "Authorization: Bearer $API_KEY"const response = await fetch('https://app.convs.io/api/v1/me', {
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
},
})
if (!response.ok) throw new Error((await response.json()).error.message)
const data = await response.json()
console.log(data)import os
import requests
response = requests.get(
"https://app.convs.io/api/v1/me",
headers={
"Authorization": f"Bearer {os.environ['API_KEY']}",
},
timeout=30,
)
response.raise_for_status()
print(response.json())<?php
$ch = curl_init('https://app.convs.io/api/v1/me');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('API_KEY'),
],
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException($data['error']['message']);
}
print_r($data);Osoby
Osoby ze strony Klienci.
/contactsLista osób
Osoby ze strony Klienci (scalone karty są pominięte). Filtruj po etapie, tagu, dokładnym e-mailu lub telefonie albo reklamie, z której przyszły.
Uprawnienie: contacts:read
Parametry
| Nazwa | Opis |
|---|---|
limitzapytanieinteger | Rozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100 |
cursorzapytaniestring | next_cursor z poprzedniej strony. |
orderzapytaniestring | Sortowanie po updated_at (potem id): desc od najnowszych (domyślnie) lub asc.Wartości: asc, descDomyślnie: desc |
updated_sincezapytaniestring (date-time) | Tylko rekordy zmienione w tym czasie ISO 8601 lub później. |
stagezapytaniestring | Etap.Wartości: new, contacted, qualified, sold, rejected |
tagzapytaniestring | Tag. |
emailzapytaniestring | Dokładny e-mail (dopasowanie po skrócie). |
phonezapytaniestring | Dokładny telefon (dopasowanie po skrócie). |
campaignzapytaniestring | Osoby ze zgłoszeniem z tej kampanii Meta. |
adsetzapytaniestring | …z tego zestawu reklam. |
adzapytaniestring | …z tej reklamy. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis dataContact[]Wymaganydata[].idstringIdentyfikator osoby. data[].namestringImię i nazwisko. data[].phonestringTelefon w formacie E.164, pusty gdy nieznany. data[].emailstringE-mail, pusty gdy nieznany. data[].stagestringEtap sprzedaży.Wartości: new,contacted,qualified,sold,rejecteddata[].cycleintegerNumer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl. data[].tagsstring[]Tagi. data[].sms_optoutbooleanPrawda, gdy SMS-y do tej osoby są zablokowane. data[].first_sourcestringSkąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…). data[].first_adAdSource | nullPierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego. data[].first_ad.platformstringPlatforma emisji podana przez Meta (facebook, instagram…). data[].first_ad.campaign_idstringIdentyfikator kampanii Meta. data[].first_ad.campaign_namestringNazwa kampanii. data[].first_ad.adset_idstringIdentyfikator zestawu reklam Meta. data[].first_ad.adset_namestringNazwa zestawu reklam. data[].first_ad.ad_idstringIdentyfikator reklamy Meta. data[].first_ad.ad_namestringNazwa reklamy. data[].owner_idstring | nullIdentyfikator użytkownika — opiekuna osoby. data[].last_activity_atstring (date-time) | nullCzas ostatniej aktywności. data[].created_atstring (date-time)Czas utworzenia. data[].updated_atstring (date-time)Ostatnia zmiana; używaj z updated_since.next_cursorstring | nullWymaganyPrzekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.has_morebooleanWymaganyPrawda, gdy istnieje kolejna strona. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/contacts" \
-H "Authorization: Bearer $API_KEY"const response = await fetch('https://app.convs.io/api/v1/contacts', {
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
},
})
if (!response.ok) throw new Error((await response.json()).error.message)
const data = await response.json()
console.log(data)import os
import requests
response = requests.get(
"https://app.convs.io/api/v1/contacts",
headers={
"Authorization": f"Bearer {os.environ['API_KEY']}",
},
timeout=30,
)
response.raise_for_status()
print(response.json())<?php
$ch = curl_init('https://app.convs.io/api/v1/contacts');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('API_KEY'),
],
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException($data['error']['message']);
}
print_r($data);/contactsDodaj osobę
Dodaje osobę jak „Dodaj osobę” w panelu (opiekun z round robin, gdy jest włączony).
Uprawnienie: contacts:write
Parametry
| Nazwa | Opis |
|---|---|
Idempotency-Keynagłówekstring | Unikalny klucz (1–255 widocznych znaków ASCII). Powtórzenie POST z tym samym kluczem i treścią w ciągu 24 godzin zwraca zapisaną odpowiedź z Idempotent-Replayed: true.Maks. długość: 255 |
Treść żądania application/json
| Nazwa | Opis |
|---|---|
namestring | Imię i nazwisko (do 200 znaków).Maks. długość: 200 |
phonestring | Telefon z numerem kierunkowym, np. +48 600 857 482, albo 9 cyfr. |
emailstring | Adres e-mail.Maks. długość: 254 |
tagsstring[] | Tagi. |
Odpowiedzi
201UtworzonoPola odpowiedziNazwa Opis idstringIdentyfikator osoby. namestringImię i nazwisko. phonestringTelefon w formacie E.164, pusty gdy nieznany. emailstringE-mail, pusty gdy nieznany. stagestringEtap sprzedaży.Wartości: new,contacted,qualified,sold,rejectedcycleintegerNumer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl. tagsstring[]Tagi. sms_optoutbooleanPrawda, gdy SMS-y do tej osoby są zablokowane. first_sourcestringSkąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…). first_adAdSource | nullPierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego. first_ad.platformstringPlatforma emisji podana przez Meta (facebook, instagram…). first_ad.campaign_idstringIdentyfikator kampanii Meta. first_ad.campaign_namestringNazwa kampanii. first_ad.adset_idstringIdentyfikator zestawu reklam Meta. first_ad.adset_namestringNazwa zestawu reklam. first_ad.ad_idstringIdentyfikator reklamy Meta. first_ad.ad_namestringNazwa reklamy. owner_idstring | nullIdentyfikator użytkownika — opiekuna osoby. last_activity_atstring (date-time) | nullCzas ostatniej aktywności. created_atstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana; używaj z updated_since.400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).413Treść ponad 64 KB (payload_too_large).422Idempotency-Key użyty z inną treścią (idempotency_key_reused).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X POST "https://app.convs.io/api/v1/contacts" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b" \
-H "Content-Type: application/json" \
-d '{
"name": "Anna Nowak",
"phone": "+48600100200",
"email": "anna@example.com",
"tags": [
"vip"
]
}'const response = await fetch('https://app.convs.io/api/v1/contacts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
'Idempotency-Key': '5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Anna Nowak",
"phone": "+48600100200",
"email": "anna@example.com",
"tags": [
"vip"
]
}),
})
if (!response.ok) throw new Error((await response.json()).error.message)
const data = await response.json()
console.log(data)import os
import requests
response = requests.post(
"https://app.convs.io/api/v1/contacts",
headers={
"Authorization": f"Bearer {os.environ['API_KEY']}",
"Idempotency-Key": "5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b",
},
json={
"name": "Anna Nowak",
"phone": "+48600100200",
"email": "anna@example.com",
"tags": ["vip"],
},
timeout=30,
)
response.raise_for_status()
print(response.json())<?php
$ch = curl_init('https://app.convs.io/api/v1/contacts');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('API_KEY'),
'Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Anna Nowak',
'phone' => '+48600100200',
'email' => 'anna@example.com',
'tags' => ['vip'],
]),
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException($data['error']['message']);
}
print_r($data);/contacts/{id}Pobierz osobę
Scalona karta zwraca 409 contact_merged z details.merged_into.
Uprawnienie: contacts:read
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis idstringIdentyfikator osoby. namestringImię i nazwisko. phonestringTelefon w formacie E.164, pusty gdy nieznany. emailstringE-mail, pusty gdy nieznany. stagestringEtap sprzedaży.Wartości: new,contacted,qualified,sold,rejectedcycleintegerNumer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl. tagsstring[]Tagi. sms_optoutbooleanPrawda, gdy SMS-y do tej osoby są zablokowane. first_sourcestringSkąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…). first_adAdSource | nullPierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego. first_ad.platformstringPlatforma emisji podana przez Meta (facebook, instagram…). first_ad.campaign_idstringIdentyfikator kampanii Meta. first_ad.campaign_namestringNazwa kampanii. first_ad.adset_idstringIdentyfikator zestawu reklam Meta. first_ad.adset_namestringNazwa zestawu reklam. first_ad.ad_idstringIdentyfikator reklamy Meta. first_ad.ad_namestringNazwa reklamy. owner_idstring | nullIdentyfikator użytkownika — opiekuna osoby. last_activity_atstring (date-time) | nullCzas ostatniej aktywności. created_atstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana; używaj z updated_since.400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/contacts/abc123" \
-H "Authorization: Bearer $API_KEY"/contacts/{id}Zmień dane osoby
Zmienia imię, telefon, e-mail lub tagi; każda zmiana to wpis w historii.
Uprawnienie: contacts:write
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Treść żądania application/json
| Nazwa | Opis |
|---|---|
namestring | Imię i nazwisko. |
phonestring | Telefon; pusty tekst usuwa go (musi zostać telefon lub e-mail). |
emailstring | E-mail; pusty tekst usuwa go. |
tagsstring[] | Zastępuje wszystkie tagi. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis idstringIdentyfikator osoby. namestringImię i nazwisko. phonestringTelefon w formacie E.164, pusty gdy nieznany. emailstringE-mail, pusty gdy nieznany. stagestringEtap sprzedaży.Wartości: new,contacted,qualified,sold,rejectedcycleintegerNumer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl. tagsstring[]Tagi. sms_optoutbooleanPrawda, gdy SMS-y do tej osoby są zablokowane. first_sourcestringSkąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…). first_adAdSource | nullPierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego. first_ad.platformstringPlatforma emisji podana przez Meta (facebook, instagram…). first_ad.campaign_idstringIdentyfikator kampanii Meta. first_ad.campaign_namestringNazwa kampanii. first_ad.adset_idstringIdentyfikator zestawu reklam Meta. first_ad.adset_namestringNazwa zestawu reklam. first_ad.ad_idstringIdentyfikator reklamy Meta. first_ad.ad_namestringNazwa reklamy. owner_idstring | nullIdentyfikator użytkownika — opiekuna osoby. last_activity_atstring (date-time) | nullCzas ostatniej aktywności. created_atstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana; używaj z updated_since.400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).413Treść ponad 64 KB (payload_too_large).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X PATCH "https://app.convs.io/api/v1/contacts/abc123" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Anna Nowak",
"phone": "+48600100200",
"email": "anna@example.com",
"tags": [
"vip"
]
}'/contacts/{id}/stageZmień etap
Przesuwa osobę i w tej samej transakcji wszystkie otwarte zgłoszenia bieżącego cyklu; zgłoszenia z aktywnym przepływem dostają zdarzenie konwersji Meta w kolejce. Ta sama ścieżka co „Zmień etap” w panelu; uruchamiają się automatyzacje etapu.
Uprawnienie: contacts:write
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Idempotency-Keynagłówekstring | Unikalny klucz (1–255 widocznych znaków ASCII). Powtórzenie POST z tym samym kluczem i treścią w ciągu 24 godzin zwraca zapisaną odpowiedź z Idempotent-Replayed: true.Maks. długość: 255 |
Treść żądania application/json
| Nazwa | Opis |
|---|---|
stagestringWymagany | Docelowy etap.Wartości: new, contacted, qualified, sold, rejected |
valuenumber | Wartość sprzedaży (dla sold); liczona raz, na najnowszym zgłoszeniu, którego zdarzenie Meta trafia do kolejki. |
currencystring | Waluta ISO 4217 dla value, np. PLN. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis contactContactcontact.idstringIdentyfikator osoby. contact.namestringImię i nazwisko. contact.phonestringTelefon w formacie E.164, pusty gdy nieznany. contact.emailstringE-mail, pusty gdy nieznany. contact.stagestringEtap sprzedaży.Wartości: new,contacted,qualified,sold,rejectedcontact.cycleintegerNumer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl. contact.tagsstring[]Tagi. contact.sms_optoutbooleanPrawda, gdy SMS-y do tej osoby są zablokowane. contact.first_sourcestringSkąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…). contact.first_adAdSource | nullPierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego. contact.first_ad.platformstringPlatforma emisji podana przez Meta (facebook, instagram…). contact.first_ad.campaign_idstringIdentyfikator kampanii Meta. contact.first_ad.campaign_namestringNazwa kampanii. contact.first_ad.adset_idstringIdentyfikator zestawu reklam Meta. contact.first_ad.adset_namestringNazwa zestawu reklam. contact.first_ad.ad_idstringIdentyfikator reklamy Meta. contact.first_ad.ad_namestringNazwa reklamy. contact.owner_idstring | nullIdentyfikator użytkownika — opiekuna osoby. contact.last_activity_atstring (date-time) | nullCzas ostatniej aktywności. contact.created_atstring (date-time)Czas utworzenia. contact.updated_atstring (date-time)Ostatnia zmiana; używaj z updated_since.meta_events_queuedintegerZdarzenia konwersji Meta dodane do kolejki dla otwartych zgłoszeń (kolejka je wyśle; to nie jest potwierdzenie od Meta). leads_without_sendintegerOtwarte zgłoszenia przesunięte bez zdarzenia Meta (brak aktywnego przepływu dla etapu). 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).413Treść ponad 64 KB (payload_too_large).422Idempotency-Key użyty z inną treścią (idempotency_key_reused).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X POST "https://app.convs.io/api/v1/contacts/abc123/stage" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b" \
-H "Content-Type: application/json" \
-d '{
"stage": "sold",
"value": 1200,
"currency": "PLN"
}'const response = await fetch('https://app.convs.io/api/v1/contacts/abc123/stage', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
'Idempotency-Key': '5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"stage": "sold",
"value": 1200,
"currency": "PLN"
}),
})
if (!response.ok) throw new Error((await response.json()).error.message)
const data = await response.json()
console.log(data)import os
import requests
response = requests.post(
"https://app.convs.io/api/v1/contacts/abc123/stage",
headers={
"Authorization": f"Bearer {os.environ['API_KEY']}",
"Idempotency-Key": "5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b",
},
json={
"stage": "sold",
"value": 1200,
"currency": "PLN",
},
timeout=30,
)
response.raise_for_status()
print(response.json())<?php
$ch = curl_init('https://app.convs.io/api/v1/contacts/abc123/stage');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('API_KEY'),
'Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'stage' => 'sold',
'value' => 1200,
'currency' => 'PLN',
]),
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException($data['error']['message']);
}
print_r($data);/contacts/{id}/notesDodaj notatkę
Dodaje notatkę, telefon lub spotkanie do historii osoby.
Uprawnienie: contacts:write
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Idempotency-Keynagłówekstring | Unikalny klucz (1–255 widocznych znaków ASCII). Powtórzenie POST z tym samym kluczem i treścią w ciągu 24 godzin zwraca zapisaną odpowiedź z Idempotent-Replayed: true.Maks. długość: 255 |
Treść żądania application/json
| Nazwa | Opis |
|---|---|
kindstring | Rodzaj wpisu.Wartości: note, call, meetingDomyślnie: note |
textstringWymagany | Treść, 1–5000 znaków.Maks. długość: 5000 |
timestring (date-time) | Kiedy to było (domyślnie teraz); nie w przyszłości. |
Odpowiedzi
201UtworzonoPola odpowiedziNazwa Opis idstringIdentyfikator wpisu historii. contact_idstringIdentyfikator osoby. kindstringRodzaj wpisu. textstringTreść. timestring (date-time)Czas wpisu. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).413Treść ponad 64 KB (payload_too_large).422Idempotency-Key użyty z inną treścią (idempotency_key_reused).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X POST "https://app.convs.io/api/v1/contacts/abc123/notes" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b" \
-H "Content-Type: application/json" \
-d '{
"kind": "call",
"text": "Called back, wants an offer by Friday."
}'/contacts/{id}/sms-optoutZablokuj lub dopuść SMS-y
Utrzymuje listę „nie wysyłaj” i wszystkie osoby z tym samym telefonem w zgodzie.
Uprawnienie: contacts:write
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Idempotency-Keynagłówekstring | Unikalny klucz (1–255 widocznych znaków ASCII). Powtórzenie POST z tym samym kluczem i treścią w ciągu 24 godzin zwraca zapisaną odpowiedź z Idempotent-Replayed: true.Maks. długość: 255 |
Treść żądania application/json
| Nazwa | Opis |
|---|---|
sms_optoutbooleanWymagany | true blokuje SMS-y na telefon osoby (dla wszystkich osób z tym numerem), false ponownie je dopuszcza. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis idstringIdentyfikator osoby. namestringImię i nazwisko. phonestringTelefon w formacie E.164, pusty gdy nieznany. emailstringE-mail, pusty gdy nieznany. stagestringEtap sprzedaży.Wartości: new,contacted,qualified,sold,rejectedcycleintegerNumer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl. tagsstring[]Tagi. sms_optoutbooleanPrawda, gdy SMS-y do tej osoby są zablokowane. first_sourcestringSkąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…). first_adAdSource | nullPierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego. first_ad.platformstringPlatforma emisji podana przez Meta (facebook, instagram…). first_ad.campaign_idstringIdentyfikator kampanii Meta. first_ad.campaign_namestringNazwa kampanii. first_ad.adset_idstringIdentyfikator zestawu reklam Meta. first_ad.adset_namestringNazwa zestawu reklam. first_ad.ad_idstringIdentyfikator reklamy Meta. first_ad.ad_namestringNazwa reklamy. owner_idstring | nullIdentyfikator użytkownika — opiekuna osoby. last_activity_atstring (date-time) | nullCzas ostatniej aktywności. created_atstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana; używaj z updated_since.400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).413Treść ponad 64 KB (payload_too_large).422Idempotency-Key użyty z inną treścią (idempotency_key_reused).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X POST "https://app.convs.io/api/v1/contacts/abc123/sms-optout" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b" \
-H "Content-Type: application/json" \
-d '{
"sms_optout": true
}'Leady
Leady z formularzy Meta.
/leadsLista zgłoszeń
Leady z formularzy Meta. answers są dołączane tylko dla kluczy z leads:answers.
Uprawnienie: leads:read
Parametry
| Nazwa | Opis |
|---|---|
limitzapytanieinteger | Rozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100 |
cursorzapytaniestring | next_cursor z poprzedniej strony. |
orderzapytaniestring | Sortowanie po updated_at (potem id): desc od najnowszych (domyślnie) lub asc.Wartości: asc, descDomyślnie: desc |
updated_sincezapytaniestring (date-time) | Tylko rekordy zmienione w tym czasie ISO 8601 lub później. |
formzapytaniestring | Identyfikator formularza (źródła) w Convs. |
campaignzapytaniestring | Identyfikator kampanii Meta. |
adsetzapytaniestring | Identyfikator zestawu reklam. |
adzapytaniestring | Identyfikator reklamy. |
contactzapytaniestring | Identyfikator osoby. |
stagezapytaniestring | Etap.Wartości: new, contacted, qualified, sold, rejected |
fromzapytaniestring | Wysłane tego dnia lub później (RRRR-MM-DD w strefie organizacji albo ISO 8601). |
tozapytaniestring | Wysłane tego dnia lub wcześniej. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis dataLead[]Wymaganydata[].idstringIdentyfikator zgłoszenia w Convs. data[].meta_lead_idstringIdentyfikator leada w Meta. data[].form_idstringIdentyfikator źródła (formularza) w Convs; filtr form.data[].form_namestringNazwa formularza. data[].meta_form_idstringIdentyfikator formularza w Meta. data[].meta_page_idstringIdentyfikator strony w Meta. data[].stagestringEtap zgłoszenia.Wartości: new,contacted,qualified,sold,rejecteddata[].cycleintegerCykl sprzedaży osoby, do której należy zgłoszenie. data[].contact_idstring | nullOsoba (kontakt) tego zgłoszenia. data[].fetch_statusstringready, gdy dane leada są zapisane.data[].adAdSource | nullReklama zgłoszenia; null dla organicznych lub nieznanych. data[].ad.platformstringPlatforma emisji podana przez Meta (facebook, instagram…). data[].ad.campaign_idstringIdentyfikator kampanii Meta. data[].ad.campaign_namestringNazwa kampanii. data[].ad.adset_idstringIdentyfikator zestawu reklam Meta. data[].ad.adset_namestringNazwa zestawu reklam. data[].ad.ad_idstringIdentyfikator reklamy Meta. data[].ad.ad_namestringNazwa reklamy. data[].stagesobject[]Historia etapów. data[].stages[].stagestringdata[].stages[].atstring (date-time)data[].stages[].meta_event_queuedbooleandata[].answersLeadAnswer[]Odpowiedzi z formularza. Tylko dla kluczy z leads:answers.data[].answers[].keystringKlucz pola (także zmienna automatyzacji). data[].answers[].labelstringPytanie jak w formularzu. data[].answers[].valuesstring[]Odpowiedzi. data[].created_atstring (date-time) | nullKiedy zgłoszenie zostało wysłane. data[].updated_atstring (date-time)Ostatnia zmiana. next_cursorstring | nullWymaganyPrzekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.has_morebooleanWymaganyPrawda, gdy istnieje kolejna strona. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/leads" \
-H "Authorization: Bearer $API_KEY"/leads/{id}Pobierz zgłoszenie
Jedno zgłoszenie; answers tylko z leads:answers.
Uprawnienie: leads:read
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis idstringIdentyfikator zgłoszenia w Convs. meta_lead_idstringIdentyfikator leada w Meta. form_idstringIdentyfikator źródła (formularza) w Convs; filtr form.form_namestringNazwa formularza. meta_form_idstringIdentyfikator formularza w Meta. meta_page_idstringIdentyfikator strony w Meta. stagestringEtap zgłoszenia.Wartości: new,contacted,qualified,sold,rejectedcycleintegerCykl sprzedaży osoby, do której należy zgłoszenie. contact_idstring | nullOsoba (kontakt) tego zgłoszenia. fetch_statusstringready, gdy dane leada są zapisane.adAdSource | nullReklama zgłoszenia; null dla organicznych lub nieznanych. ad.platformstringPlatforma emisji podana przez Meta (facebook, instagram…). ad.campaign_idstringIdentyfikator kampanii Meta. ad.campaign_namestringNazwa kampanii. ad.adset_idstringIdentyfikator zestawu reklam Meta. ad.adset_namestringNazwa zestawu reklam. ad.ad_idstringIdentyfikator reklamy Meta. ad.ad_namestringNazwa reklamy. stagesobject[]Historia etapów. stages[].stagestringstages[].atstring (date-time)stages[].meta_event_queuedbooleananswersLeadAnswer[]Odpowiedzi z formularza. Tylko dla kluczy z leads:answers.answers[].keystringKlucz pola (także zmienna automatyzacji). answers[].labelstringPytanie jak w formularzu. answers[].valuesstring[]Odpowiedzi. created_atstring (date-time) | nullKiedy zgłoszenie zostało wysłane. updated_atstring (date-time)Ostatnia zmiana. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/leads/abc123" \
-H "Authorization: Bearer $API_KEY"Konwersje
Konwersje wysyłane do Meta i ich wysyłki.
202 z POST /events znaczy tylko tyle, że konwersja trafiła do kolejki wysyłek do Meta. Status wysyłki accepted to potwierdzenie odbioru przez Meta. Żadne z nich nie dowodzi, że kampania optymalizuje się na tych danych ani że konwersja zostanie przypisana reklamie.
/eventsLista zdarzeń
Konwersje z wysyłkami; treść zdarzeń nigdy nie jest zwracana.
Uprawnienie: events:read
Parametry
| Nazwa | Opis |
|---|---|
limitzapytanieinteger | Rozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100 |
cursorzapytaniestring | next_cursor z poprzedniej strony. |
orderzapytaniestring | Sortowanie po updated_at (potem id): desc od najnowszych (domyślnie) lub asc.Wartości: asc, descDomyślnie: desc |
updated_sincezapytaniestring (date-time) | Tylko rekordy zmienione w tym czasie ISO 8601 lub później. |
sourcezapytaniestring | Identyfikator źródła. |
statuszapytaniestring | Twój status. |
external_idzapytaniestring | Twój identyfikator rekordu. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis dataEvent[]Wymaganydata[].idstringIdentyfikator zdarzenia. data[].source_idstringIdentyfikator źródła. data[].external_idstringTwój identyfikator rekordu. data[].statusstringTwój status. data[].meta_event_idstringIdentyfikator deduplikacji Meta. data[].event_timestring (date-time) | nullCzas zdarzenia. data[].valuenumber | nullWartość. data[].currencystringWaluta. data[].deliveriesDelivery[]Wysyłki tego zdarzenia. data[].deliveries[].idstringIdentyfikator wysyłki. data[].deliveries[].event_idstringIdentyfikator zdarzenia w Convs. data[].deliveries[].target_idstringIdentyfikator odbiorcy Meta (połączenia z datasetem). data[].deliveries[].dataset_idstringIdentyfikator datasetu (piksela) Meta. data[].deliveries[].event_namestringNazwa zdarzenia Meta, np. Lead, Purchase. data[].deliveries[].meta_event_idstringevent_id wysłane do Meta. data[].deliveries[].modestringtestalbolive.data[].deliveries[].statusstringStatus wysyłki.Wartości: pending,sending,retry,accepted,failed,cancelleddata[].deliveries[].attemptsintegerDotychczasowe próby. data[].deliveries[].last_errorstringOstatni błąd, pusty gdy brak. data[].deliveries[].accepted_atstring (date-time) | nullKiedy Meta przyjęła wysyłkę (odbiór, nie dowód atrybucji). data[].deliveries[].next_attempt_atstring (date-time) | nullNastępna próba. data[].deliveries[].created_atstring (date-time)Czas utworzenia. data[].deliveries[].updated_atstring (date-time)Ostatnia zmiana. data[].created_atstring (date-time)Czas utworzenia. data[].updated_atstring (date-time)Ostatnia zmiana. next_cursorstring | nullWymaganyPrzekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.has_morebooleanWymaganyPrawda, gdy istnieje kolejna strona. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/events" \
-H "Authorization: Bearer $API_KEY"/eventsWyślij konwersję
Przyjmowanie konwersji serwer–serwer. Aktywne przepływy źródła mapują status na zdarzenia Meta i dodają jedną wysyłkę na dataset; zasady deduplikacji bez zmian. Odpowiedź 202: w kolejce, jeszcze nie wysłane.
Uprawnienie: events:write
Parametry
| Nazwa | Opis |
|---|---|
Idempotency-Keynagłówekstring | Unikalny klucz (1–255 widocznych znaków ASCII). Powtórzenie POST z tym samym kluczem i treścią w ciągu 24 godzin zwraca zapisaną odpowiedź z Idempotent-Replayed: true.Maks. długość: 255 |
Treść żądania application/json
| Nazwa | Opis |
|---|---|
sourcestringWymagany | Identyfikator źródła Arkusz Google lub Shoper Twojej organizacji (Połączenia → szczegóły źródła). |
external_idstringWymagany | Twój identyfikator rekordu (zamówienia, leada…), do 128 znaków.Maks. długość: 128 |
statusstringWymagany | Twój status zamapowany na zdarzenie Meta przez przepływ źródła, np. QUALIFIED albo purchase.Maks. długość: 80 |
consentbooleanWymagany | Musi być true: potwierdzasz podstawę prawną przesłania danych. |
event_timeinteger | string (date-time) | Sekundy Unix lub ISO 8601; najwyżej 7 dni wstecz. |
event_idstring | Identyfikator deduplikacji Meta; bez niego powstaje z source + external_id + status. |
emailstring | E-mail klienta (haszowany SHA-256 przed zapisem). |
phonestring | Telefon klienta w E.164 (haszowany). |
lead_idstring | Identyfikator leada Meta, gdy konwersja zamyka lead Meta. |
user_idstring | Twój identyfikator klienta (haszowany jako external_id). |
fbpstring | Ciasteczko _fbp. |
fbcstring | Ciasteczko _fbc. |
event_source_urlstring | Adres strony konwersji. |
tracking_idstring | Identyfikator śledzenia kolektora (Shoper). |
client_ip_addressstring | IP klienta. |
client_user_agentstring | User agent klienta. |
valuenumber | Wartość konwersji (wymagana dla Purchase). |
currencystring | Waluta ISO 4217 (wymagana z wartością). |
content_idsstring[] | Identyfikatory produktów. |
Odpowiedzi
202Przyjęto do kolejkiPola odpowiedziNazwa Opis event_idstringIdentyfikator zdarzenia w Convs. deliveries_createdintegerNowe wysyłki dodane do kolejki dla datasetów Meta. duplicatesintegerWysyłki pominięte jako duplikaty. sending_enabledbooleanfalse, gdy serwer nie wysyła do Meta (tylko kolejka). 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).413Treść ponad 64 KB (payload_too_large).422Idempotency-Key użyty z inną treścią (idempotency_key_reused).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X POST "https://app.convs.io/api/v1/events" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b" \
-H "Content-Type: application/json" \
-d '{
"source": "src_abc123",
"external_id": "order-1001",
"status": "purchase",
"consent": true,
"event_time": "2026-10-08T10:00:00Z",
"email": "anna@example.com",
"phone": "+48600100200",
"value": 1200,
"currency": "PLN"
}'const response = await fetch('https://app.convs.io/api/v1/events', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
'Idempotency-Key': '5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"source": "src_abc123",
"external_id": "order-1001",
"status": "purchase",
"consent": true,
"event_time": "2026-10-08T10:00:00Z",
"email": "anna@example.com",
"phone": "+48600100200",
"value": 1200,
"currency": "PLN"
}),
})
if (!response.ok) throw new Error((await response.json()).error.message)
const data = await response.json()
console.log(data)import os
import requests
response = requests.post(
"https://app.convs.io/api/v1/events",
headers={
"Authorization": f"Bearer {os.environ['API_KEY']}",
"Idempotency-Key": "5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b",
},
json={
"source": "src_abc123",
"external_id": "order-1001",
"status": "purchase",
"consent": True,
"event_time": "2026-10-08T10:00:00Z",
"email": "anna@example.com",
"phone": "+48600100200",
"value": 1200,
"currency": "PLN",
},
timeout=30,
)
response.raise_for_status()
print(response.json())<?php
$ch = curl_init('https://app.convs.io/api/v1/events');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('API_KEY'),
'Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'source' => 'src_abc123',
'external_id' => 'order-1001',
'status' => 'purchase',
'consent' => true,
'event_time' => '2026-10-08T10:00:00Z',
'email' => 'anna@example.com',
'phone' => '+48600100200',
'value' => 1200,
'currency' => 'PLN',
]),
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException($data['error']['message']);
}
print_r($data);/events/{id}Pobierz zdarzenie
Jedna konwersja ze statusem każdej wysyłki.
Uprawnienie: events:read
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis idstringIdentyfikator zdarzenia. source_idstringIdentyfikator źródła. external_idstringTwój identyfikator rekordu. statusstringTwój status. meta_event_idstringIdentyfikator deduplikacji Meta. event_timestring (date-time) | nullCzas zdarzenia. valuenumber | nullWartość. currencystringWaluta. deliveriesDelivery[]Wysyłki tego zdarzenia. deliveries[].idstringIdentyfikator wysyłki. deliveries[].event_idstringIdentyfikator zdarzenia w Convs. deliveries[].target_idstringIdentyfikator odbiorcy Meta (połączenia z datasetem). deliveries[].dataset_idstringIdentyfikator datasetu (piksela) Meta. deliveries[].event_namestringNazwa zdarzenia Meta, np. Lead, Purchase. deliveries[].meta_event_idstringevent_id wysłane do Meta. deliveries[].modestringtestalbolive.deliveries[].statusstringStatus wysyłki.Wartości: pending,sending,retry,accepted,failed,cancelleddeliveries[].attemptsintegerDotychczasowe próby. deliveries[].last_errorstringOstatni błąd, pusty gdy brak. deliveries[].accepted_atstring (date-time) | nullKiedy Meta przyjęła wysyłkę (odbiór, nie dowód atrybucji). deliveries[].next_attempt_atstring (date-time) | nullNastępna próba. deliveries[].created_atstring (date-time)Czas utworzenia. deliveries[].updated_atstring (date-time)Ostatnia zmiana. created_atstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/events/abc123" \
-H "Authorization: Bearer $API_KEY"/deliveriesLista wysyłek
Status wysyłek do Meta, np. status=failed&updated_since=…, by śledzić błędy.
Uprawnienie: events:read
Parametry
| Nazwa | Opis |
|---|---|
limitzapytanieinteger | Rozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100 |
cursorzapytaniestring | next_cursor z poprzedniej strony. |
orderzapytaniestring | Sortowanie po updated_at (potem id): desc od najnowszych (domyślnie) lub asc.Wartości: asc, descDomyślnie: desc |
updated_sincezapytaniestring (date-time) | Tylko rekordy zmienione w tym czasie ISO 8601 lub później. |
statuszapytaniestring | Status wysyłki.Wartości: pending, sending, retry, accepted, failed, cancelled |
eventzapytaniestring | Identyfikator zdarzenia. |
targetzapytaniestring | Identyfikator odbiorcy. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis dataDelivery[]Wymaganydata[].idstringIdentyfikator wysyłki. data[].event_idstringIdentyfikator zdarzenia w Convs. data[].target_idstringIdentyfikator odbiorcy Meta (połączenia z datasetem). data[].dataset_idstringIdentyfikator datasetu (piksela) Meta. data[].event_namestringNazwa zdarzenia Meta, np. Lead, Purchase. data[].meta_event_idstringevent_id wysłane do Meta. data[].modestringtestalbolive.data[].statusstringStatus wysyłki.Wartości: pending,sending,retry,accepted,failed,cancelleddata[].attemptsintegerDotychczasowe próby. data[].last_errorstringOstatni błąd, pusty gdy brak. data[].accepted_atstring (date-time) | nullKiedy Meta przyjęła wysyłkę (odbiór, nie dowód atrybucji). data[].next_attempt_atstring (date-time) | nullNastępna próba. data[].created_atstring (date-time)Czas utworzenia. data[].updated_atstring (date-time)Ostatnia zmiana. next_cursorstring | nullWymaganyPrzekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.has_morebooleanWymaganyPrawda, gdy istnieje kolejna strona. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/deliveries" \
-H "Authorization: Bearer $API_KEY"Raporty
Liczby kampanii i kreacji.
/campaigns/reportRaport kampanii
Wydatki, zgłoszenia, zakwalifikowane, sprzedaż i koszty na kampanię, zestaw lub reklamę — liczby ze strony Kampanie.
Uprawnienie: campaigns:read
Parametry
| Nazwa | Opis |
|---|---|
fromzapytaniestring | Pierwszy dzień RRRR-MM-DD (domyślnie 30 dni temu). |
tozapytaniestring | Ostatni dzień RRRR-MM-DD (zakres do 366 dni). |
levelzapytaniestring | Poziom wierszy.Wartości: campaign, adset, adDomyślnie: campaign |
campaignzapytaniestring | Tylko ta kampania (dla poziomu adset/ad). |
adsetzapytaniestring | Tylko ten zestaw (poziom ad). |
Odpowiedzi
200OKPola odpowiedziNazwa Opis fromstringPierwszy dzień (strefa czasowa organizacji). tostringOstatni dzień. levelstringPoziom wierszy.Wartości: campaign,adset,adtotalsobject[]Sumy w każdej walucie: currenti poprzedni okres tej samej długości (previous).rowsobject[]Wiersz na kampanię / zestaw / reklamę z metrics(spend, meta_leads, leads, qualified, rejected, sales, revenue, cost_per_lead, cost_per_qualified, cost_per_sale, revenue_per_spend; koszty są null przy zerowym dzielniku).organicobjectZgłoszenia bez znanej reklamy. syncsobject[]Stan synchronizacji wydatków na konto reklamowe. maturingbooleanPrawda, gdy zakres obejmuje ostatnie 30 dni (sprzedaże mogą jeszcze dojść). unattributedintegerZgłoszenia z okresu ze znanym źródłem, ale bez identyfikatora na tym poziomie. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/campaigns/report" \
-H "Authorization: Bearer $API_KEY"/creatives/reportRaport kreacji
Metryki na grupę kreacji z trendem tygodniowym i regułą zmęczenia — liczby ze strony Kreacje.
Uprawnienie: creatives:read
Parametry
| Nazwa | Opis |
|---|---|
fromzapytaniestring | Pierwszy dzień RRRR-MM-DD. |
tozapytaniestring | Ostatni dzień RRRR-MM-DD. |
formatzapytaniestring | Format kreacji. |
campaignzapytaniestring | Identyfikator kampanii Meta. |
ad_accountzapytaniestring | Identyfikator konta reklamowego. |
tagzapytaniestring | Filtr tagu wymiar:wartość (hook, creator, offer). |
weekszapytanieinteger | Liczba tygodni trendu, 4–8. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis fromstringPierwszy dzień. tostringOstatni dzień. weeksarray[]Zakresy tygodni użyte do trendu. rowsobject[]Wiersz na grupę kreacji (ten sam film, obraz lub kreacja) z metrykami, trendem tygodniowym, oceną zmęczenia i tagami. totalsobject[]Sumy w każdej walucie. syncsobject[]Stan synchronizacji wydatków na konto reklamowe. unattributedintegerZgłoszenia bez znanej kreacji. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/creatives/report" \
-H "Authorization: Bearer $API_KEY"Zadania w tle
Prace w tle.
/jobsLista zadań w tle
Importy leadów, synchronizacje wydatków, arkuszy i inne prace w tle organizacji.
Uprawnienie: jobs:read
Parametry
| Nazwa | Opis |
|---|---|
limitzapytanieinteger | Rozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100 |
cursorzapytaniestring | next_cursor z poprzedniej strony. |
orderzapytaniestring | Sortowanie po updated_at (potem id): desc od najnowszych (domyślnie) lub asc.Wartości: asc, descDomyślnie: desc |
updated_sincezapytaniestring (date-time) | Tylko rekordy zmienione w tym czasie ISO 8601 lub później. |
statuszapytaniestring | Status zadania.Wartości: queued, running, done, failed, cancelled |
Odpowiedzi
200OKPola odpowiedziNazwa Opis dataJob[]Wymaganydata[].numberintegerNumer zadania w organizacji. data[].kindstringRodzaj zadania, np. lead_import, ad_spend, sheets_sync. data[].labelstringOpis. data[].statusstringStatus.Wartości: queued,running,done,failed,cancelleddata[].prioritystringuseralbobackground.data[].triggerstringCo je uruchomiło. data[].progressobjectLicznik donei opistext.data[].attemptsintegerPróby. data[].errorstringBłąd nieudanego zadania. data[].summarystringPodsumowanie wyniku. data[].run_afterstring (date-time) | nullNie wcześniej niż. data[].started_atstring (date-time) | nullStart. data[].finished_atstring (date-time) | nullKoniec. data[].createdstring (date-time)Czas utworzenia. data[].updated_atstring (date-time)Ostatnia zmiana. next_cursorstring | nullWymaganyPrzekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.has_morebooleanWymaganyPrawda, gdy istnieje kolejna strona. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/jobs" \
-H "Authorization: Bearer $API_KEY"/jobs/{number}Pobierz zadanie
Jedno zadanie po numerze.
Uprawnienie: jobs:read
Parametry
| Nazwa | Opis |
|---|---|
numberścieżkaintegerWymagany | Numer zadania. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis numberintegerNumer zadania w organizacji. kindstringRodzaj zadania, np. lead_import, ad_spend, sheets_sync. labelstringOpis. statusstringStatus.Wartości: queued,running,done,failed,cancelledprioritystringuseralbobackground.triggerstringCo je uruchomiło. progressobjectLicznik donei opistext.attemptsintegerPróby. errorstringBłąd nieudanego zadania. summarystringPodsumowanie wyniku. run_afterstring (date-time) | nullNie wcześniej niż. started_atstring (date-time) | nullStart. finished_atstring (date-time) | nullKoniec. createdstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/jobs/42" \
-H "Authorization: Bearer $API_KEY"Webhooki
Zdarzenia wysyłane na Twój serwer.
/webhooksLista webhooków
Subskrypcje webhooków organizacji (do 10).
Uprawnienie: webhooks:read
Odpowiedzi
200OKPola odpowiedziNazwa Opis dataWebhook[]Wymaganydata[].idstringIdentyfikator webhooka. data[].urlstringAdres HTTPS, który odbiera POST-y. data[].descriptionstringTwój opis. data[].eventsstring[]Subskrybowane zdarzenia.Wartości: contact.created,contact.stage_changed,lead.created,delivery.faileddata[].activebooleanfalse wstrzymuje wysyłki. data[].last_statusintegerStatus HTTP ostatniej próby (0 = brak odpowiedzi). data[].last_errorstringOstatni błąd. data[].last_delivery_atstring (date-time) | nullOstatnia próba. data[].consecutive_failuresintegerNieudane próby z rzędu. data[].created_atstring (date-time)Czas utworzenia. data[].updated_atstring (date-time)Ostatnia zmiana. next_cursorstring | nullWymaganyPrzekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.has_morebooleanWymaganyPrawda, gdy istnieje kolejna strona. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/webhooks" \
-H "Authorization: Bearer $API_KEY"/webhooksDodaj webhook
Subskrybuje adres HTTPS na zdarzenia. Sekret podpisu secret jest zwracany tylko tutaj.
Uprawnienie: webhooks:write
Parametry
| Nazwa | Opis |
|---|---|
Idempotency-Keynagłówekstring | Unikalny klucz (1–255 widocznych znaków ASCII). Powtórzenie POST z tym samym kluczem i treścią w ciągu 24 godzin zwraca zapisaną odpowiedź z Idempotent-Replayed: true.Maks. długość: 255 |
Treść żądania application/json
| Nazwa | Opis |
|---|---|
urlstringWymagany | Adres HTTPS (bez loginu i hasła, bez adresów prywatnych i lokalnych).Maks. długość: 2000 |
eventsstring[]Wymagany | Zdarzenia do odbierania.Wartości: contact.created, contact.stage_changed, lead.created, delivery.failed |
descriptionstring | Twój opis.Maks. długość: 200 |
Odpowiedzi
201UtworzonoPola odpowiedziNazwa Opis idstringIdentyfikator webhooka. urlstringAdres HTTPS, który odbiera POST-y. descriptionstringTwój opis. eventsstring[]Subskrybowane zdarzenia.Wartości: contact.created,contact.stage_changed,lead.created,delivery.failedactivebooleanfalse wstrzymuje wysyłki. last_statusintegerStatus HTTP ostatniej próby (0 = brak odpowiedzi). last_errorstringOstatni błąd. last_delivery_atstring (date-time) | nullOstatnia próba. consecutive_failuresintegerNieudane próby z rzędu. created_atstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana. secretstringWymaganySekret podpisu ( whsec_…). Widoczny tylko w tej odpowiedzi — zapisz go.400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).413Treść ponad 64 KB (payload_too_large).422Idempotency-Key użyty z inną treścią (idempotency_key_reused).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X POST "https://app.convs.io/api/v1/webhooks" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks",
"events": [
"contact.created",
"contact.stage_changed"
]
}'/webhooks/{id}Pobierz webhook
Jedna subskrypcja z ostatnim wynikiem.
Uprawnienie: webhooks:read
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis idstringIdentyfikator webhooka. urlstringAdres HTTPS, który odbiera POST-y. descriptionstringTwój opis. eventsstring[]Subskrybowane zdarzenia.Wartości: contact.created,contact.stage_changed,lead.created,delivery.failedactivebooleanfalse wstrzymuje wysyłki. last_statusintegerStatus HTTP ostatniej próby (0 = brak odpowiedzi). last_errorstringOstatni błąd. last_delivery_atstring (date-time) | nullOstatnia próba. consecutive_failuresintegerNieudane próby z rzędu. created_atstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/webhooks/abc123" \
-H "Authorization: Bearer $API_KEY"/webhooks/{id}Zmień webhook
Zmienia adres, zdarzenia, opis lub wstrzymuje; wznowienie zeruje licznik błędów.
Uprawnienie: webhooks:write
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Treść żądania application/json
| Nazwa | Opis |
|---|---|
urlstring | Nowy adres. |
eventsstring[] | Nowa lista zdarzeń.Wartości: contact.created, contact.stage_changed, lead.created, delivery.failed |
descriptionstring | Twój opis. |
activeboolean | Wstrzymaj lub wznów. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis idstringIdentyfikator webhooka. urlstringAdres HTTPS, który odbiera POST-y. descriptionstringTwój opis. eventsstring[]Subskrybowane zdarzenia.Wartości: contact.created,contact.stage_changed,lead.created,delivery.failedactivebooleanfalse wstrzymuje wysyłki. last_statusintegerStatus HTTP ostatniej próby (0 = brak odpowiedzi). last_errorstringOstatni błąd. last_delivery_atstring (date-time) | nullOstatnia próba. consecutive_failuresintegerNieudane próby z rzędu. created_atstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).413Treść ponad 64 KB (payload_too_large).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X PATCH "https://app.convs.io/api/v1/webhooks/abc123" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks",
"events": [
"contact.created",
"contact.stage_changed"
],
"active": false
}'/webhooks/{id}Usuń webhook
Usuwa subskrypcję i jej wysyłki w kolejce.
Uprawnienie: webhooks:write
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Odpowiedzi
204Usunięto400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X DELETE "https://app.convs.io/api/v1/webhooks/abc123" \
-H "Authorization: Bearer $API_KEY"/webhooks/{id}/testWyślij próbny ping
Dodaje do kolejki podpisane zdarzenie ping, by sprawdzić odbiornik i weryfikację podpisu.
Uprawnienie: webhooks:write
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Idempotency-Keynagłówekstring | Unikalny klucz (1–255 widocznych znaków ASCII). Powtórzenie POST z tym samym kluczem i treścią w ciągu 24 godzin zwraca zapisaną odpowiedź z Idempotent-Replayed: true.Maks. długość: 255 |
Odpowiedzi
202W kolejcePola odpowiedziNazwa Opis delivery_idstringWysyłka zdarzenia pingdodana do kolejki.400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).422Idempotency-Key użyty z inną treścią (idempotency_key_reused).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X POST "https://app.convs.io/api/v1/webhooks/abc123/test" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b"/webhooks/{id}/rotate-secretWymień sekret podpisu
Od razu wymienia sekret podpisu; nowy secret jest zwracany tylko tutaj. Wysyłki czekające w kolejce zostaną podpisane nowym sekretem.
Uprawnienie: webhooks:write
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
Idempotency-Keynagłówekstring | Unikalny klucz (1–255 widocznych znaków ASCII). Powtórzenie POST z tym samym kluczem i treścią w ciągu 24 godzin zwraca zapisaną odpowiedź z Idempotent-Replayed: true.Maks. długość: 255 |
Odpowiedzi
200OKPola odpowiedziNazwa Opis idstringIdentyfikator webhooka. urlstringAdres HTTPS, który odbiera POST-y. descriptionstringTwój opis. eventsstring[]Subskrybowane zdarzenia.Wartości: contact.created,contact.stage_changed,lead.created,delivery.failedactivebooleanfalse wstrzymuje wysyłki. last_statusintegerStatus HTTP ostatniej próby (0 = brak odpowiedzi). last_errorstringOstatni błąd. last_delivery_atstring (date-time) | nullOstatnia próba. consecutive_failuresintegerNieudane próby z rzędu. created_atstring (date-time)Czas utworzenia. updated_atstring (date-time)Ostatnia zmiana. secretstringWymaganySekret podpisu ( whsec_…). Widoczny tylko w tej odpowiedzi — zapisz go.400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).409Konflikt z aktualnym stanem (conflict,contact_exists,contact_merged,stage_conflict,event_conflict,source_paused,idempotency_in_progress).422Idempotency-Key użyty z inną treścią (idempotency_key_reused).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl -X POST "https://app.convs.io/api/v1/webhooks/abc123/rotate-secret" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b"/webhooks/{id}/deliveriesLista wysyłek webhooka
Ostatnie próby (przechowywane 30 dni), od najnowszych.
Uprawnienie: webhooks:read
Parametry
| Nazwa | Opis |
|---|---|
idścieżkastringWymagany | Identyfikator rekordu. |
limitzapytanieinteger | Rozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100 |
cursorzapytaniestring | next_cursor z poprzedniej strony. |
orderzapytaniestring | Sortowanie po updated_at (potem id): desc od najnowszych (domyślnie) lub asc.Wartości: asc, descDomyślnie: desc |
updated_sincezapytaniestring (date-time) | Tylko rekordy zmienione w tym czasie ISO 8601 lub później. |
Odpowiedzi
200OKPola odpowiedziNazwa Opis dataWebhookDelivery[]Wymaganydata[].idstringIdentyfikator wysyłki (nagłówek X-Convs-Delivery). data[].webhook_idstringIdentyfikator webhooka. data[].eventstringTyp zdarzenia. data[].event_idstringIdentyfikator zdarzenia ( evt_…, ten sam dla wszystkich webhooków jednego zdarzenia).data[].statusstringStatus.Wartości: pending,sending,retry,delivered,failed,cancelleddata[].attemptsintegerPróby. data[].response_statusintegerStatus HTTP ostatniej próby. data[].last_errorstringOstatni błąd. data[].next_attempt_atstring (date-time) | nullNastępna próba. data[].delivered_atstring (date-time) | nullDostarczono. data[].created_atstring (date-time)Czas utworzenia. data[].updated_atstring (date-time)Ostatnia zmiana. next_cursorstring | nullWymaganyPrzekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.has_morebooleanWymaganyPrawda, gdy istnieje kolejna strona. 400Nieprawidłowe dane (validation_error,invalid_json,invalid_cursor).401Brak, nieznany, unieważniony lub wygasły klucz (unauthorized,key_revoked,key_expired).403Klucz nie ma uprawnienia (insufficient_scope,details.required_scope).404Brak takiego rekordu w Twojej organizacji (not_found).429Ponad 120 żądań na minutę tym kluczem (rate_limited); odczekajRetry-Aftersekund.
Przykład
curl "https://app.convs.io/api/v1/webhooks/abc123/deliveries" \
-H "Authorization: Bearer $API_KEY"Webhooki
Webhook wysyła POST z JSON-em na Twój adres HTTPS, gdy coś zmieni się w organizacji. Organizacja może mieć do 10 webhooków. Sekret podpisu (whsec_…) dostajesz tylko w odpowiedzi na utworzenie webhooka.
Dostarczamy co najmniej raz: to samo zdarzenie może przyjść kilka razy, więc pomijaj id, które już obsłużyłeś. Treść zawiera tylko identyfikatory i stany, nigdy imion, telefonów ani e-maili; szczegóły pobierz przez GET.
Zdarzenia
contact.created
Dodano osobę (lead z formularza, ręcznie, przez API, automatyzacją).
{
"id": "evt_9f2c4b1a7d3e5f60a1b2c3d4",
"type": "contact.created",
"created_at": "2026-10-08T10:00:00Z",
"organization_id": "org123",
"data": {
"contact_id": "abc123",
"stage": "new",
"first_source": "Formularz kontaktowy"
}
}contact.stage_changed
Osoba przeszła do innego etapu.
{
"id": "evt_9f2c4b1a7d3e5f60a1b2c3d4",
"type": "contact.stage_changed",
"created_at": "2026-10-08T10:00:00Z",
"organization_id": "org123",
"data": {
"contact_id": "abc123",
"from": "new",
"to": "qualified",
"cycle": 1,
"meta_events_queued": 1,
"leads_without_send": 0
}
}lead.created
Zapisano lead z formularza Meta.
{
"id": "evt_9f2c4b1a7d3e5f60a1b2c3d4",
"type": "lead.created",
"created_at": "2026-10-08T10:00:00Z",
"organization_id": "org123",
"data": {
"lead_id": "l123",
"meta_lead_id": "1234567890",
"form_id": "src123",
"contact_id": "abc123",
"campaign_id": "120200000",
"adset_id": "",
"ad_id": "",
"created_at": "2026-10-08T10:00:00Z"
}
}delivery.failed
Wysyłka konwersji do Meta ostatecznie się nie powiodła.
{
"id": "evt_9f2c4b1a7d3e5f60a1b2c3d4",
"type": "delivery.failed",
"created_at": "2026-10-08T10:00:00Z",
"organization_id": "org123",
"data": {
"delivery_id": "d123",
"event_id": "e123",
"target_id": "t123",
"dataset_id": "123456789",
"event_name": "Lead",
"mode": "live",
"error": "Połącz konto Meta ponownie lub sprawdź token."
}
}Nagłówki
| Nagłówek | Opis |
|---|---|
X-Convs-Signature | sha256= + hex HMAC-SHA256 z {X-Convs-Timestamp}.{surowa treść} kluczem sekretu webhooka. |
X-Convs-Timestamp | Sekundy Unix próby; odrzucaj starsze niż 5 minut. |
X-Convs-Event | Typ zdarzenia. |
X-Convs-Delivery | Identyfikator wysyłki (inny dla każdego webhooka, ten sam przy ponowieniach). |
Potwierdzenie i ponowienia
- Odpowiedz dowolnym kodem 2xx w ciągu 15 sekund. Najpierw zapisz zdarzenie, a dłuższą pracę wykonaj później.
- Inna odpowiedź albo brak odpowiedzi to ponowienie: łącznie do 8 prób, kolejne po 1 min, 5 min, 30 min, 2 h, 6 h, 12 h i 24 h.
X-Convs-Deliveryjest ten sam przy każdej próbie danej wysyłki; historię prób pokazujeGET /webhooks/{id}/deliveries.
Weryfikacja podpisu
- Odczytaj surową treść żądania, zanim cokolwiek ją sparsuje.
- Odrzuć żądanie, gdy znacznik czasu jest starszy niż 5 minut.
- Policz HMAC-SHA256 z
{timestamp}.{surowa treść}kluczem sekretu i porównaj z nagłówkiem podpisu (sha256=<hex>) w stałym czasie.
import crypto from 'node:crypto'
import http from 'node:http'
const secret = process.env.WEBHOOK_SECRET // whsec_…
function verify(rawBody, timestamp, signature) {
const age = Math.abs(Date.now() / 1000 - Number(timestamp))
if (!timestamp || !(age <= 300)) return false
const expected = 'sha256=' + crypto.createHmac('sha256', secret)
.update(`${timestamp}.`)
.update(rawBody)
.digest('hex')
const a = Buffer.from(String(signature ?? ''))
const b = Buffer.from(expected)
return a.length === b.length && crypto.timingSafeEqual(a, b)
}
http.createServer((req, res) => {
const chunks = []
req.on('data', chunk => chunks.push(chunk))
req.on('end', () => {
const raw = Buffer.concat(chunks) // surowa treść, przed parsowaniem JSON
if (!verify(raw, req.headers['x-convs-timestamp'], req.headers['x-convs-signature'])) {
res.writeHead(401).end()
return
}
const event = JSON.parse(raw.toString('utf8'))
// pomiń event.id, które już obsłużyłeś, i odpowiedz szybko
res.writeHead(200).end()
})
}).listen(3000)import hashlib
import hmac
import os
import time
from flask import Flask, abort, request
app = Flask(__name__)
SECRET = os.environ["WEBHOOK_SECRET"].encode() # whsec_…
@app.post("/webhooks")
def webhook():
raw = request.get_data() # surowa treść, przed parsowaniem JSON
timestamp = request.headers.get("X-Convs-Timestamp", "")
signature = request.headers.get("X-Convs-Signature", "")
if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
abort(401)
expected = "sha256=" + hmac.new(SECRET, timestamp.encode() + b"." + raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature):
abort(401)
event = request.get_json()
# pomiń event.id, które już obsłużyłeś, i odpowiedz szybko
return "", 200<?php
$secret = getenv('WEBHOOK_SECRET'); // whsec_…
$raw = file_get_contents('php://input'); // surowa treść, przed parsowaniem JSON
$timestamp = $_SERVER['HTTP_X_CONVS_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_CONVS_SIGNATURE'] ?? '';
if (!ctype_digit($timestamp) || abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit;
}
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $raw, $secret);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit;
}
$event = json_decode($raw, true);
// pomiń event.id, które już obsłużyłeś, i odpowiedz szybko
http_response_code(200);Utworzenie i test
Utwórz webhook, zapisz secret z odpowiedzi, a potem wyślij próbny ping, żeby sprawdzić odbiornik i weryfikację podpisu.
curl -X POST "https://app.convs.io/api/v1/webhooks" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks",
"events": [
"contact.created",
"contact.stage_changed"
]
}'curl -X POST "https://app.convs.io/api/v1/webhooks/abc123/test" \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b"Historia zmian
- 1.0.0 · : Pierwsza publiczna wersja.