Przejdź do treści
Dla programistów

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
Spis treści

Szybki start

  1. 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.
  2. Każdy adres zaczyna się od https://app.convs.io/api/v1. Odpowiedzi są w JSON.
  3. Sprawdź klucz wywołaniem GET /me. Nie wymaga żadnych uprawnień i zwraca organizację, nazwę klucza, uprawnienia i termin ważności.
curl
curl -H "Authorization: Bearer cvs_live_…" \
  https://app.convs.io/api/v1/me

W 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.

UprawnienieNa co pozwalaEndpointy
contacts:readOdczyt osób ze strony Klienci (imiona, telefony, e-maile — dane osobowe).
contacts:writeDodawanie i zmiana osób: dane, etap, notatki, tagi, blokada SMS.
leads:readOdczyt leadów z formularzy Meta, bez odpowiedzi z formularza.
leads:answersJak leads:read, a do tego odpowiedzi z formularza (answers) — dane osobowe.
    events:readOdczyt konwersji i statusu ich wysyłek do Meta.
    events:writeWysyłanie konwersji serwer–serwer do kolejki.
    campaigns:readRaport kampanii.
    creatives:readRaport kreacji.
    jobs:readOdczyt zadań w tle.
    webhooks:readOdczyt webhooków i historii ich wysyłek.
    webhooks:writeDodawanie, 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.

    JSON
    {
      "error": {
        "code": "insufficient_scope",
        "message": "Klucz API nie ma uprawnienia contacts:write.",
        "details": {
          "required_scope": "contacts:write"
        }
      }
    }
    KodHTTPZnaczenie
    unauthorized401Brak klucza, zły format albo nieznany klucz.
    key_revoked401Klucz został unieważniony.
    key_expired401Minął termin ważności klucza.
    insufficient_scope403Klucz nie ma potrzebnego uprawnienia (details.required_scope).
    rate_limited429Ponad 120 żądań na minutę tym kluczem; odczekaj Retry-After sekund.
    invalid_json400Treść nie jest poprawnym JSON-em albo zawiera nieznane pole.
    validation_error400Nieprawidłowa wartość pola lub parametru; opis mówi, co poprawić.
    invalid_cursor400cursor nie pochodzi z poprzedniej strony tej samej listy.
    not_found404Brak takiego rekordu w Twojej organizacji.
    route_not_found404Nie ma takiego endpointu.
    conflict409Operacja kłóci się z aktualnym stanem rekordu.
    contact_exists409Osoba z tym telefonem lub e-mailem już istnieje (details.contact_id).
    contact_merged409Karta została scalona z inną (details.merged_into).
    stage_conflict409Etapu nie da się teraz zmienić w ten sposób.
    event_conflict409Zdarzenie koliduje z już przyjętym.
    source_paused409Źródło jest wstrzymane.
    limit_reached409Osiągnięty limit, np. 10 webhooków na organizację.
    idempotency_key_reused422Ten sam Idempotency-Key z inną treścią żądania.
    idempotency_in_progress409Żądanie z tym Idempotency-Key jeszcze trwa; ponów za chwilę.
    payload_too_large413Treść żądania ponad 64 KB.
    internal_error500Błą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

    curl
    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')
    done
    JavaScript
    const 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)
    Python
    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
    <?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-Remaining i X-RateLimit-Reset.
    • Po przekroczeniu dostajesz 429 rate_limited z nagłówkiem Retry-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 POST przyjmuje nagłówek Idempotency-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, dostajesz 409 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.

    GET/me

    Opis 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 odpowiedzi
      NazwaOpis
      organizationobject
      organization.idstring
      organization.namestring
      keyobject
      key.idstring
      key.namestring
      key.prefixstring
      key.scopesstring[]
      key.expires_atstring (date-time) | null
      rate_limitobject
      rate_limit.per_minuteinteger
    • 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/me" \
      -H "Authorization: Bearer $API_KEY"
    JavaScript
    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)
    Python
    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
    <?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.

    GET/contacts

    Lista 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
    NazwaOpis
    limitzapytanieintegerRozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100
    cursorzapytaniestringnext_cursor z poprzedniej strony.
    orderzapytaniestringSortowanie 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.
    stagezapytaniestringEtap.Wartości: new, contacted, qualified, sold, rejected
    tagzapytaniestringTag.
    emailzapytaniestringDokładny e-mail (dopasowanie po skrócie).
    phonezapytaniestringDokładny telefon (dopasowanie po skrócie).
    campaignzapytaniestringOsoby ze zgłoszeniem z tej kampanii Meta.
    adsetzapytaniestring…z tego zestawu reklam.
    adzapytaniestring…z tej reklamy.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      dataContact[]Wymagany
      data[].idstring
      Identyfikator osoby.
      data[].namestring
      Imię i nazwisko.
      data[].phonestring
      Telefon w formacie E.164, pusty gdy nieznany.
      data[].emailstring
      E-mail, pusty gdy nieznany.
      data[].stagestring
      Etap sprzedaży.Wartości: new, contacted, qualified, sold, rejected
      data[].cycleinteger
      Numer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl.
      data[].tagsstring[]
      Tagi.
      data[].sms_optoutboolean
      Prawda, gdy SMS-y do tej osoby są zablokowane.
      data[].first_sourcestring
      Skąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…).
      data[].first_adAdSource | null
      Pierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego.
      data[].first_ad.platformstring
      Platforma emisji podana przez Meta (facebook, instagram…).
      data[].first_ad.campaign_idstring
      Identyfikator kampanii Meta.
      data[].first_ad.campaign_namestring
      Nazwa kampanii.
      data[].first_ad.adset_idstring
      Identyfikator zestawu reklam Meta.
      data[].first_ad.adset_namestring
      Nazwa zestawu reklam.
      data[].first_ad.ad_idstring
      Identyfikator reklamy Meta.
      data[].first_ad.ad_namestring
      Nazwa reklamy.
      data[].owner_idstring | null
      Identyfikator użytkownika — opiekuna osoby.
      data[].last_activity_atstring (date-time) | null
      Czas ostatniej aktywności.
      data[].created_atstring (date-time)
      Czas utworzenia.
      data[].updated_atstring (date-time)
      Ostatnia zmiana; używaj z updated_since.
      next_cursorstring | nullWymagany
      Przekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.
      has_morebooleanWymagany
      Prawda, 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/contacts" \
      -H "Authorization: Bearer $API_KEY"
    JavaScript
    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)
    Python
    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
    <?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);
    POST/contacts

    Dodaj osobę

    Dodaje osobę jak „Dodaj osobę” w panelu (opiekun z round robin, gdy jest włączony).

    Uprawnienie: contacts:write

    Parametry
    NazwaOpis
    Idempotency-KeynagłówekstringUnikalny 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
    NazwaOpis
    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 odpowiedzi
      NazwaOpis
      idstring
      Identyfikator osoby.
      namestring
      Imię i nazwisko.
      phonestring
      Telefon w formacie E.164, pusty gdy nieznany.
      emailstring
      E-mail, pusty gdy nieznany.
      stagestring
      Etap sprzedaży.Wartości: new, contacted, qualified, sold, rejected
      cycleinteger
      Numer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl.
      tagsstring[]
      Tagi.
      sms_optoutboolean
      Prawda, gdy SMS-y do tej osoby są zablokowane.
      first_sourcestring
      Skąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…).
      first_adAdSource | null
      Pierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego.
      first_ad.platformstring
      Platforma emisji podana przez Meta (facebook, instagram…).
      first_ad.campaign_idstring
      Identyfikator kampanii Meta.
      first_ad.campaign_namestring
      Nazwa kampanii.
      first_ad.adset_idstring
      Identyfikator zestawu reklam Meta.
      first_ad.adset_namestring
      Nazwa zestawu reklam.
      first_ad.ad_idstring
      Identyfikator reklamy Meta.
      first_ad.ad_namestring
      Nazwa reklamy.
      owner_idstring | null
      Identyfikator użytkownika — opiekuna osoby.
      last_activity_atstring (date-time) | null
      Czas 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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"
        ]
      }'
    JavaScript
    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)
    Python
    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
    <?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);
    GET/contacts/{id}

    Pobierz osobę

    Scalona karta zwraca 409 contact_merged z details.merged_into.

    Uprawnienie: contacts:read

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      idstring
      Identyfikator osoby.
      namestring
      Imię i nazwisko.
      phonestring
      Telefon w formacie E.164, pusty gdy nieznany.
      emailstring
      E-mail, pusty gdy nieznany.
      stagestring
      Etap sprzedaży.Wartości: new, contacted, qualified, sold, rejected
      cycleinteger
      Numer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl.
      tagsstring[]
      Tagi.
      sms_optoutboolean
      Prawda, gdy SMS-y do tej osoby są zablokowane.
      first_sourcestring
      Skąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…).
      first_adAdSource | null
      Pierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego.
      first_ad.platformstring
      Platforma emisji podana przez Meta (facebook, instagram…).
      first_ad.campaign_idstring
      Identyfikator kampanii Meta.
      first_ad.campaign_namestring
      Nazwa kampanii.
      first_ad.adset_idstring
      Identyfikator zestawu reklam Meta.
      first_ad.adset_namestring
      Nazwa zestawu reklam.
      first_ad.ad_idstring
      Identyfikator reklamy Meta.
      first_ad.ad_namestring
      Nazwa reklamy.
      owner_idstring | null
      Identyfikator użytkownika — opiekuna osoby.
      last_activity_atstring (date-time) | null
      Czas 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/contacts/abc123" \
      -H "Authorization: Bearer $API_KEY"
    PATCH/contacts/{id}

    Zmień dane osoby

    Zmienia imię, telefon, e-mail lub tagi; każda zmiana to wpis w historii.

    Uprawnienie: contacts:write

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Treść żądania application/json
    NazwaOpis
    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 odpowiedzi
      NazwaOpis
      idstring
      Identyfikator osoby.
      namestring
      Imię i nazwisko.
      phonestring
      Telefon w formacie E.164, pusty gdy nieznany.
      emailstring
      E-mail, pusty gdy nieznany.
      stagestring
      Etap sprzedaży.Wartości: new, contacted, qualified, sold, rejected
      cycleinteger
      Numer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl.
      tagsstring[]
      Tagi.
      sms_optoutboolean
      Prawda, gdy SMS-y do tej osoby są zablokowane.
      first_sourcestring
      Skąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…).
      first_adAdSource | null
      Pierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego.
      first_ad.platformstring
      Platforma emisji podana przez Meta (facebook, instagram…).
      first_ad.campaign_idstring
      Identyfikator kampanii Meta.
      first_ad.campaign_namestring
      Nazwa kampanii.
      first_ad.adset_idstring
      Identyfikator zestawu reklam Meta.
      first_ad.adset_namestring
      Nazwa zestawu reklam.
      first_ad.ad_idstring
      Identyfikator reklamy Meta.
      first_ad.ad_namestring
      Nazwa reklamy.
      owner_idstring | null
      Identyfikator użytkownika — opiekuna osoby.
      last_activity_atstring (date-time) | null
      Czas 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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"
        ]
      }'
    POST/contacts/{id}/stage

    Zmień 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
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Idempotency-KeynagłówekstringUnikalny 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
    NazwaOpis
    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 odpowiedzi
      NazwaOpis
      contactContact
      contact.idstring
      Identyfikator osoby.
      contact.namestring
      Imię i nazwisko.
      contact.phonestring
      Telefon w formacie E.164, pusty gdy nieznany.
      contact.emailstring
      E-mail, pusty gdy nieznany.
      contact.stagestring
      Etap sprzedaży.Wartości: new, contacted, qualified, sold, rejected
      contact.cycleinteger
      Numer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl.
      contact.tagsstring[]
      Tagi.
      contact.sms_optoutboolean
      Prawda, gdy SMS-y do tej osoby są zablokowane.
      contact.first_sourcestring
      Skąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…).
      contact.first_adAdSource | null
      Pierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego.
      contact.first_ad.platformstring
      Platforma emisji podana przez Meta (facebook, instagram…).
      contact.first_ad.campaign_idstring
      Identyfikator kampanii Meta.
      contact.first_ad.campaign_namestring
      Nazwa kampanii.
      contact.first_ad.adset_idstring
      Identyfikator zestawu reklam Meta.
      contact.first_ad.adset_namestring
      Nazwa zestawu reklam.
      contact.first_ad.ad_idstring
      Identyfikator reklamy Meta.
      contact.first_ad.ad_namestring
      Nazwa reklamy.
      contact.owner_idstring | null
      Identyfikator użytkownika — opiekuna osoby.
      contact.last_activity_atstring (date-time) | null
      Czas ostatniej aktywności.
      contact.created_atstring (date-time)
      Czas utworzenia.
      contact.updated_atstring (date-time)
      Ostatnia zmiana; używaj z updated_since.
      meta_events_queuedinteger
      Zdarzenia konwersji Meta dodane do kolejki dla otwartych zgłoszeń (kolejka je wyśle; to nie jest potwierdzenie od Meta).
      leads_without_sendinteger
      Otwarte 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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"
      }'
    JavaScript
    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)
    Python
    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
    <?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);
    POST/contacts/{id}/notes

    Dodaj notatkę

    Dodaje notatkę, telefon lub spotkanie do historii osoby.

    Uprawnienie: contacts:write

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Idempotency-KeynagłówekstringUnikalny 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
    NazwaOpis
    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 odpowiedzi
      NazwaOpis
      idstring
      Identyfikator wpisu historii.
      contact_idstring
      Identyfikator osoby.
      kindstring
      Rodzaj wpisu.
      textstring
      Treść.
      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); odczekaj Retry-After sekund.
    Przykład
    curl
    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."
      }'
    POST/contacts/{id}/tags

    Dodaj lub usuń tagi

    Dodaje i usuwa tagi bez wysyłania całej listy.

    Uprawnienie: contacts:write

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Idempotency-KeynagłówekstringUnikalny 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
    NazwaOpis
    addstring[]
    Tagi do dodania.
    removestring[]
    Tagi do usunięcia.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      idstring
      Identyfikator osoby.
      namestring
      Imię i nazwisko.
      phonestring
      Telefon w formacie E.164, pusty gdy nieznany.
      emailstring
      E-mail, pusty gdy nieznany.
      stagestring
      Etap sprzedaży.Wartości: new, contacted, qualified, sold, rejected
      cycleinteger
      Numer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl.
      tagsstring[]
      Tagi.
      sms_optoutboolean
      Prawda, gdy SMS-y do tej osoby są zablokowane.
      first_sourcestring
      Skąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…).
      first_adAdSource | null
      Pierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego.
      first_ad.platformstring
      Platforma emisji podana przez Meta (facebook, instagram…).
      first_ad.campaign_idstring
      Identyfikator kampanii Meta.
      first_ad.campaign_namestring
      Nazwa kampanii.
      first_ad.adset_idstring
      Identyfikator zestawu reklam Meta.
      first_ad.adset_namestring
      Nazwa zestawu reklam.
      first_ad.ad_idstring
      Identyfikator reklamy Meta.
      first_ad.ad_namestring
      Nazwa reklamy.
      owner_idstring | null
      Identyfikator użytkownika — opiekuna osoby.
      last_activity_atstring (date-time) | null
      Czas 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl -X POST "https://app.convs.io/api/v1/contacts/abc123/tags" \
      -H "Authorization: Bearer $API_KEY" \
      -H "Idempotency-Key: 5f0c7a2e-8d41-4b6a-9e3f-1c2d3e4f5a6b" \
      -H "Content-Type: application/json" \
      -d '{
        "add": [
          "vip"
        ],
        "remove": [
          "cold"
        ]
      }'
    POST/contacts/{id}/sms-optout

    Zablokuj lub dopuść SMS-y

    Utrzymuje listę „nie wysyłaj” i wszystkie osoby z tym samym telefonem w zgodzie.

    Uprawnienie: contacts:write

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Idempotency-KeynagłówekstringUnikalny 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
    NazwaOpis
    sms_optoutbooleanWymagany
    true blokuje SMS-y na telefon osoby (dla wszystkich osób z tym numerem), false ponownie je dopuszcza.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      idstring
      Identyfikator osoby.
      namestring
      Imię i nazwisko.
      phonestring
      Telefon w formacie E.164, pusty gdy nieznany.
      emailstring
      E-mail, pusty gdy nieznany.
      stagestring
      Etap sprzedaży.Wartości: new, contacted, qualified, sold, rejected
      cycleinteger
      Numer cyklu sprzedaży; nowe zgłoszenie zamkniętej osoby otwiera kolejny cykl.
      tagsstring[]
      Tagi.
      sms_optoutboolean
      Prawda, gdy SMS-y do tej osoby są zablokowane.
      first_sourcestring
      Skąd osoba przyszła po raz pierwszy (nazwa formularza, „Ręcznie”…).
      first_adAdSource | null
      Pierwsza reklama, z której przyszła osoba; null dla ruchu organicznego lub nieznanego.
      first_ad.platformstring
      Platforma emisji podana przez Meta (facebook, instagram…).
      first_ad.campaign_idstring
      Identyfikator kampanii Meta.
      first_ad.campaign_namestring
      Nazwa kampanii.
      first_ad.adset_idstring
      Identyfikator zestawu reklam Meta.
      first_ad.adset_namestring
      Nazwa zestawu reklam.
      first_ad.ad_idstring
      Identyfikator reklamy Meta.
      first_ad.ad_namestring
      Nazwa reklamy.
      owner_idstring | null
      Identyfikator użytkownika — opiekuna osoby.
      last_activity_atstring (date-time) | null
      Czas 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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.

    GET/leads

    Lista zgłoszeń

    Leady z formularzy Meta. answers są dołączane tylko dla kluczy z leads:answers.

    Uprawnienie: leads:read

    Parametry
    NazwaOpis
    limitzapytanieintegerRozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100
    cursorzapytaniestringnext_cursor z poprzedniej strony.
    orderzapytaniestringSortowanie 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.
    formzapytaniestringIdentyfikator formularza (źródła) w Convs.
    campaignzapytaniestringIdentyfikator kampanii Meta.
    adsetzapytaniestringIdentyfikator zestawu reklam.
    adzapytaniestringIdentyfikator reklamy.
    contactzapytaniestringIdentyfikator osoby.
    stagezapytaniestringEtap.Wartości: new, contacted, qualified, sold, rejected
    fromzapytaniestringWysłane tego dnia lub później (RRRR-MM-DD w strefie organizacji albo ISO 8601).
    tozapytaniestringWysłane tego dnia lub wcześniej.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      dataLead[]Wymagany
      data[].idstring
      Identyfikator zgłoszenia w Convs.
      data[].meta_lead_idstring
      Identyfikator leada w Meta.
      data[].form_idstring
      Identyfikator źródła (formularza) w Convs; filtr form.
      data[].form_namestring
      Nazwa formularza.
      data[].meta_form_idstring
      Identyfikator formularza w Meta.
      data[].meta_page_idstring
      Identyfikator strony w Meta.
      data[].stagestring
      Etap zgłoszenia.Wartości: new, contacted, qualified, sold, rejected
      data[].cycleinteger
      Cykl sprzedaży osoby, do której należy zgłoszenie.
      data[].contact_idstring | null
      Osoba (kontakt) tego zgłoszenia.
      data[].fetch_statusstring
      ready, gdy dane leada są zapisane.
      data[].adAdSource | null
      Reklama zgłoszenia; null dla organicznych lub nieznanych.
      data[].ad.platformstring
      Platforma emisji podana przez Meta (facebook, instagram…).
      data[].ad.campaign_idstring
      Identyfikator kampanii Meta.
      data[].ad.campaign_namestring
      Nazwa kampanii.
      data[].ad.adset_idstring
      Identyfikator zestawu reklam Meta.
      data[].ad.adset_namestring
      Nazwa zestawu reklam.
      data[].ad.ad_idstring
      Identyfikator reklamy Meta.
      data[].ad.ad_namestring
      Nazwa reklamy.
      data[].stagesobject[]
      Historia etapów.
      data[].stages[].stagestring
      data[].stages[].atstring (date-time)
      data[].stages[].meta_event_queuedboolean
      data[].answersLeadAnswer[]
      Odpowiedzi z formularza. Tylko dla kluczy z leads:answers.
      data[].answers[].keystring
      Klucz pola (także zmienna automatyzacji).
      data[].answers[].labelstring
      Pytanie jak w formularzu.
      data[].answers[].valuesstring[]
      Odpowiedzi.
      data[].created_atstring (date-time) | null
      Kiedy zgłoszenie zostało wysłane.
      data[].updated_atstring (date-time)
      Ostatnia zmiana.
      next_cursorstring | nullWymagany
      Przekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.
      has_morebooleanWymagany
      Prawda, 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/leads" \
      -H "Authorization: Bearer $API_KEY"
    GET/leads/{id}

    Pobierz zgłoszenie

    Jedno zgłoszenie; answers tylko z leads:answers.

    Uprawnienie: leads:read

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      idstring
      Identyfikator zgłoszenia w Convs.
      meta_lead_idstring
      Identyfikator leada w Meta.
      form_idstring
      Identyfikator źródła (formularza) w Convs; filtr form.
      form_namestring
      Nazwa formularza.
      meta_form_idstring
      Identyfikator formularza w Meta.
      meta_page_idstring
      Identyfikator strony w Meta.
      stagestring
      Etap zgłoszenia.Wartości: new, contacted, qualified, sold, rejected
      cycleinteger
      Cykl sprzedaży osoby, do której należy zgłoszenie.
      contact_idstring | null
      Osoba (kontakt) tego zgłoszenia.
      fetch_statusstring
      ready, gdy dane leada są zapisane.
      adAdSource | null
      Reklama zgłoszenia; null dla organicznych lub nieznanych.
      ad.platformstring
      Platforma emisji podana przez Meta (facebook, instagram…).
      ad.campaign_idstring
      Identyfikator kampanii Meta.
      ad.campaign_namestring
      Nazwa kampanii.
      ad.adset_idstring
      Identyfikator zestawu reklam Meta.
      ad.adset_namestring
      Nazwa zestawu reklam.
      ad.ad_idstring
      Identyfikator reklamy Meta.
      ad.ad_namestring
      Nazwa reklamy.
      stagesobject[]
      Historia etapów.
      stages[].stagestring
      stages[].atstring (date-time)
      stages[].meta_event_queuedboolean
      answersLeadAnswer[]
      Odpowiedzi z formularza. Tylko dla kluczy z leads:answers.
      answers[].keystring
      Klucz pola (także zmienna automatyzacji).
      answers[].labelstring
      Pytanie jak w formularzu.
      answers[].valuesstring[]
      Odpowiedzi.
      created_atstring (date-time) | null
      Kiedy 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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.

    GET/events

    Lista zdarzeń

    Konwersje z wysyłkami; treść zdarzeń nigdy nie jest zwracana.

    Uprawnienie: events:read

    Parametry
    NazwaOpis
    limitzapytanieintegerRozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100
    cursorzapytaniestringnext_cursor z poprzedniej strony.
    orderzapytaniestringSortowanie 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.
    sourcezapytaniestringIdentyfikator źródła.
    statuszapytaniestringTwój status.
    external_idzapytaniestringTwój identyfikator rekordu.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      dataEvent[]Wymagany
      data[].idstring
      Identyfikator zdarzenia.
      data[].source_idstring
      Identyfikator źródła.
      data[].external_idstring
      Twój identyfikator rekordu.
      data[].statusstring
      Twój status.
      data[].meta_event_idstring
      Identyfikator deduplikacji Meta.
      data[].event_timestring (date-time) | null
      Czas zdarzenia.
      data[].valuenumber | null
      Wartość.
      data[].currencystring
      Waluta.
      data[].deliveriesDelivery[]
      Wysyłki tego zdarzenia.
      data[].deliveries[].idstring
      Identyfikator wysyłki.
      data[].deliveries[].event_idstring
      Identyfikator zdarzenia w Convs.
      data[].deliveries[].target_idstring
      Identyfikator odbiorcy Meta (połączenia z datasetem).
      data[].deliveries[].dataset_idstring
      Identyfikator datasetu (piksela) Meta.
      data[].deliveries[].event_namestring
      Nazwa zdarzenia Meta, np. Lead, Purchase.
      data[].deliveries[].meta_event_idstring
      event_id wysłane do Meta.
      data[].deliveries[].modestring
      test albo live.
      data[].deliveries[].statusstring
      Status wysyłki.Wartości: pending, sending, retry, accepted, failed, cancelled
      data[].deliveries[].attemptsinteger
      Dotychczasowe próby.
      data[].deliveries[].last_errorstring
      Ostatni błąd, pusty gdy brak.
      data[].deliveries[].accepted_atstring (date-time) | null
      Kiedy Meta przyjęła wysyłkę (odbiór, nie dowód atrybucji).
      data[].deliveries[].next_attempt_atstring (date-time) | null
      Nastę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 | nullWymagany
      Przekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.
      has_morebooleanWymagany
      Prawda, 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/events" \
      -H "Authorization: Bearer $API_KEY"
    POST/events

    Wyś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
    NazwaOpis
    Idempotency-KeynagłówekstringUnikalny 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
    NazwaOpis
    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 odpowiedzi
      NazwaOpis
      event_idstring
      Identyfikator zdarzenia w Convs.
      deliveries_createdinteger
      Nowe wysyłki dodane do kolejki dla datasetów Meta.
      duplicatesinteger
      Wysyłki pominięte jako duplikaty.
      sending_enabledboolean
      false, 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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"
      }'
    JavaScript
    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)
    Python
    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
    <?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);
    GET/events/{id}

    Pobierz zdarzenie

    Jedna konwersja ze statusem każdej wysyłki.

    Uprawnienie: events:read

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      idstring
      Identyfikator zdarzenia.
      source_idstring
      Identyfikator źródła.
      external_idstring
      Twój identyfikator rekordu.
      statusstring
      Twój status.
      meta_event_idstring
      Identyfikator deduplikacji Meta.
      event_timestring (date-time) | null
      Czas zdarzenia.
      valuenumber | null
      Wartość.
      currencystring
      Waluta.
      deliveriesDelivery[]
      Wysyłki tego zdarzenia.
      deliveries[].idstring
      Identyfikator wysyłki.
      deliveries[].event_idstring
      Identyfikator zdarzenia w Convs.
      deliveries[].target_idstring
      Identyfikator odbiorcy Meta (połączenia z datasetem).
      deliveries[].dataset_idstring
      Identyfikator datasetu (piksela) Meta.
      deliveries[].event_namestring
      Nazwa zdarzenia Meta, np. Lead, Purchase.
      deliveries[].meta_event_idstring
      event_id wysłane do Meta.
      deliveries[].modestring
      test albo live.
      deliveries[].statusstring
      Status wysyłki.Wartości: pending, sending, retry, accepted, failed, cancelled
      deliveries[].attemptsinteger
      Dotychczasowe próby.
      deliveries[].last_errorstring
      Ostatni błąd, pusty gdy brak.
      deliveries[].accepted_atstring (date-time) | null
      Kiedy Meta przyjęła wysyłkę (odbiór, nie dowód atrybucji).
      deliveries[].next_attempt_atstring (date-time) | null
      Nastę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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/events/abc123" \
      -H "Authorization: Bearer $API_KEY"
    GET/deliveries

    Lista wysyłek

    Status wysyłek do Meta, np. status=failed&updated_since=…, by śledzić błędy.

    Uprawnienie: events:read

    Parametry
    NazwaOpis
    limitzapytanieintegerRozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100
    cursorzapytaniestringnext_cursor z poprzedniej strony.
    orderzapytaniestringSortowanie 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.
    statuszapytaniestringStatus wysyłki.Wartości: pending, sending, retry, accepted, failed, cancelled
    eventzapytaniestringIdentyfikator zdarzenia.
    targetzapytaniestringIdentyfikator odbiorcy.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      dataDelivery[]Wymagany
      data[].idstring
      Identyfikator wysyłki.
      data[].event_idstring
      Identyfikator zdarzenia w Convs.
      data[].target_idstring
      Identyfikator odbiorcy Meta (połączenia z datasetem).
      data[].dataset_idstring
      Identyfikator datasetu (piksela) Meta.
      data[].event_namestring
      Nazwa zdarzenia Meta, np. Lead, Purchase.
      data[].meta_event_idstring
      event_id wysłane do Meta.
      data[].modestring
      test albo live.
      data[].statusstring
      Status wysyłki.Wartości: pending, sending, retry, accepted, failed, cancelled
      data[].attemptsinteger
      Dotychczasowe próby.
      data[].last_errorstring
      Ostatni błąd, pusty gdy brak.
      data[].accepted_atstring (date-time) | null
      Kiedy Meta przyjęła wysyłkę (odbiór, nie dowód atrybucji).
      data[].next_attempt_atstring (date-time) | null
      Następna próba.
      data[].created_atstring (date-time)
      Czas utworzenia.
      data[].updated_atstring (date-time)
      Ostatnia zmiana.
      next_cursorstring | nullWymagany
      Przekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.
      has_morebooleanWymagany
      Prawda, 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/deliveries" \
      -H "Authorization: Bearer $API_KEY"

    Raporty

    Liczby kampanii i kreacji.

    GET/campaigns/report

    Raport kampanii

    Wydatki, zgłoszenia, zakwalifikowane, sprzedaż i koszty na kampanię, zestaw lub reklamę — liczby ze strony Kampanie.

    Uprawnienie: campaigns:read

    Parametry
    NazwaOpis
    fromzapytaniestringPierwszy dzień RRRR-MM-DD (domyślnie 30 dni temu).
    tozapytaniestringOstatni dzień RRRR-MM-DD (zakres do 366 dni).
    levelzapytaniestringPoziom wierszy.Wartości: campaign, adset, adDomyślnie: campaign
    campaignzapytaniestringTylko ta kampania (dla poziomu adset/ad).
    adsetzapytaniestringTylko ten zestaw (poziom ad).
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      fromstring
      Pierwszy dzień (strefa czasowa organizacji).
      tostring
      Ostatni dzień.
      levelstring
      Poziom wierszy.Wartości: campaign, adset, ad
      totalsobject[]
      Sumy w każdej walucie: current i 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).
      organicobject
      Zgłoszenia bez znanej reklamy.
      syncsobject[]
      Stan synchronizacji wydatków na konto reklamowe.
      maturingboolean
      Prawda, gdy zakres obejmuje ostatnie 30 dni (sprzedaże mogą jeszcze dojść).
      unattributedinteger
      Zgł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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/campaigns/report" \
      -H "Authorization: Bearer $API_KEY"
    GET/creatives/report

    Raport kreacji

    Metryki na grupę kreacji z trendem tygodniowym i regułą zmęczenia — liczby ze strony Kreacje.

    Uprawnienie: creatives:read

    Parametry
    NazwaOpis
    fromzapytaniestringPierwszy dzień RRRR-MM-DD.
    tozapytaniestringOstatni dzień RRRR-MM-DD.
    formatzapytaniestringFormat kreacji.
    campaignzapytaniestringIdentyfikator kampanii Meta.
    ad_accountzapytaniestringIdentyfikator konta reklamowego.
    tagzapytaniestringFiltr tagu wymiar:wartość (hook, creator, offer).
    weekszapytanieintegerLiczba tygodni trendu, 4–8.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      fromstring
      Pierwszy dzień.
      tostring
      Ostatni 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.
      unattributedinteger
      Zgł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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/creatives/report" \
      -H "Authorization: Bearer $API_KEY"

    Zadania w tle

    Prace w tle.

    GET/jobs

    Lista zadań w tle

    Importy leadów, synchronizacje wydatków, arkuszy i inne prace w tle organizacji.

    Uprawnienie: jobs:read

    Parametry
    NazwaOpis
    limitzapytanieintegerRozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100
    cursorzapytaniestringnext_cursor z poprzedniej strony.
    orderzapytaniestringSortowanie 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.
    statuszapytaniestringStatus zadania.Wartości: queued, running, done, failed, cancelled
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      dataJob[]Wymagany
      data[].numberinteger
      Numer zadania w organizacji.
      data[].kindstring
      Rodzaj zadania, np. lead_import, ad_spend, sheets_sync.
      data[].labelstring
      Opis.
      data[].statusstring
      Status.Wartości: queued, running, done, failed, cancelled
      data[].prioritystring
      user albo background.
      data[].triggerstring
      Co je uruchomiło.
      data[].progressobject
      Licznik done i opis text.
      data[].attemptsinteger
      Próby.
      data[].errorstring
      Błąd nieudanego zadania.
      data[].summarystring
      Podsumowanie wyniku.
      data[].run_afterstring (date-time) | null
      Nie wcześniej niż.
      data[].started_atstring (date-time) | null
      Start.
      data[].finished_atstring (date-time) | null
      Koniec.
      data[].createdstring (date-time)
      Czas utworzenia.
      data[].updated_atstring (date-time)
      Ostatnia zmiana.
      next_cursorstring | nullWymagany
      Przekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.
      has_morebooleanWymagany
      Prawda, 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/jobs" \
      -H "Authorization: Bearer $API_KEY"
    GET/jobs/{number}

    Pobierz zadanie

    Jedno zadanie po numerze.

    Uprawnienie: jobs:read

    Parametry
    NazwaOpis
    numberścieżkaintegerWymaganyNumer zadania.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      numberinteger
      Numer zadania w organizacji.
      kindstring
      Rodzaj zadania, np. lead_import, ad_spend, sheets_sync.
      labelstring
      Opis.
      statusstring
      Status.Wartości: queued, running, done, failed, cancelled
      prioritystring
      user albo background.
      triggerstring
      Co je uruchomiło.
      progressobject
      Licznik done i opis text.
      attemptsinteger
      Próby.
      errorstring
      Błąd nieudanego zadania.
      summarystring
      Podsumowanie wyniku.
      run_afterstring (date-time) | null
      Nie wcześniej niż.
      started_atstring (date-time) | null
      Start.
      finished_atstring (date-time) | null
      Koniec.
      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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/jobs/42" \
      -H "Authorization: Bearer $API_KEY"

    Webhooki

    Zdarzenia wysyłane na Twój serwer.

    GET/webhooks

    Lista webhooków

    Subskrypcje webhooków organizacji (do 10).

    Uprawnienie: webhooks:read

    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      dataWebhook[]Wymagany
      data[].idstring
      Identyfikator webhooka.
      data[].urlstring
      Adres HTTPS, który odbiera POST-y.
      data[].descriptionstring
      Twój opis.
      data[].eventsstring[]
      Subskrybowane zdarzenia.Wartości: contact.created, contact.stage_changed, lead.created, delivery.failed
      data[].activeboolean
      false wstrzymuje wysyłki.
      data[].last_statusinteger
      Status HTTP ostatniej próby (0 = brak odpowiedzi).
      data[].last_errorstring
      Ostatni błąd.
      data[].last_delivery_atstring (date-time) | null
      Ostatnia próba.
      data[].consecutive_failuresinteger
      Nieudane próby z rzędu.
      data[].created_atstring (date-time)
      Czas utworzenia.
      data[].updated_atstring (date-time)
      Ostatnia zmiana.
      next_cursorstring | nullWymagany
      Przekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.
      has_morebooleanWymagany
      Prawda, 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/webhooks" \
      -H "Authorization: Bearer $API_KEY"
    POST/webhooks

    Dodaj webhook

    Subskrybuje adres HTTPS na zdarzenia. Sekret podpisu secret jest zwracany tylko tutaj.

    Uprawnienie: webhooks:write

    Parametry
    NazwaOpis
    Idempotency-KeynagłówekstringUnikalny 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
    NazwaOpis
    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 odpowiedzi
      NazwaOpis
      idstring
      Identyfikator webhooka.
      urlstring
      Adres HTTPS, który odbiera POST-y.
      descriptionstring
      Twój opis.
      eventsstring[]
      Subskrybowane zdarzenia.Wartości: contact.created, contact.stage_changed, lead.created, delivery.failed
      activeboolean
      false wstrzymuje wysyłki.
      last_statusinteger
      Status HTTP ostatniej próby (0 = brak odpowiedzi).
      last_errorstring
      Ostatni błąd.
      last_delivery_atstring (date-time) | null
      Ostatnia próba.
      consecutive_failuresinteger
      Nieudane próby z rzędu.
      created_atstring (date-time)
      Czas utworzenia.
      updated_atstring (date-time)
      Ostatnia zmiana.
      secretstringWymagany
      Sekret 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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"
        ]
      }'
    GET/webhooks/{id}

    Pobierz webhook

    Jedna subskrypcja z ostatnim wynikiem.

    Uprawnienie: webhooks:read

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Odpowiedzi
    • 200OKPola odpowiedzi
      NazwaOpis
      idstring
      Identyfikator webhooka.
      urlstring
      Adres HTTPS, który odbiera POST-y.
      descriptionstring
      Twój opis.
      eventsstring[]
      Subskrybowane zdarzenia.Wartości: contact.created, contact.stage_changed, lead.created, delivery.failed
      activeboolean
      false wstrzymuje wysyłki.
      last_statusinteger
      Status HTTP ostatniej próby (0 = brak odpowiedzi).
      last_errorstring
      Ostatni błąd.
      last_delivery_atstring (date-time) | null
      Ostatnia próba.
      consecutive_failuresinteger
      Nieudane 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl "https://app.convs.io/api/v1/webhooks/abc123" \
      -H "Authorization: Bearer $API_KEY"
    PATCH/webhooks/{id}

    Zmień webhook

    Zmienia adres, zdarzenia, opis lub wstrzymuje; wznowienie zeruje licznik błędów.

    Uprawnienie: webhooks:write

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Treść żądania application/json
    NazwaOpis
    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 odpowiedzi
      NazwaOpis
      idstring
      Identyfikator webhooka.
      urlstring
      Adres HTTPS, który odbiera POST-y.
      descriptionstring
      Twój opis.
      eventsstring[]
      Subskrybowane zdarzenia.Wartości: contact.created, contact.stage_changed, lead.created, delivery.failed
      activeboolean
      false wstrzymuje wysyłki.
      last_statusinteger
      Status HTTP ostatniej próby (0 = brak odpowiedzi).
      last_errorstring
      Ostatni błąd.
      last_delivery_atstring (date-time) | null
      Ostatnia próba.
      consecutive_failuresinteger
      Nieudane 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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
      }'
    DELETE/webhooks/{id}

    Usuń webhook

    Usuwa subskrypcję i jej wysyłki w kolejce.

    Uprawnienie: webhooks:write

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Odpowiedzi
    • 204Usunięto
    • 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); odczekaj Retry-After sekund.
    Przykład
    curl
    curl -X DELETE "https://app.convs.io/api/v1/webhooks/abc123" \
      -H "Authorization: Bearer $API_KEY"
    POST/webhooks/{id}/test

    Wyślij próbny ping

    Dodaje do kolejki podpisane zdarzenie ping, by sprawdzić odbiornik i weryfikację podpisu.

    Uprawnienie: webhooks:write

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Idempotency-KeynagłówekstringUnikalny 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 odpowiedzi
      NazwaOpis
      delivery_idstring
      Wysyłka zdarzenia ping dodana 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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"
    POST/webhooks/{id}/rotate-secret

    Wymień 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
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    Idempotency-KeynagłówekstringUnikalny 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 odpowiedzi
      NazwaOpis
      idstring
      Identyfikator webhooka.
      urlstring
      Adres HTTPS, który odbiera POST-y.
      descriptionstring
      Twój opis.
      eventsstring[]
      Subskrybowane zdarzenia.Wartości: contact.created, contact.stage_changed, lead.created, delivery.failed
      activeboolean
      false wstrzymuje wysyłki.
      last_statusinteger
      Status HTTP ostatniej próby (0 = brak odpowiedzi).
      last_errorstring
      Ostatni błąd.
      last_delivery_atstring (date-time) | null
      Ostatnia próba.
      consecutive_failuresinteger
      Nieudane próby z rzędu.
      created_atstring (date-time)
      Czas utworzenia.
      updated_atstring (date-time)
      Ostatnia zmiana.
      secretstringWymagany
      Sekret 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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"
    GET/webhooks/{id}/deliveries

    Lista wysyłek webhooka

    Ostatnie próby (przechowywane 30 dni), od najnowszych.

    Uprawnienie: webhooks:read

    Parametry
    NazwaOpis
    idścieżkastringWymaganyIdentyfikator rekordu.
    limitzapytanieintegerRozmiar strony, 1–100 (domyślnie 25).Domyślnie: 25Zakres: 1–100
    cursorzapytaniestringnext_cursor z poprzedniej strony.
    orderzapytaniestringSortowanie 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 odpowiedzi
      NazwaOpis
      dataWebhookDelivery[]Wymagany
      data[].idstring
      Identyfikator wysyłki (nagłówek X-Convs-Delivery).
      data[].webhook_idstring
      Identyfikator webhooka.
      data[].eventstring
      Typ zdarzenia.
      data[].event_idstring
      Identyfikator zdarzenia (evt_…, ten sam dla wszystkich webhooków jednego zdarzenia).
      data[].statusstring
      Status.Wartości: pending, sending, retry, delivered, failed, cancelled
      data[].attemptsinteger
      Próby.
      data[].response_statusinteger
      Status HTTP ostatniej próby.
      data[].last_errorstring
      Ostatni błąd.
      data[].next_attempt_atstring (date-time) | null
      Następna próba.
      data[].delivered_atstring (date-time) | null
      Dostarczono.
      data[].created_atstring (date-time)
      Czas utworzenia.
      data[].updated_atstring (date-time)
      Ostatnia zmiana.
      next_cursorstring | nullWymagany
      Przekaż jako cursor, by pobrać następną stronę; null na ostatniej stronie.
      has_morebooleanWymagany
      Prawda, 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); odczekaj Retry-After sekund.
    Przykład
    curl
    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ą).

    Przykładowa treść · JSON
    {
      "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.

    Przykładowa treść · JSON
    {
      "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.

    Przykładowa treść · JSON
    {
      "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.

    Przykładowa treść · JSON
    {
      "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łówekOpis
    X-Convs-Signaturesha256= + hex HMAC-SHA256 z {X-Convs-Timestamp}.{surowa treść} kluczem sekretu webhooka.
    X-Convs-TimestampSekundy Unix próby; odrzucaj starsze niż 5 minut.
    X-Convs-EventTyp zdarzenia.
    X-Convs-DeliveryIdentyfikator 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-Delivery jest ten sam przy każdej próbie danej wysyłki; historię prób pokazuje GET /webhooks/{id}/deliveries.

    Weryfikacja podpisu

    1. Odczytaj surową treść żądania, zanim cokolwiek ją sparsuje.
    2. Odrzuć żądanie, gdy znacznik czasu jest starszy niż 5 minut.
    3. Policz HMAC-SHA256 z {timestamp}.{surowa treść} kluczem sekretu i porównaj z nagłówkiem podpisu (sha256=<hex>) w stałym czasie.
    Node.js
    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)
    Python
    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
    <?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
    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
    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.