Strona APISDKMCPopenapi.jsonZałóż konto

Przypominamy.com SMS API v2.3.0

Polskie REST API do wysyłki SMS z własnym kluczem, saldem, kontaktami, czarną listą, śledzonymi linkami, odbiorem odpowiedzi (2-way, na życzenie) i historią wysyłek

REST API do programowej wysyłki SMS w Polsce i za granicą. Jeden endpoint do wysyłki (pojedynczej, masowej i do grupy kontaktów), historia wiadomości, saldo, wybór nadpisu, książka kontaktów z personalizacją, czarna lista z linkiem opt-out, śledzone linki {{link:…}} z licznikiem kliknięć, odbiór odpowiedzi (2-way, na życzenie) i webhooki ze statusem doręczenia podpisane HMAC.

Dla kogo: firmy, które chcą wysyłać SMS-y z własnego systemu - przypomnienia o wizytach, potwierdzenia zamówień, kody 2FA, powiadomienia transakcyjne.

Autoryzacja

Klucz API generujesz w panelu (https://app.przypominamy.com/keys). Klucz ma postać pk_live_… (lub pk_test_… na koncie testowym) i jest pokazywany raz. Przekazuj go w nagłówku:

Authorization: Bearer pk_live_…

Klucz można w każdej chwili odwołać i wydać nowy w panelu.

Zakresy klucza (scopes)

Przy tworzeniu klucza w panelu wybierasz zakresy: send (wysyłka SMS/MMS/głos i anulowanie zaplanowanych), read (historia, raporty, konto, nadpisy, czarna lista, kontakty i grupy, odpowiedzi 2-way, śledzone linki - odczyt), manage (ustawienia konta, webhook, zapis czarnej listy, kontaktów i grup). Klucze wydane przed wprowadzeniem zakresów mają wszystkie trzy. Wywołanie bez wymaganego zakresu zwraca HTTP 403 forbidden z komunikatem wskazującym brakujący zakres. Aktualne zakresy klucza widzisz w polu scopes w GET /v1/account.

Saldo i cennik

Konto działa w modelu prepaid: każda wysyłka obciąża saldo w groszach według ceny za część SMS ustalonej dla Twojego konta (price_per_part_grosze w GET /v1/account). Przy braku środków API zwraca HTTP 402 i nic nie jest wysyłane. Na życzenie ustawiamy limit kredytowy (saldo może zejść poniżej zera) i rozliczamy fakturą.

Liczba części liczona jest jak u operatorów: 160 znaków dla alfabetu GSM-7 (153 przy wiadomościach wieloczęściowych), 70 znaków (67) gdy treść zawiera polskie znaki lub inne znaki spoza GSM-7.

Rate limit

120 żądań na minutę per konto. Po przekroczeniu HTTP 429 z nagłówkiem Retry-After. Do wysyłki masowej użyj tablicy to (do 500 numerów w jednym żądaniu) zamiast wielu pojedynczych wywołań.

Idempotencja

Dodaj nagłówek Idempotency-Key (dowolny ciąg do 128 znaków). Powtórzenie żądania z tym samym kluczem i tą samą treścią w ciągu 24 h zwraca pierwotną odpowiedź (nagłówek Idempotent-Replayed: true) bez ponownej wysyłki i obciążenia. Ten sam klucz z inną treścią zwraca HTTP 409.

Godziny wysyłki i ważność wiadomości

send_window ("HH:MM-HH:MM", czas polski) w żądaniu albo jako domyślne ustawienie konta (PATCH /v1/account) przesuwa wysyłkę spoza okna na najbliższy początek okna (dziś lub jutro); koniec okna jest wyłączny. Taka wiadomość ma status scheduled i można ją anulować. expires_at (ISO 8601, 15 min – 72 h po czasie wysyłki) mówi, po jakim czasie dostawca ma przestać próbować doręczyć - np. termin wizyty, po którym przypomnienie nie ma sensu.

Kontakty, grupy i personalizacja

POST /v1/contacts zapisuje odbiorców (imię, nazwisko, e-mail, do 20 pól własnych, grupy). W polu to wysyłki możesz podać "group:<id lub nazwa>" - również w tablicy razem ze zwykłymi numerami. Placeholdery {{imie}}, {{nazwisko}}, {{email}} i {{<pole_własne>}} w text są podstawiane per odbiorca (maks. 4 różne placeholdery w jednej treści, 3 gdy używasz też {{opt_out}}); zwrócone wiadomości mają już spersonalizowany text.

Czarna lista i opt-out

Numery z czarnej listy (POST /v1/blacklist lub kliknięcie linku wypisu) nie idą do dostawcy: dostają status rejected, koszt 0 i błąd „Numer na czarnej liście (opt-out)”, nie liczą się do accepted. Placeholder {{opt_out}} (alias {{wypisz}}) w treści SMS zamienia się w krótki, osobisty link api.przypominamy.com/o/<token>; odbiorca po kliknięciu widzi stronę potwierdzenia, a jego numer trafia na czarną listę Twojego konta. W SMS-ach marketingowych taki link jest wymagany.

Śledzone linki

Wstaw {{link:https://…}} w text (do 2 różnych adresów w jednej wiadomości). Każdy odbiorca dostaje własny krótki link api.przypominamy.com/l/<8 znaków>, który przekierowuje (302) na Twój adres i zlicza kliknięcia. Zwrócony text zawiera już podstawione linki; GET /v1/messages/{id} ma tablicę links[], GET /v1/links zestawienie (kto kliknął, ile razy, kiedy), a webhook link.clicked przychodzi przy pierwszym kliknięciu każdego linku. Bez dopłaty. Budżet placeholderów: łącznie do 4 na wiadomość dla {{opt_out}}, linków i pól z kontaktów.

Odbiór odpowiedzi (2-way) - na życzenie

Odbiór odpowiedzi uruchamiamy na życzenie, po włączeniu numeru odbiorczego dla Twojego konta (napisz na [email protected]). Do tego czasu inbound_number w GET /v1/account i GET /v1/inbound jest null, a lista odpowiedzi pusta - endpointy istnieją i możesz je zintegrować już dziś. Po uruchomieniu odbiorcy odpisują na numer odbiorczy, a odpowiedź trafia do Twojego konta, gdy zaczyna się od Twojego słowa kluczowego (inbound_prefix, 2–10 liter lub cyfr, unikalne, PATCH /v1/account; słowo jest usuwane z treści) albo - bez słowa - gdy to Ty jako ostatni pisałeś na numer nadawcy w ciągu 30 dni (reply_to = id tej wysyłki). Odpowiedzi czytasz przez GET /v1/inbound (filtry from, since, unread, mark_read) i dostajesz webhookiem message.received. STOP, WYPISZ lub NIE od dopasowanego nadawcy dopisuje numer do czarnej listy (opt_out) - w webhooku opt_out: true. Odbiór na współdzielonym numerze jest bezpłatny; dedykowany numer odbiorczy - wycena indywidualna.

Webhooki

Po ustawieniu adresu przez PUT /v1/account/webhook wysyłamy POST application/json przy każdej zmianie statusu wiadomości (message.sent|delivered|undelivered|failed|expired), przy odpowiedzi odbiorcy (message.received, data.inbound + data.opt_out) i przy pierwszym kliknięciu śledzonego linku (link.clicked, data.link + data.clicked_at). Każde wywołanie jest podpisane:

X-Przypominamy-Signature: t=<unix>,v1=<hex>

v1 = HMAC-SHA256(webhook_secret, "<t>.<surowe body>"). Odrzucaj wywołania, w których |now - t| > 300 sekund. Próby: 3 (0 s, 2 s, 10 s).

Przykład weryfikacji w Node.js:

const crypto = require('crypto');
const header = req.headers['x-przypominamy-signature']; // "t=1757230000,v1=abc…"
const t = header.match(/t=(\d+)/)[1];
const sig = header.match(/v1=([0-9a-f]+)/)[1];
const expected = crypto.createHmac('sha256', WEBHOOK_SECRET).update(`${t}.${rawBody}`).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return res.status(403).end();
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.status(403).end();

Błędy

Wszystkie błędy mają postać { "error": { "code": "…", "message": "…", "param": "…" }, "request_id": "req_…" }. Każda odpowiedź ma nagłówek X-Request-Id - podaj go w zgłoszeniu do supportu.

Linki

Bezpieczny start

Po aktywacji konta utwórz nowy klucz pk_live_ w panelu. Stary pk_test_ nie uruchamia płatnych wysyłek na aktywnym koncie (403 forbidden). Saldo i stawki są netto; 50 zł netto doładowania = 61,50 zł brutto z 23% VAT. Raporty doręczenia w panelu i API działają niezależnie od własnego webhooka klienta. Błędny format numeru powoduje 400 invalid_request przed wysyłką. GSM-7 liczy znaki rozszerzone podwójnie, UTF-16 znaki spoza BMP jako dwie jednostki.

SMS zagraniczne

Domyślnie 2× krajowa cena konta za część netto; priority ponownie mnoży cenę przez 2. Pole international_sms w GET /v1/account podaje domyślną cenę. Kraje UE są aktywne, pozostałe kierunki wymagają potwierdzenia dostępności. MMS i głos zagraniczny wymagają osobnej wyceny.

Autoryzacja

Nagłówek Authorization: Bearer pk_live_… (lub pk_test_… na koncie testowym). Klucz tworzysz w panelu app.przypominamy.com.

Serwer MCP (asystenci AI)

To samo API dla Claude, Codex, Cursora i n8n przez Model Context Protocol: endpoint https://mcp.przypominamy.com/mcp (Streamable HTTP), ten sam nagłówek Authorization: Bearer pk_…, bez OAuth. Narzędzia (25) send_sms (także z template_id + params, priority i śledzonym linkiem {link:…}), send_voice, cancel_message, get_message, list_messages, list_replies (odpowiedzi 2-way), list_links (kliknięcia), count_sms_parts, list_templates, save_template, check_number (HLR), get_account, list_senders, set_default_sender, set_send_window, set_inbound_keyword, list_blacklist, add_to_blacklist, remove_from_blacklist, list_contacts, upsert_contacts, delete_contact, list_groups, add_to_group, get_report; podzbiory /mcp/sms, /mcp/account, /mcp/reports, /mcp/contacts. Narzędzia podlegają zakresom klucza (send / read / manage) tak samo jak REST. Konfiguracje klientów, przykładowe polecenia i zasady bezpieczeństwa: przypominamy.com/mcp.

GET /v1/health

Status API

Odpowiedzi

HTTP 200 - API działa

{
  "status": "ok",
  "service": "przypominamy.com API",
  "version": "2.0"
}

POST /v1/messages

Wyślij SMS (jeden lub wielu odbiorców)

Wysyła SMS do jednego numeru (to jako string) lub do wielu (to jako tablica do 500 numerów, duplikaty usuwane). Koszt = liczba odbiorców × liczba części × cena za część. Saldo jest sprawdzane przed wysyłką. Wymaga zakresu send.

Numery przyjmujemy w formacie E.164 (+48600100200), bez plusa (48600100200) lub jako 9 cyfr (traktowane jako polskie).

Grupy i personalizacja: to może być "group:<id lub nazwa grupy>" albo tablicą mieszającą numery i grupy (łącznie do 500 odbiorców po rozwinięciu; pusta lub nieznana grupa = 400/404). Gdy w to jest grupa, placeholdery {{imie}}, {{nazwisko}}, {{email}} i {{<pole_własne>}} w text są podstawiane z kontaktów per odbiorca (także dla numerów podanych wprost, jeśli są w książce); brakująca wartość = pusty ciąg. Zwrócone wiadomości mają spersonalizowany text.

Opt-out: {{opt_out}} (alias {{wypisz}}) w treści zamienia się w osobisty link wypisu api.przypominamy.com/o/<token>. Odbiorcy z czarnej listy dostają status rejected, koszt 0 i nie są liczeni w accepted.

Godziny i ważność: send_window przesuwa wysyłkę spoza okna na najbliższy jego początek (status scheduled), expires_at ogranicza czas prób doręczenia. Te same opcje działają w POST /v1/mms i POST /v1/voice.

Szablony: zamiast text podaj template_id (szablon typu sms z GET /v1/templates) i params z wartościami {{klucz}}; pozostałe placeholdery są podstawiane z kontaktów albo pustym ciągiem. Ten sam mechanizm działa w POST /v1/mms (szablon mms) i POST /v1/voice (szablon vms).

Priorytet: priority: true kieruje SMS do osobnej, szybkiej kolejki u operatora (kody OTP, alerty) - cena za część × 2. Tylko SMS.

Śledzone linki: {{link:https://…}} w treści (do 2 różnych adresów) zamienia się per odbiorca w krótki link api.przypominamy.com/l/<token> z licznikiem kliknięć; zwrócony text ma już podstawiony link, GET /v1/messages/{id} zwraca links[], a przy pierwszym kliknięciu przychodzi webhook link.clicked. Bez dopłaty. {{opt_out}}, linki i pola z kontaktów dzielą wspólny budżet 4 placeholderów na wiadomość.

Parametry

NazwaTypOpis
Idempotency-Key headerstringRezerwuje operację przed wysyłką. Ten sam klucz i treść odtwarzają zakończony wynik przez 24 h. Inna treść lub operacja w toku/nierozstrzygnięta: 409 idempotency_conflict. Nie ponawiaj z nowym kluczem po timeoutcie. Nierozstrzygnięte operacje wymagają uzgodnienia statusu i nie wygasają automatycznie.

Treść żądania (JSON)

PoleTypOpis
to wymaganestring | arrayNumer odbiorcy, `"group:<id lub nazwa grupy>"` albo tablica numerów i grup (łącznie do 500 odbiorców po rozwinięciu, duplikaty usuwane) np. "+48600100200"
textstringTreść. Polskie znaki dozwolone (UCS-2, 70/67 znaków na część). Placeholdery: `{{imie}}`, `{{nazwisko}}`, `{{email}}`, `{{<pole_własne>}}` (z kontaktów - dla grup i dla numerów, które są w książce) i `{{opt_out}}` / `{{wypisz}}` (osobisty link wypisu) oraz `{{link:https://…}}` (śledzony krótki link per odbiorca, do 2 różnych adresów). Wymagane, chyba że podajesz `template_id`. np. "Przypominamy o wizycie jutro o 10:00."
template_idstringId szablonu (`tpl_…`, z `GET /v1/templates`) zamiast `text`. Szablon musi być typu `sms` (w `POST /v1/mms` - `mms`, w `POST /v1/voice` - `vms`), inaczej 400 z `param: "template_id"`; nieznany → 404. Placeholdery `{{klucz}}` podstawiane z `params`, pozostałe z kontaktów albo pustym ciągiem. np. "tpl_Q3m7kL2pXa9dRt"
paramsobjectWartości placeholderów szablonu, np. `{ "kiedy": "jutro 10:00" }` → `{{kiedy}}`. Klucze bez rozróżniania wielkości liter. Tylko z `template_id`. np. {"kiedy": "jutro 10:00", "lekarz": "dr Nowak"}
fromstringNadpis (nazwa nadawcy). Musi być aktywny na liście `GET /v1/senders`. Domyślnie nadpis konta. np. "ZDROWKO"
send_atstringZaplanowana wysyłka (ISO 8601), do 90 dni w przód. Daty w przeszłości = wysyłka natychmiast. np. "2026-09-08T08:00:00Z"
send_windowstringOkno godzin wysyłki w czasie polskim (`HH:MM-HH:MM`, min. 15 minut, koniec wyłączny). Wysyłka spoza okna (teraz albo `send_at`) jest przesuwana na najbliższy początek okna i dostaje status `scheduled`. Pominięte = domyślne okno konta z `PATCH /v1/account`. np. "08:00-20:00"
expires_atstringWażność: po tym czasie dostawca przestaje próbować doręczyć (status `expired`). Od 15 minut do 72 godzin po czasie wysyłki. np. "2026-09-08T20:00:00+02:00"
referencestringTwój identyfikator (np. id wizyty). Wraca w odpowiedzi, webhookach i jako filtr w `GET /v1/messages`. np. "wizyta-4711"
prioritybooleanSMS priorytetowy: osobna, szybka kolejka u operatora (kody OTP, alerty). Cena za część × 2. Tylko SMS - w `POST /v1/mms` i `POST /v1/voice` ignorowane. Wartość inna niż `true`/`false` → 400. np. false

Jeden odbiorca

{
  "to": "+48600100200",
  "text": "Przypominamy o wizycie jutro o 10:00.",
  "from": "ZDROWKO",
  "reference": "wizyta-4711"
}

Wielu odbiorców, ta sama treść

{
  "to": [
    "+48600100200",
    "+48600100201"
  ],
  "text": "Promocja -20% do niedzieli. Kod: SMS20"
}

Wysyłka odroczona

{
  "to": "+48600100200",
  "text": "Wizyta dziś o 14:00.",
  "send_at": "2026-09-08T08:00:00Z"
}

Do grupy kontaktów z personalizacją

{
  "to": "group:VIP",
  "text": "Cześć {{imie}}, przypominamy o wizycie {{wizyta}}."
}

Marketing z linkiem opt-out, oknem godzin i ważnością

{
  "to": [
    "+48600100200",
    "group:Newsletter"
  ],
  "text": "Promocja -20% do niedzieli. Kod: SMS20. Wypisz sie: {{opt_out}}",
  "send_window": "08:00-20:00",
  "expires_at": "2026-09-08T20:00:00+02:00"
}

Z szablonu i parametrów

{
  "to": "+48600100200",
  "template_id": "tpl_Q3m7kL2pXa9dRt",
  "params": {
    "imie": "Anno",
    "kiedy": "jutro 10:00",
    "lekarz": "dr Nowak"
  },
  "reference": "wizyta-4711"
}

Kod OTP priorytetem (podwójna stawka)

{
  "to": "+48600100200",
  "text": "Twoj kod: 4321. Wazny 5 minut.",
  "priority": true
}

Śledzony link z licznikiem kliknięć

{
  "to": [
    "+48600100200",
    "+48600100201"
  ],
  "text": "Potwierdz wizyte: {{link:https://firma.pl/wizyta?id=7}} Odpowiedz TAK albo NIE.",
  "reference": "wizyta-4711"
}

Odpowiedzi

HTTP 201 - Wiadomość przyjęta. Dla `to` jako string zwracany jest pojedynczy obiekt Message; dla tablicy - obiekt zbiorczy.

pojedynczy

{
  "id": "msg_qY08hZ2mmDXAazdRTytS",
  "type": "sms",
  "status": "queued",
  "to": "+48600100200",
  "from": "ZDROWKO",
  "text": "Przypominamy o wizycie jutro o 10:00.",
  "subject": null,
  "parts": 1,
  "cost_grosze": 9,
  "priority": false,
  "reference": "wizyta-4711",
  "send_at": null,
  "expires_at": null,
  "delivered_at": null,
  "error": null,
  "created_at": "2026-09-07T07:11:04.000Z",
  "updated_at": "2026-09-07T07:11:04.000Z"
}

masowy

{
  "count": 2,
  "accepted": 2,
  "total_cost_grosze": 18,
  "messages": [
    {
      "id": "msg_a…",
      "type": "sms",
      "status": "queued",
      "to": "+48600100200",
      "from": "ZDROWKO",
      "text": "…",
      "subject": null,
      "parts": 1,
      "cost_grosze": 9,
      "priority": false,
      "reference": null,
      "send_at": null,
      "expires_at": null,
      "delivered_at": null,
      "error": null,
      "created_at": "…",
      "updated_at": "…"
    },
    {
      "id": "msg_b…",
      "type": "sms",
      "status": "queued",
      "to": "+48600100201",
      "from": "ZDROWKO",
      "text": "…",
      "subject": null,
      "parts": 1,
      "cost_grosze": 9,
      "priority": false,
      "reference": null,
      "send_at": null,
      "expires_at": null,
      "delivered_at": null,
      "error": null,
      "created_at": "…",
      "updated_at": "…"
    }
  ]
}

Grupa z personalizacją i jednym numerem na czarnej liście

{
  "count": 2,
  "accepted": 1,
  "total_cost_grosze": 9,
  "messages": [
    {
      "id": "msg_a…",
      "type": "sms",
      "status": "queued",
      "to": "+48600100200",
      "from": "ZDROWKO",
      "text": "Cześć Anna, przypominamy o wizycie 10.09 14:00.",
      "subject": null,
      "parts": 1,
      "cost_grosze": 9,
      "priority": false,
      "reference": null,
      "send_at": null,
      "expires_at": null,
      "delivered_at": null,
      "error": null,
      "created_at": "…",
      "updated_at": "…"
    },
    {
      "id": "msg_b…",
      "type": "sms",
      "status": "rejected",
      "to": "+48600100201",
      "from": "ZDROWKO",
      "text": "Cześć Piotr, przypominamy o wizycie .",
      "subject": null,
      "parts": 1,
      "cost_grosze": 0,
      "priority": false,
      "reference": null,
      "send_at": null,
      "expires_at": null,
      "delivered_at": null,
      "error": "Numer na czarnej liście (opt-out)",
      "created_at": "…",
      "updated_at": "…"
    }
  ]
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 402 - Niewystarczające środki (prepaid) albo nieopłacone zestawienie miesięczne (postpaid) - nic nie zostało wysłane

Za mało środków na saldzie

{
  "error": {
    "code": "insufficient_funds",
    "message": "Niewystarczające środki. Szacowany koszt: 0.18 PLN, dostępne: 0.05 PLN"
  },
  "request_id": "req_…"
}

Konto postpaid z zaległym zestawieniem

{
  "error": {
    "code": "insufficient_funds",
    "message": "Konto ma nieopłacone zestawienie miesięczne. Wysyłki wznowimy po zaksięgowaniu wpłaty."
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nieznana grupa w polu `to`

{
  "error": {
    "code": "not_found",
    "message": "Nie znaleziono grupy: VIP",
    "param": "groups"
  },
  "request_id": "req_…"
}

HTTP 409 - Idempotency-Key użyty z inną treścią albo operacja w toku lub nierozstrzygnięta

HTTP 422 - Odrzucone przez dostawcę SMS (numer, nadpis, długość)

HTTP 429 - Przekroczono limit żądań

HTTP 502 - Błąd lub brak odpowiedzi dostawcy SMS (502/504)

Przykład: curl

curl -X POST https://api.przypominamy.com/v1/messages \
  -H "Authorization: Bearer $PRZYPOMINAMY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": "+48600100200", "text": "Przypominamy o wizycie jutro o 10:00.", "reference": "wizyta-4711"}'

Przykład: Python

import os, requests

resp = requests.post(
    "https://api.przypominamy.com/v1/messages",
    headers={"Authorization": f"Bearer {os.environ['PRZYPOMINAMY_API_KEY']}"},
    json={"to": "+48600100200", "text": "Przypominamy o wizycie jutro o 10:00.", "reference": "wizyta-4711"},
    timeout=10,
)
resp.raise_for_status()
print(resp.json()["id"], resp.json()["status"])

Przykład: Node.js

const res = await fetch('https://api.przypominamy.com/v1/messages', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.PRZYPOMINAMY_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ to: '+48600100200', text: 'Przypominamy o wizycie jutro o 10:00.', reference: 'wizyta-4711' }),
});
const msg = await res.json();
console.log(msg.id, msg.status);

GET /v1/messages

Historia wiadomości

Paginowana lista wiadomości konta, od najnowszych. Do następnej strony użyj cursor z pola next_cursor.

Parametry

NazwaTypOpis
limit queryinteger
status querystring
reference querystringDokładne dopasowanie pola `reference`
to querystringNumer odbiorcy
cursor querystringWartość `next_cursor` z poprzedniej strony

Odpowiedzi

HTTP 200 - Strona wyników

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 429 - Przekroczono limit żądań

GET /v1/messages/{id}

Pobierz wiadomość

Parametry

NazwaTypOpis
id path wymaganestring

Odpowiedzi

HTTP 200 - Wiadomość wraz ze śledzonymi linkami (`links[]`, pusta tablica, gdy w treści nie było `{{link:…}}`)

{
  "id": "msg_qY08hZ2mmDXAazdRTytS",
  "type": "sms",
  "status": "delivered",
  "to": "+48600100200",
  "from": "ZDROWKO",
  "text": "Potwierdz wizyte: api.przypominamy.com/l/k3Jd9sQz Odpowiedz TAK albo NIE.",
  "subject": null,
  "parts": 1,
  "cost_grosze": 9,
  "priority": false,
  "reference": "wizyta-4711",
  "send_at": null,
  "expires_at": null,
  "delivered_at": "2026-09-08T07:12:38.000Z",
  "error": null,
  "created_at": "2026-09-08T07:11:04.000Z",
  "updated_at": "2026-09-08T07:12:40.000Z",
  "links": [
    {
      "token": "k3Jd9sQz",
      "short_url": "https://api.przypominamy.com/l/k3Jd9sQz",
      "url": "https://firma.pl/wizyta?id=7",
      "message_id": "msg_qY08hZ2mmDXAazdRTytS",
      "to": "+48600100200",
      "clicks": 1,
      "first_click_at": "2026-09-08T07:15:02.000Z",
      "last_click_at": "2026-09-08T07:15:02.000Z",
      "created_at": "2026-09-08T07:11:04.000Z"
    }
  ]
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

DELETE /v1/messages/{id}

Anuluj zaplanowaną wysyłkę

Anuluje wiadomość ze statusem scheduled co najmniej 30 s przed send_at (SMS, MMS i głos). Status zmienia się na cancelled, koszt wraca na saldo (wpis refund w historii salda), a na koncie testowym zwracany jest kredyt testowy. Ponowne anulowanie tej samej wiadomości zwraca 200 z tym samym rekordem. Wiadomości już wysłanej albo z terminem za mniej niż 30 s nie da się cofnąć - HTTP 409. Wymaga zakresu send.

Parametry

NazwaTypOpis
id path wymaganestring

Odpowiedzi

HTTP 200 - Anulowano - rekord wiadomości ze statusem `cancelled`

PoleTypOpis
idstring np. "msg_qY08hZ2mmDXAazdRTytS"
typestring: sms, mms, vmsKanał: SMS, MMS, wiadomość głosowa
statusstring: scheduled, queued, sent, delivered, undelivered, failed, expired, rejected, cancelled`scheduled` - zaplanowana (`send_at` lub przesunięta przez `send_window`); `queued` - przyjęta; `sent` - przekazana do sieci; `delivered` - doręczona; `undelivered` - niedoręczona; `failed` - odrzucona przez dostawcę; `rejected` - odrzucona przez nas (numer na czarnej liście, koszt 0); `expired` - wygasła (m.in. po `expires_at`); `cancelled` - zaplanowana wysyłka anulowana przez `DELETE /v1/messages/{id}`, koszt zwrócony
tostring np. "+48600100200"
fromstring | null np. "ZDROWKO"
textstringTreść po personalizacji - dokładnie to, co dostał odbiorca (link opt-out, śledzone linki `api.przypominamy.com/l/…` i placeholdery już podstawione)
subjectstring | nullTemat (tylko MMS)
partsinteger np. 1
cost_groszeintegerKoszt w groszach (0 dla odrzuconych; po anulowaniu zwrócony na saldo) np. 9
prioritybooleanCzy wysłano jako SMS priorytetowy (podwójna stawka) np. false
referencestring | null
send_atstring | nullTermin wysyłki (po przesunięciu przez `send_window`, jeśli było)
expires_atstring | nullKoniec prób doręczenia, gdy podano `expires_at`
delivered_atstring | null
errorstring | nullPowód odrzucenia, gdy status = failed lub rejected (np. „Numer na czarnej liście (opt-out)”)
created_atstring
updated_atstring
{
  "id": "msg_qY08hZ2mmDXAazdRTytS",
  "type": "sms",
  "status": "cancelled",
  "to": "+48600100200",
  "from": "ZDROWKO",
  "text": "Wizyta jutro o 10:00.",
  "subject": null,
  "parts": 1,
  "cost_grosze": 9,
  "priority": false,
  "reference": null,
  "send_at": "2026-09-08T06:00:00.000Z",
  "expires_at": null,
  "delivered_at": null,
  "error": null,
  "created_at": "2026-09-07T07:11:04.000Z",
  "updated_at": "2026-09-07T09:20:11.000Z"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

HTTP 409 - Nie można anulować (wiadomość nie jest zaplanowana albo termin za mniej niż 30 s)

{
  "error": {
    "code": "invalid_request",
    "message": "Można anulować tylko zaplanowaną wysyłkę co najmniej 30 s przed terminem"
  },
  "request_id": "req_…"
}

HTTP 502 - Błąd lub brak odpowiedzi dostawcy SMS (502/504)

Przykład: curl

curl -X DELETE https://api.przypominamy.com/v1/messages/msg_qY08hZ2mmDXAazdRTytS \
  -H "Authorization: Bearer $PRZYPOMINAMY_API_KEY"

GET /v1/templates

Lista szablonów

Szablony konta (te same, które widać w panelu), posortowane po nazwie, z listą placeholderów {{klucz}} znalezionych w treści. Wymaga zakresu read.

Odpowiedzi

HTTP 200 - Lista szablonów

{
  "data": [
    {
      "id": "tpl_Q3m7kL2pXa9dRt",
      "name": "Wizyta",
      "type": "sms",
      "body": "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}.",
      "subject": null,
      "placeholders": [
        "imie",
        "kiedy",
        "lekarz"
      ],
      "created_at": "2026-09-07T07:11:04.000Z",
      "updated_at": "2026-09-07T07:11:04.000Z"
    }
  ]
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

Przykład: curl

curl https://api.przypominamy.com/v1/templates \
  -H "Authorization: Bearer $PRZYPOMINAMY_API_KEY"

POST /v1/templates

Utwórz szablon

Zapisuje szablon z placeholderami {{klucz}} (klucz: litery, cyfry, podkreślenie). type domyślnie sms; dla mms w body podaj dokument SMIL, a temat w subject; vms to szablon wiadomości głosowej. Wymaga zakresu manage.

Treść żądania (JSON)

PoleTypOpis
name wymaganestring np. "Wizyta"
typestring: sms, mms, vmsDomyślnie `sms`
body wymaganestringTreść z placeholderami `{{klucz}}` np. "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}."
subjectstring | nullTemat (tylko MMS)
{
  "name": "Wizyta",
  "body": "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}."
}

Odpowiedzi

HTTP 201 - Utworzono

PoleTypOpis
idstring np. "tpl_Q3m7kL2pXa9dRt"
namestring np. "Wizyta"
typestring: sms, mms, vmsKanał, do którego pasuje szablon - musi zgadzać się z endpointem wysyłki
bodystringTreść z placeholderami `{{klucz}}` (dla MMS - dokument SMIL) np. "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}."
subjectstring | nullTemat (tylko MMS)
placeholdersarray<string>Placeholdery znalezione w `body`, małymi literami np. ["imie", "kiedy", "lekarz"]
created_atstring
updated_atstring
{
  "id": "tpl_Q3m7kL2pXa9dRt",
  "name": "Wizyta",
  "type": "sms",
  "body": "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}.",
  "subject": null,
  "placeholders": [
    "imie",
    "kiedy",
    "lekarz"
  ],
  "created_at": "2026-09-07T07:11:04.000Z",
  "updated_at": "2026-09-07T07:11:04.000Z"
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

Przykład: curl

curl -X POST https://api.przypominamy.com/v1/templates \
  -H "Authorization: Bearer $PRZYPOMINAMY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Wizyta", "body": "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}."}'

Przykład: Python

import requests

r = requests.post(
    "https://api.przypominamy.com/v1/templates",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"name": "Wizyta", "body": "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}."},
    timeout=15,
)
tpl = r.json()

# wysyłka z szablonu
requests.post(
    "https://api.przypominamy.com/v1/messages",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"to": "+48600100200", "template_id": tpl["id"], "params": {"imie": "Anno", "kiedy": "jutro 10:00", "lekarz": "dr Nowak"}},
    timeout=15,
)

GET /v1/templates/{id}

Pobierz szablon

Wymaga zakresu read.

Parametry

NazwaTypOpis
id path wymaganestring

Odpowiedzi

HTTP 200 - Szablon

PoleTypOpis
idstring np. "tpl_Q3m7kL2pXa9dRt"
namestring np. "Wizyta"
typestring: sms, mms, vmsKanał, do którego pasuje szablon - musi zgadzać się z endpointem wysyłki
bodystringTreść z placeholderami `{{klucz}}` (dla MMS - dokument SMIL) np. "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}."
subjectstring | nullTemat (tylko MMS)
placeholdersarray<string>Placeholdery znalezione w `body`, małymi literami np. ["imie", "kiedy", "lekarz"]
created_atstring
updated_atstring

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

PATCH /v1/templates/{id}

Zmień szablon

Częściowa aktualizacja - podajesz tylko zmieniane pola (name, type, body, subject). Wymaga zakresu manage.

Parametry

NazwaTypOpis
id path wymaganestring

Treść żądania (JSON)

PoleTypOpis
namestring
typestring: sms, mms, vms
bodystring
subjectstring | null
{
  "name": "Wizyta 2"
}

Odpowiedzi

HTTP 200 - Zmieniono

PoleTypOpis
idstring np. "tpl_Q3m7kL2pXa9dRt"
namestring np. "Wizyta"
typestring: sms, mms, vmsKanał, do którego pasuje szablon - musi zgadzać się z endpointem wysyłki
bodystringTreść z placeholderami `{{klucz}}` (dla MMS - dokument SMIL) np. "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}."
subjectstring | nullTemat (tylko MMS)
placeholdersarray<string>Placeholdery znalezione w `body`, małymi literami np. ["imie", "kiedy", "lekarz"]
created_atstring
updated_atstring

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

DELETE /v1/templates/{id}

Usuń szablon

Usuwa szablon; wysłane wcześniej wiadomości zostają. Wymaga zakresu manage.

Parametry

NazwaTypOpis
id path wymaganestring

Odpowiedzi

HTTP 200 - Usunięto

{
  "deleted": "tpl_Q3m7kL2pXa9dRt"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

GET /v1/numbers/{msisdn}/lookup

Sprawdź numer (HLR)

Pyta operatora, czy numer jest aktywny w sieci i w jakiej - bez wysyłania SMS-a. Przydatne przed kampanią (czyszczenie bazy z martwych numerów) i przy weryfikacji numeru w rejestracji.

Koszt: price_per_hlr_grosze z GET /v1/account (domyślnie 5 gr = 0,05 zł), pobierany z salda jak SMS. Ponowne sprawdzenie tego samego numeru w ciągu 24 h zwraca wynik z pamięci (cached: true, cost_grosze: 0) bez pytania operatora.

Konto testowe: tylko numery zweryfikowane w panelu (inaczej 403), bez opłaty. Przy braku środków 402. Wymaga zakresu send.

Parametry

NazwaTypOpis
msisdn path wymaganestringNumer w E.164 (plus zakoduj jako `%2B` albo pomiń); 9 cyfr = numer polski

Odpowiedzi

HTTP 200 - Wynik sprawdzenia

PoleTypOpis
msisdnstring np. "+48600100200"
statusstring: active, inactive, invalid, unknown`active` - numer w sieci; `inactive` - nieosiągalny lub nieistniejący; `invalid` - zły format; `unknown` - operator nie odpowiedział jednoznacznie
networkstring | nullNazwa sieci (Plus, T-Mobile, Orange, Play…) np. "T-Mobile"
mccstring | null np. "260"
mncstring | null np. "02"
portedboolean | nullCzy numer został przeniesiony do innej sieci
cost_groszeintegerPobrana opłata (0 dla wyniku z pamięci i na koncie testowym) np. 5
cachedboolean`true` - wynik z ostatnich 24 h, bez opłaty i bez pytania operatora
checked_atstringKiedy operator sprawdził numer

Numer aktywny, sprawdzony u operatora

{
  "msisdn": "+48600100200",
  "status": "active",
  "network": "T-Mobile",
  "mcc": "260",
  "mnc": "02",
  "ported": false,
  "cost_grosze": 5,
  "cached": false,
  "checked_at": "2026-09-07T07:11:04.000Z"
}

Ten sam numer w ciągu 24 h - bez opłaty

{
  "msisdn": "+48600100200",
  "status": "active",
  "network": "T-Mobile",
  "mcc": "260",
  "mnc": "02",
  "ported": false,
  "cost_grosze": 0,
  "cached": true,
  "checked_at": "2026-09-07T07:11:04.000Z"
}

Numer nieosiągalny

{
  "msisdn": "+48600100201",
  "status": "inactive",
  "network": "Play",
  "mcc": "260",
  "mnc": "06",
  "ported": null,
  "cost_grosze": 5,
  "cached": false,
  "checked_at": "2026-09-07T07:11:04.000Z"
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 402 - Niewystarczające środki na sprawdzenie

{
  "error": {
    "code": "insufficient_funds",
    "message": "Niewystarczające środki na sprawdzenie numeru (0.05 PLN)"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez zakresu `send` albo konto testowe i niezweryfikowany numer

{
  "error": {
    "code": "forbidden",
    "message": "Konto testowe może sprawdzać tylko zweryfikowane numery. Doładuj konto, żeby sprawdzać dowolne.",
    "param": "msisdn"
  },
  "request_id": "req_…"
}

HTTP 502 - Błąd lub brak odpowiedzi dostawcy SMS (502/504)

Przykład: curl

curl https://api.przypominamy.com/v1/numbers/48600100200/lookup \
  -H "Authorization: Bearer $PRZYPOMINAMY_API_KEY"

Przykład: Python

import requests

r = requests.get(
    "https://api.przypominamy.com/v1/numbers/48600100200/lookup",
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=15,
)
hlr = r.json()
print(hlr["status"], hlr["network"], "z pamięci" if hlr["cached"] else f"{hlr['cost_grosze']} gr")

Przykład: Node.js

const r = await fetch('https://api.przypominamy.com/v1/numbers/48600100200/lookup', {
  headers: { Authorization: `Bearer ${process.env.PRZYPOMINAMY_API_KEY}` },
});
const hlr = await r.json();
if (hlr.status !== 'active') console.log('numer nieaktywny - pomiń w kampanii');

GET /v1/account

Saldo i ustawienia konta

Saldo, cennik (w tym price_per_hlr_grosze za sprawdzenie numeru), tryb konta, model rozliczenia (billing_mode: prepaid domyślnie, postpaid włączany na życzenie po weryfikacji firmy), domyślny nadpis, domyślne okno godzin wysyłki (send_window), numer odbiorczy do odpowiedzi 2-way (inbound_number; null, dopóki odbiór nie jest uruchomiony na życzenie dla konta), Twoje słowo kluczowe do odpowiedzi (inbound_prefix) i zakresy użytego klucza (scopes). Wymaga zakresu read.

Odpowiedzi

HTTP 200 - Konto

PoleTypOpis
country_ratesobjectIndywidualne stawki zagraniczne: prefiks numeru → ceny kanałów w groszach netto. Bez pasującej stawki SMS kosztuje 2× krajową cenę konta; MMS i głos wymagają osobnej wyceny. Najdłuższy prefiks wygrywa. Polska używa standardowej ceny konta.
idstring np. "cl_3W4997VtDI8fG1hM"
namestring
sender_namestring | null np. "ZDROWKO"
balance_groszeinteger np. 4982
credit_limit_groszeinteger np. 0
price_per_part_groszeinteger np. 9
price_per_mms_groszeinteger np. 35
price_per_vms_groszeinteger np. 25
price_per_hlr_groszeintegerCena sprawdzenia numeru (HLR) w groszach np. 5
rate_limit_per_minuteinteger np. 120
webhook_urlstring | null
statusstring: active, suspended, closed
modestring: test, live`test` - tylko zweryfikowane numery, koszt z puli testowej
test_creditsintegerPozostałe darmowe wiadomości (tylko w trybie `test`)
send_windowstring | nullDomyślne okno godzin wysyłki konta (czas polski) lub `null` np. "08:00-20:00"
billing_modestring: prepaid, postpaid`prepaid` (domyślnie) - saldo doładowane z góry. `postpaid` - włączany przez nas na życzenie po weryfikacji firmy: saldo może zejść poniżej zera do `credit_limit_grosze`, 1. dnia miesiąca wystawiamy zestawienie za poprzedni miesiąc (14 dni na przelew, tytuł = id zestawienia), po terminie wysyłki są wstrzymane (402 `insufficient_funds`) do zaksięgowania wpłaty. np. "prepaid"
inbound_numberstring | nullNumer odbiorczy, na który odbiorcy mogą odpisać (2-way). Odbiór uruchamiamy na życzenie - `null`, dopóki nie jest włączony dla konta np. "+48799000000"
inbound_prefixstring | nullTwoje słowo kluczowe: SMS zaczynający się od niego trafia do Twojego konta niezależnie od wcześniejszych wysyłek (`PATCH /v1/account`) np. "ZDROWKO"
scopesarray<string>Zakresy klucza użytego w tym żądaniu np. ["send", "read", "manage"]
international_smsobjectDomyślna cena SMS zagranicznego netto za część. Kraje UE aktywne; inne kierunki po potwierdzeniu dostępności.
{
  "id": "cl_3W4997VtDI8fG1hM",
  "name": "Przychodnia Zdrówko",
  "sender_name": "ZDROWKO",
  "balance_grosze": 4982,
  "credit_limit_grosze": 0,
  "price_per_part_grosze": 9,
  "price_per_mms_grosze": 35,
  "price_per_vms_grosze": 25,
  "price_per_hlr_grosze": 5,
  "rate_limit_per_minute": 120,
  "webhook_url": null,
  "status": "active",
  "mode": "live",
  "send_window": "08:00-20:00",
  "billing_mode": "prepaid",
  "inbound_number": "+48799000000",
  "inbound_prefix": "ZDROWKO",
  "scopes": [
    "send",
    "read",
    "manage"
  ]
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

PATCH /v1/account

Ustaw domyślny nadpis, godziny wysyłki lub słowo kluczowe odpowiedzi

Zmienia ustawienia konta; podaj co najmniej jedno pole. sender_name - domyślna nazwa nadawcy, musi być aktywna na liście z GET /v1/senders, inaczej HTTP 422; null przywraca domyślny nadpis operatora. send_window - domyślne okno godzin wysyłki w czasie polskim ("HH:MM-HH:MM", minimum 15 minut, koniec wyłączny); wysyłki bez własnego send_window spoza okna są przesuwane na najbliższy początek okna; null wyłącza. inbound_prefix - słowo kluczowe (2–10 liter lub cyfr, zapisywane wielkimi literami, unikalne w całej platformie - zajęte → HTTP 409), którym odbiorcy zaczynają SMS na numer odbiorczy, żeby trafił do Twojego konta niezależnie od wcześniejszych wysyłek (działa po uruchomieniu odbioru 2-way dla konta); null usuwa. Wymaga zakresu manage.

Treść żądania (JSON)

PoleTypOpis
sender_namestring | nullDomyślny nadpis; `null` = nadpis operatora np. "ZDROWKO"
send_windowstring | nullDomyślne okno godzin wysyłki (czas polski); `null` = bez ograniczeń np. "08:00-20:00"
inbound_prefixstring | nullSłowo kluczowe odpowiedzi na numer odbiorczy (2–10 liter/cyfr, bez rozróżniania wielkości); `null` = brak np. "ZDROWKO"

Domyślny nadpis

{
  "sender_name": "ZDROWKO"
}

Godziny wysyłki

{
  "send_window": "08:00-20:00"
}

Słowo kluczowe do odpowiedzi

{
  "inbound_prefix": "ZDROWKO"
}

Odpowiedzi

HTTP 200 - Zaktualizowano

{
  "id": "cl_3W4997VtDI8fG1hM",
  "sender_name": "ZDROWKO",
  "send_window": "08:00-20:00",
  "inbound_prefix": "ZDROWKO"
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 409 - Słowo kluczowe `inbound_prefix` zajęte przez inne konto

{
  "error": {
    "code": "invalid_request",
    "message": "Ten prefiks jest już zajęty. Wybierz inny.",
    "param": "inbound_prefix"
  },
  "request_id": "req_…"
}

HTTP 422 - Nadpis nieaktywny

GET /v1/senders

Dostępne nadpisy

Aktywne nazwy nadawcy, których możesz użyć w polu from lub jako domyślny nadpis. Nowy nadpis rejestrujemy na życzenie ([email protected]), weryfikacja u operatora trwa zwykle 1–2 dni robocze.

Odpowiedzi

HTTP 200 - Lista nadpisów

{
  "data": [
    {
      "name": "PRZYPOMINAM",
      "is_default": false
    },
    {
      "name": "ZDROWKO",
      "is_default": false
    }
  ],
  "current": "ZDROWKO"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 502 - Błąd lub brak odpowiedzi dostawcy SMS (502/504)

PUT /v1/account/webhook

Ustaw adres webhooka

Ustawia adres HTTPS, na który wysyłamy zdarzenia message.* (statusy doręczenia i message.received - odpowiedź odbiorcy) oraz link.clicked (pierwsze kliknięcie śledzonego linku). Odpowiedź zawiera webhook_secret do weryfikacji podpisu. rotate_secret: true generuje nowy sekret; url: null wyłącza webhooki.

Treść żądania (JSON)

PoleTypOpis
url wymaganestring | null np. "https://twojadomena.pl/webhooks/sms"
rotate_secretboolean

Odpowiedzi

HTTP 200 - Zapisano

{
  "webhook_url": "https://twojadomena.pl/webhooks/sms",
  "webhook_secret": "whsec_…",
  "signature_header": "X-Przypominamy-Signature"
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

GET /v1/blacklist

Czarna lista

Aktywne wpisy czarnej listy konta (bez wygasłych), posortowane po numerze. Paginacja kursorem: next_cursor to ostatni numer strony. Wymaga zakresu read.

Parametry

NazwaTypOpis
limit queryinteger
cursor querystringWartość `next_cursor` z poprzedniej strony (numer)

Odpowiedzi

HTTP 200 - Strona wyników

{
  "data": [
    {
      "msisdn": "+48600100200",
      "reason": "opt_out",
      "created_at": "2026-09-07T10:02:11.000Z",
      "expires_at": null
    },
    {
      "msisdn": "+48600100201",
      "reason": "reklamacja",
      "created_at": "2026-09-07T10:05:40.000Z",
      "expires_at": "2026-12-31T23:00:00.000Z"
    }
  ],
  "next_cursor": null
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

POST /v1/blacklist

Dodaj numery do czarnej listy

Blokuje jeden numer (msisdn) lub wiele (msisdns, do 1000). Istniejący wpis jest nadpisywany (nowy powód i data wygaśnięcia). Nieprawidłowe numery wracają w invalid i nie przerywają żądania. Wysyłka na zablokowany numer dostaje status rejected bez opłaty. Wymaga zakresu manage.

Treść żądania (JSON)

PoleTypOpis
msisdnstringJeden numer (alternatywnie `msisdns`) np. "+48600100200"
msisdnsarray<string>Lista numerów
reasonstringPowód (domyślnie `manual`; link opt-out zapisuje `opt_out`) np. "reklamacja"
expires_atstring | nullKoniec blokady (ISO 8601, w przyszłości); brak = bezterminowo

Jeden numer bezterminowo

{
  "msisdn": "+48600100200",
  "reason": "reklamacja"
}

Lista numerów z datą wygaśnięcia

{
  "msisdns": [
    "+48600100200",
    "+48600100201"
  ],
  "reason": "kampania Q4",
  "expires_at": "2026-12-31T23:00:00Z"
}

Odpowiedzi

HTTP 201 - Dodano

{
  "added": 2,
  "invalid": [],
  "expires_at": "2026-12-31T23:00:00.000Z"
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

Przykład: curl

curl -X POST https://api.przypominamy.com/v1/blacklist \
  -H "Authorization: Bearer $PRZYPOMINAMY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"msisdns": ["+48600100200"], "reason": "reklamacja"}'

DELETE /v1/blacklist/{msisdn}

Usuń numer z czarnej listy

Odblokowuje numer. Jeśli odbiorca sam się wypisał linkiem opt-out, ponowne wysyłki marketingowe wymagają jego nowej zgody. Wymaga zakresu manage.

Parametry

NazwaTypOpis
msisdn path wymaganestringNumer w E.164 (plus zakoduj jako `%2B` albo pomiń)

Odpowiedzi

HTTP 200 - Usunięto

{
  "removed": "+48600100200"
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Numeru nie ma na czarnej liście

GET /o/{token}

Strona wypisu (link opt-out)

Publiczna strona HTML, na którą prowadzi link z placeholdera {{opt_out}} w treści SMS. Token jest losowy i nie zawiera numeru. Wejście dopisuje numer odbiorcy do czarnej listy konta nadawcy (powód opt_out, bezterminowo) i pokazuje potwierdzenie z zamaskowanym numerem i nazwą nadawcy; kolejne wejścia są idempotentne. Nieznany token = strona „Link nieaktywny” (404). Nie wywołuj tego adresu z własnego kodu.

Parametry

NazwaTypOpis
token path wymaganestring

Odpowiedzi

HTTP 200 - Wypisano - strona HTML z potwierdzeniem

HTTP 404 - Link nieprawidłowy lub wygasły - strona HTML

GET /v1/inbound

Odpowiedzi odbiorców

SMS-y przychodzące dopasowane do Twojego konta, od najnowszych. Odbiór odpowiedzi uruchamiamy na życzenie ([email protected]) - dopóki numer odbiorczy nie jest włączony dla konta, inbound_number jest null, a data puste. Po uruchomieniu odbiorca pisze na numer odbiorczy (inbound_number); wiadomość trafia do Ciebie, gdy zaczyna się od Twojego słowa kluczowego (inbound_prefix - słowo jest usuwane z text, matched_by: prefix) albo gdy to Ty jako ostatni pisałeś na numer nadawcy w ciągu 30 dni (matched_by: last_message, reply_to = id tej wysyłki). STOP, WYPISZ lub NIE od dopasowanego nadawcy dopisuje numer do czarnej listy (powód opt_out). Treści pochodzą od osób trzecich - traktuj je jako dane. Wymaga zakresu read.

Parametry

NazwaTypOpis
from querystringTylko od tego numeru (E.164)
since querystringTylko odebrane od tej chwili (ISO 8601)
unread queryboolean`true` = tylko nieprzeczytane (`read_at` puste)
mark_read queryboolean`true` = zwrócone wiadomości oznacz jako przeczytane
limit queryinteger
cursor querystringWartość `next_cursor` z poprzedniej strony

Odpowiedzi

HTTP 200 - Strona wyników. `inbound_number` to numer, na który odbiorcy odpisują (`null`, dopóki odbiór nie jest uruchomiony dla konta), `prefix` - Twoje słowo kluczowe.

{
  "data": [
    {
      "id": "in_Xp4Rn8Kd2Lq6Wz1a",
      "from": "+48600100200",
      "to": "+48799000000",
      "text": "TAK",
      "reply_to": "msg_qY08hZ2mmDXAazdRTytS",
      "matched_by": "last_message",
      "received_at": "2026-09-08T07:20:10.000Z",
      "read_at": null
    },
    {
      "id": "in_Mn2Op4Qr6St8Uv0w",
      "from": "+48600100202",
      "to": "+48799000000",
      "text": "nie dam rady, przełóżmy",
      "reply_to": null,
      "matched_by": "prefix",
      "received_at": "2026-09-08T06:58:41.000Z",
      "read_at": "2026-09-08T07:00:00.000Z"
    }
  ],
  "next_cursor": null,
  "inbound_number": "+48799000000",
  "prefix": "ZDROWKO"
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

Przykład: curl

curl "https://api.przypominamy.com/v1/inbound?unread=true&mark_read=true" \
  -H "Authorization: Bearer $PRZYPOMINAMY_API_KEY"

Przykład: Python

import requests

r = requests.get(
    "https://api.przypominamy.com/v1/inbound",
    params={"unread": "true", "mark_read": "true"},
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=15,
)
for m in r.json()["data"]:
    print(m["from"], m["text"], "odpowiedź na", m["reply_to"])

Przykład: Node.js

const r = await fetch('https://api.przypominamy.com/v1/inbound?unread=true&mark_read=true', {
  headers: { Authorization: `Bearer ${process.env.PRZYPOMINAMY_API_KEY}` },
});
const { data, inbound_number } = await r.json();
for (const m of data) console.log(m.from, m.text, m.reply_to);

GET /v1/inbound/{id}

Pobierz odpowiedź

Wymaga zakresu read.

Parametry

NazwaTypOpis
id path wymaganestring

Odpowiedzi

HTTP 200 - Wiadomość przychodząca

PoleTypOpis
idstring np. "in_Xp4Rn8Kd2Lq6Wz1a"
fromstringNumer nadawcy (E.164) np. "+48600100200"
tostring | nullNumer odbiorczy, na który przyszła wiadomość np. "+48799000000"
textstringTreść; przy dopasowaniu po słowie kluczowym - bez tego słowa np. "TAK"
reply_tostring | nullId Twojej ostatniej wiadomości do tego numeru z ostatnich 30 dni (`msg_…`), jeśli była np. "msg_qY08hZ2mmDXAazdRTytS"
matched_bystring: prefix, last_messageJak wiadomość trafiła do Twojego konta: `prefix` - zaczynała się od Twojego słowa kluczowego, `last_message` - Ty ostatni pisałeś na ten numer
received_atstring
read_atstring | nullKiedy oznaczono jako przeczytaną (`mark_read=true` w `GET /v1/inbound` albo panel)

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

GET /l/{token}

Przekierowanie śledzonego linku

Publiczny adres, który odbiorca dostaje w SMS-ie w miejsce {{link:…}}. Zlicza kliknięcie (licznik, czas, user_agent, skrót IP), przy pierwszym kliknięciu wysyła webhook link.clicked, i przekierowuje 302 na docelowy adres. Nieznany token = 404 „Link nieaktywny”. Nie wywołuj tego adresu z własnego kodu - każde wejście liczy się jako kliknięcie.

Parametry

NazwaTypOpis
token path wymaganestring

Odpowiedzi

HTTP 302 - Przekierowanie na docelowy adres

HTTP 404 - Link nieaktywny

GET /v1/contacts

Lista kontaktów

Książka odbiorców konta, posortowana po id. Filtry: q (fragment numeru, imienia, nazwiska lub e-maila), group_id. Paginacja kursorem (next_cursor = ostatnie id strony). Wymaga zakresu read.

Parametry

NazwaTypOpis
q querystringSzukany fragment
group_id querystringTylko członkowie grupy `gr_…`
limit queryinteger
cursor querystringWartość `next_cursor` z poprzedniej strony

Odpowiedzi

HTTP 200 - Strona wyników

{
  "data": [
    {
      "id": "ct_8fK2mQpL0aXz4Wv1",
      "msisdn": "+48600100200",
      "first_name": "Anna",
      "last_name": "Nowak",
      "email": "[email protected]",
      "fields": {
        "wizyta": "10.09 14:00"
      },
      "groups": [
        {
          "id": "gr_Zq7Lk2Pm9sT1",
          "name": "VIP"
        }
      ],
      "created_at": "2026-09-07T10:00:00.000Z",
      "updated_at": "2026-09-07T10:00:00.000Z"
    }
  ],
  "next_cursor": null
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

POST /v1/contacts

Dodaj lub zaktualizuj kontakty

Upsert po numerze: istniejący kontakt z tym msisdn jest aktualizowany (podane pola nadpisują, pominięte zostają), nowy - tworzony. Treść żądania to jeden obiekt (odpowiedź 201 przy utworzeniu, 200 przy aktualizacji, zwraca kontakt) albo tablica do 500 obiektów (odpowiedź 201 { created, updated, invalid: [{ index, message }] }; błędne elementy nie przerywają importu). groups przyjmuje nazwy lub id gr_…; nieistniejące nazwy są tworzone; podanie groups zastępuje dotychczasowe przypisania kontaktu. Pola własne fields: klucz [a-zA-Z_][a-zA-Z0-9_]{0,30}, wartość do 200 znaków, maks. 20 pól - używasz ich w treści jako {{nazwa_pola}}. Wymaga zakresu manage.

Treść żądania (JSON)

PoleTypOpis
msisdnstringNumer (E.164, bez plusa lub 9 cyfr = Polska); klucz upsertu np. "+48600100200"
first_namestring | nullImię - placeholder `{{imie}}` np. "Anna"
last_namestring | nullNazwisko - placeholder `{{nazwisko}}` np. "Nowak"
emailstring | nullPlaceholder `{{email}}`
fieldsobject | nullPola własne (do 20; klucz `[a-zA-Z_][a-zA-Z0-9_]{0,30}`) - placeholder `{{nazwa_pola}}` np. {"wizyta": "10.09 14:00"}
groupsarray<string>Nazwy lub id grup; nieistniejące nazwy są tworzone; zastępuje dotychczasowe przypisania np. ["VIP"]

Jeden kontakt z grupą i polem własnym

{
  "msisdn": "+48600100200",
  "first_name": "Anna",
  "last_name": "Nowak",
  "fields": {
    "wizyta": "10.09 14:00"
  },
  "groups": [
    "VIP"
  ]
}

Import tablicy (do 500)

[
  {
    "msisdn": "+48600100201",
    "first_name": "Piotr",
    "groups": [
      "VIP"
    ]
  },
  {
    "msisdn": "+48600100202",
    "first_name": "Ewa",
    "email": "[email protected]"
  }
]

Odpowiedzi

HTTP 201 - Utworzono (obiekt Contact) lub zaimportowano (podsumowanie)

Jeden kontakt

{
  "id": "ct_8fK2mQpL0aXz4Wv1",
  "msisdn": "+48600100200",
  "first_name": "Anna",
  "last_name": "Nowak",
  "email": null,
  "fields": {
    "wizyta": "10.09 14:00"
  },
  "groups": [
    {
      "id": "gr_Zq7Lk2Pm9sT1",
      "name": "VIP"
    }
  ],
  "created_at": "2026-09-07T10:00:00.000Z",
  "updated_at": "2026-09-07T10:00:00.000Z"
}

Tablica

{
  "created": 2,
  "updated": 0,
  "invalid": []
}

HTTP 200 - Zaktualizowano istniejący kontakt (tylko dla pojedynczego obiektu)

PoleTypOpis
idstring np. "ct_8fK2mQpL0aXz4Wv1"
msisdnstring np. "+48600100200"
first_namestring | null np. "Anna"
last_namestring | null np. "Nowak"
emailstring | null
fieldsobjectPola własne np. {"wizyta": "10.09 14:00"}
groupsarray<object>
created_atstring
updated_atstring

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Podano id nieistniejącej grupy

Przykład: curl

curl -X POST https://api.przypominamy.com/v1/contacts \
  -H "Authorization: Bearer $PRZYPOMINAMY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"msisdn": "+48600100200", "first_name": "Anna", "fields": {"wizyta": "10.09 14:00"}, "groups": ["VIP"]}'

GET /v1/contacts/{id}

Pobierz kontakt

Wymaga zakresu read.

Parametry

NazwaTypOpis
id path wymaganestring

Odpowiedzi

HTTP 200 - Kontakt

PoleTypOpis
idstring np. "ct_8fK2mQpL0aXz4Wv1"
msisdnstring np. "+48600100200"
first_namestring | null np. "Anna"
last_namestring | null np. "Nowak"
emailstring | null
fieldsobjectPola własne np. {"wizyta": "10.09 14:00"}
groupsarray<object>
created_atstring
updated_atstring

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

PATCH /v1/contacts/{id}

Zmień kontakt

Częściowa aktualizacja: podane pola nadpisują, null lub "" czyści pole, pominięte zostają. Zmiana msisdn na numer innego kontaktu = 409. groups zastępuje przypisania. Wymaga zakresu manage.

Parametry

NazwaTypOpis
id path wymaganestring

Treść żądania (JSON)

PoleTypOpis
msisdnstringNumer (E.164, bez plusa lub 9 cyfr = Polska); klucz upsertu np. "+48600100200"
first_namestring | nullImię - placeholder `{{imie}}` np. "Anna"
last_namestring | nullNazwisko - placeholder `{{nazwisko}}` np. "Nowak"
emailstring | nullPlaceholder `{{email}}`
fieldsobject | nullPola własne (do 20; klucz `[a-zA-Z_][a-zA-Z0-9_]{0,30}`) - placeholder `{{nazwa_pola}}` np. {"wizyta": "10.09 14:00"}
groupsarray<string>Nazwy lub id grup; nieistniejące nazwy są tworzone; zastępuje dotychczasowe przypisania np. ["VIP"]
{
  "last_name": "Kowalska",
  "fields": {
    "wizyta": "12.09 09:30"
  }
}

Odpowiedzi

HTTP 200 - Zaktualizowany kontakt

PoleTypOpis
idstring np. "ct_8fK2mQpL0aXz4Wv1"
msisdnstring np. "+48600100200"
first_namestring | null np. "Anna"
last_namestring | null np. "Nowak"
emailstring | null
fieldsobjectPola własne np. {"wizyta": "10.09 14:00"}
groupsarray<object>
created_atstring
updated_atstring

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

HTTP 409 - Inny kontakt ma już ten numer

DELETE /v1/contacts/{id}

Usuń kontakt

Usuwa kontakt z książki i ze wszystkich grup. Nie blokuje numeru - do tego służy czarna lista. Wymaga zakresu manage.

Parametry

NazwaTypOpis
id path wymaganestring

Odpowiedzi

HTTP 200 - Usunięto

{
  "deleted": "ct_8fK2mQpL0aXz4Wv1"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

GET /v1/groups

Lista grup

Wszystkie grupy konta z liczbą członków, posortowane po nazwie. Wymaga zakresu read.

Odpowiedzi

HTTP 200 - Grupy

{
  "data": [
    {
      "id": "gr_Zq7Lk2Pm9sT1",
      "name": "VIP",
      "members": 2,
      "created_at": "2026-09-07T10:00:00.000Z"
    }
  ]
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

POST /v1/groups

Utwórz grupę

Nazwa do 80 znaków, unikalna w koncie (bez rozróżniania wielkości liter). Grupę tworzy też automatycznie POST /v1/contacts z nieznaną nazwą w groups. Wymaga zakresu manage.

Treść żądania (JSON)

PoleTypOpis
name wymaganestring np. "VIP"

Odpowiedzi

HTTP 201 - Utworzono

PoleTypOpis
idstring np. "gr_Zq7Lk2Pm9sT1"
namestring np. "VIP"
membersintegerLiczba kontaktów w grupie np. 2
created_atstring
{
  "id": "gr_Zq7Lk2Pm9sT1",
  "name": "VIP",
  "members": 0,
  "created_at": "2026-09-07T10:00:00.000Z"
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 409 - Grupa o tej nazwie już istnieje

GET /v1/groups/{id}

Pobierz grupę

Grupa z liczbą członków. Listę członków pobierzesz przez GET /v1/contacts?group_id=…. Wymaga zakresu read.

Parametry

NazwaTypOpis
id path wymaganestring

Odpowiedzi

HTTP 200 - Grupa

PoleTypOpis
idstring np. "gr_Zq7Lk2Pm9sT1"
namestring np. "VIP"
membersintegerLiczba kontaktów w grupie np. 2
created_atstring

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

PATCH /v1/groups/{id}

Zmień nazwę grupy

Wymaga zakresu manage.

Parametry

NazwaTypOpis
id path wymaganestring

Treść żądania (JSON)

PoleTypOpis
name wymaganestring np. "Klienci VIP"

Odpowiedzi

HTTP 200 - Zmieniono

{
  "id": "gr_Zq7Lk2Pm9sT1",
  "name": "Klienci VIP"
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

DELETE /v1/groups/{id}

Usuń grupę

Usuwa grupę i jej przypisania; kontakty zostają w książce. Wymaga zakresu manage.

Parametry

NazwaTypOpis
id path wymaganestring

Odpowiedzi

HTTP 200 - Usunięto

{
  "deleted": "gr_Zq7Lk2Pm9sT1"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

POST /v1/groups/{id}/contacts

Dodaj kontakty do grupy

Dodaje istniejące kontakty (contact_ids) i/lub numery (msisdns - nieznane numery są tworzone jako kontakty bez imienia). Łącznie do 500 na żądanie; id spoza konta są pomijane, błędne numery wracają w invalid. Wymaga zakresu manage.

Parametry

NazwaTypOpis
id path wymaganestring

Treść żądania (JSON)

PoleTypOpis
contact_idsarray<string>Id kontaktów `ct_…`
msisdnsarray<string>Numery (brakujące kontakty są tworzone)
{
  "msisdns": [
    "+48600100203",
    "+48600100204"
  ]
}

Odpowiedzi

HTTP 200 - Dodano

{
  "id": "gr_Zq7Lk2Pm9sT1",
  "added": 2,
  "invalid": [],
  "members": 4
}

HTTP 400 - Błąd walidacji

{
  "error": {
    "code": "invalid_request",
    "message": "Nieprawidłowy numer odbiorcy: +48XXXXXXXXX",
    "param": "to"
  },
  "request_id": "req_…"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono

DELETE /v1/groups/{id}/contacts/{contactId}

Usuń kontakt z grupy

Odpina kontakt od grupy; kontakt zostaje w książce. Wymaga zakresu manage.

Parametry

NazwaTypOpis
id path wymaganestring
contactId path wymaganestring

Odpowiedzi

HTTP 200 - Odpięto

{
  "removed": "ct_8fK2mQpL0aXz4Wv1"
}

HTTP 401 - Brak lub nieprawidłowy klucz API

{
  "error": {
    "code": "unauthorized",
    "message": "Nieprawidłowy klucz API"
  },
  "request_id": "req_…"
}

HTTP 403 - Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)

{
  "error": {
    "code": "forbidden",
    "message": "Ten klucz API nie ma zakresu \"send\". Wygeneruj klucz z odpowiednim zakresem w panelu (app.przypominamy.com/keys)."
  },
  "request_id": "req_…"
}

HTTP 404 - Nie znaleziono grupy albo kontakt nie należy do tej grupy

Schematy

Schemat: MessageStatus

scheduled, queued, sent, delivered, undelivered, failed, expired, rejected, cancelled

`scheduled` - zaplanowana (`send_at` lub przesunięta przez `send_window`); `queued` - przyjęta; `sent` - przekazana do sieci; `delivered` - doręczona; `undelivered` - niedoręczona; `failed` - odrzucona przez dostawcę; `rejected` - odrzucona przez nas (numer na czarnej liście, koszt 0); `expired` - wygasła (m.in. po `expires_at`); `cancelled` - zaplanowana wysyłka anulowana przez `DELETE /v1/messages/{id}`, koszt zwrócony

Schemat: SendMessageRequest

PoleTypOpis
to wymaganestring | arrayNumer odbiorcy, `"group:<id lub nazwa grupy>"` albo tablica numerów i grup (łącznie do 500 odbiorców po rozwinięciu, duplikaty usuwane) np. "+48600100200"
textstringTreść. Polskie znaki dozwolone (UCS-2, 70/67 znaków na część). Placeholdery: `{{imie}}`, `{{nazwisko}}`, `{{email}}`, `{{<pole_własne>}}` (z kontaktów - dla grup i dla numerów, które są w książce) i `{{opt_out}}` / `{{wypisz}}` (osobisty link wypisu) oraz `{{link:https://…}}` (śledzony krótki link per odbiorca, do 2 różnych adresów). Wymagane, chyba że podajesz `template_id`. np. "Przypominamy o wizycie jutro o 10:00."
template_idstringId szablonu (`tpl_…`, z `GET /v1/templates`) zamiast `text`. Szablon musi być typu `sms` (w `POST /v1/mms` - `mms`, w `POST /v1/voice` - `vms`), inaczej 400 z `param: "template_id"`; nieznany → 404. Placeholdery `{{klucz}}` podstawiane z `params`, pozostałe z kontaktów albo pustym ciągiem. np. "tpl_Q3m7kL2pXa9dRt"
paramsobjectWartości placeholderów szablonu, np. `{ "kiedy": "jutro 10:00" }` → `{{kiedy}}`. Klucze bez rozróżniania wielkości liter. Tylko z `template_id`. np. {"kiedy": "jutro 10:00", "lekarz": "dr Nowak"}
fromstringNadpis (nazwa nadawcy). Musi być aktywny na liście `GET /v1/senders`. Domyślnie nadpis konta. np. "ZDROWKO"
send_atstringZaplanowana wysyłka (ISO 8601), do 90 dni w przód. Daty w przeszłości = wysyłka natychmiast. np. "2026-09-08T08:00:00Z"
send_windowstringOkno godzin wysyłki w czasie polskim (`HH:MM-HH:MM`, min. 15 minut, koniec wyłączny). Wysyłka spoza okna (teraz albo `send_at`) jest przesuwana na najbliższy początek okna i dostaje status `scheduled`. Pominięte = domyślne okno konta z `PATCH /v1/account`. np. "08:00-20:00"
expires_atstringWażność: po tym czasie dostawca przestaje próbować doręczyć (status `expired`). Od 15 minut do 72 godzin po czasie wysyłki. np. "2026-09-08T20:00:00+02:00"
referencestringTwój identyfikator (np. id wizyty). Wraca w odpowiedzi, webhookach i jako filtr w `GET /v1/messages`. np. "wizyta-4711"
prioritybooleanSMS priorytetowy: osobna, szybka kolejka u operatora (kody OTP, alerty). Cena za część × 2. Tylko SMS - w `POST /v1/mms` i `POST /v1/voice` ignorowane. Wartość inna niż `true`/`false` → 400. np. false

Schemat: Message

PoleTypOpis
idstring np. "msg_qY08hZ2mmDXAazdRTytS"
typestring: sms, mms, vmsKanał: SMS, MMS, wiadomość głosowa
statusstring: scheduled, queued, sent, delivered, undelivered, failed, expired, rejected, cancelled`scheduled` - zaplanowana (`send_at` lub przesunięta przez `send_window`); `queued` - przyjęta; `sent` - przekazana do sieci; `delivered` - doręczona; `undelivered` - niedoręczona; `failed` - odrzucona przez dostawcę; `rejected` - odrzucona przez nas (numer na czarnej liście, koszt 0); `expired` - wygasła (m.in. po `expires_at`); `cancelled` - zaplanowana wysyłka anulowana przez `DELETE /v1/messages/{id}`, koszt zwrócony
tostring np. "+48600100200"
fromstring | null np. "ZDROWKO"
textstringTreść po personalizacji - dokładnie to, co dostał odbiorca (link opt-out, śledzone linki `api.przypominamy.com/l/…` i placeholdery już podstawione)
subjectstring | nullTemat (tylko MMS)
partsinteger np. 1
cost_groszeintegerKoszt w groszach (0 dla odrzuconych; po anulowaniu zwrócony na saldo) np. 9
prioritybooleanCzy wysłano jako SMS priorytetowy (podwójna stawka) np. false
referencestring | null
send_atstring | nullTermin wysyłki (po przesunięciu przez `send_window`, jeśli było)
expires_atstring | nullKoniec prób doręczenia, gdy podano `expires_at`
delivered_atstring | null
errorstring | nullPowód odrzucenia, gdy status = failed lub rejected (np. „Numer na czarnej liście (opt-out)”)
created_atstring
updated_atstring

Schemat: BatchResult

PoleTypOpis
countintegerLiczba unikalnych odbiorców (po rozwinięciu grup)
acceptedintegerIlu odbiorców przyjęto do wysyłki (bez `failed` i `rejected`)
total_cost_groszeinteger
test_modeboolean`true` na koncie testowym (koszt z puli testowej, nie z salda); pomijane na koncie live
messagesarray<object>

Schemat: Account

PoleTypOpis
country_ratesobjectIndywidualne stawki zagraniczne: prefiks numeru → ceny kanałów w groszach netto. Bez pasującej stawki SMS kosztuje 2× krajową cenę konta; MMS i głos wymagają osobnej wyceny. Najdłuższy prefiks wygrywa. Polska używa standardowej ceny konta.
idstring np. "cl_3W4997VtDI8fG1hM"
namestring
sender_namestring | null np. "ZDROWKO"
balance_groszeinteger np. 4982
credit_limit_groszeinteger np. 0
price_per_part_groszeinteger np. 9
price_per_mms_groszeinteger np. 35
price_per_vms_groszeinteger np. 25
price_per_hlr_groszeintegerCena sprawdzenia numeru (HLR) w groszach np. 5
rate_limit_per_minuteinteger np. 120
webhook_urlstring | null
statusstring: active, suspended, closed
modestring: test, live`test` - tylko zweryfikowane numery, koszt z puli testowej
test_creditsintegerPozostałe darmowe wiadomości (tylko w trybie `test`)
send_windowstring | nullDomyślne okno godzin wysyłki konta (czas polski) lub `null` np. "08:00-20:00"
billing_modestring: prepaid, postpaid`prepaid` (domyślnie) - saldo doładowane z góry. `postpaid` - włączany przez nas na życzenie po weryfikacji firmy: saldo może zejść poniżej zera do `credit_limit_grosze`, 1. dnia miesiąca wystawiamy zestawienie za poprzedni miesiąc (14 dni na przelew, tytuł = id zestawienia), po terminie wysyłki są wstrzymane (402 `insufficient_funds`) do zaksięgowania wpłaty. np. "prepaid"
inbound_numberstring | nullNumer odbiorczy, na który odbiorcy mogą odpisać (2-way). Odbiór uruchamiamy na życzenie - `null`, dopóki nie jest włączony dla konta np. "+48799000000"
inbound_prefixstring | nullTwoje słowo kluczowe: SMS zaczynający się od niego trafia do Twojego konta niezależnie od wcześniejszych wysyłek (`PATCH /v1/account`) np. "ZDROWKO"
scopesarray<string>Zakresy klucza użytego w tym żądaniu np. ["send", "read", "manage"]
international_smsobjectDomyślna cena SMS zagranicznego netto za część. Kraje UE aktywne; inne kierunki po potwierdzeniu dostępności.

Schemat: Template

PoleTypOpis
idstring np. "tpl_Q3m7kL2pXa9dRt"
namestring np. "Wizyta"
typestring: sms, mms, vmsKanał, do którego pasuje szablon - musi zgadzać się z endpointem wysyłki
bodystringTreść z placeholderami `{{klucz}}` (dla MMS - dokument SMIL) np. "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}."
subjectstring | nullTemat (tylko MMS)
placeholdersarray<string>Placeholdery znalezione w `body`, małymi literami np. ["imie", "kiedy", "lekarz"]
created_atstring
updated_atstring

Schemat: TemplateInput

PoleTypOpis
name wymaganestring np. "Wizyta"
typestring: sms, mms, vmsDomyślnie `sms`
body wymaganestringTreść z placeholderami `{{klucz}}` np. "Cześć {{imie}}, wizyta {{kiedy}} u {{lekarz}}."
subjectstring | nullTemat (tylko MMS)

Schemat: HlrResult

PoleTypOpis
msisdnstring np. "+48600100200"
statusstring: active, inactive, invalid, unknown`active` - numer w sieci; `inactive` - nieosiągalny lub nieistniejący; `invalid` - zły format; `unknown` - operator nie odpowiedział jednoznacznie
networkstring | nullNazwa sieci (Plus, T-Mobile, Orange, Play…) np. "T-Mobile"
mccstring | null np. "260"
mncstring | null np. "02"
portedboolean | nullCzy numer został przeniesiony do innej sieci
cost_groszeintegerPobrana opłata (0 dla wyniku z pamięci i na koncie testowym) np. 5
cachedboolean`true` - wynik z ostatnich 24 h, bez opłaty i bez pytania operatora
checked_atstringKiedy operator sprawdził numer

Schemat: BlacklistEntry

PoleTypOpis
msisdnstring np. "+48600100200"
reasonstring | null`opt_out` (link wypisu), `manual` (domyślne przy dodaniu przez API) lub własny opis np. "opt_out"
created_atstring
expires_atstring | nullKoniec blokady; `null` = bezterminowo

Schemat: ContactInput

PoleTypOpis
msisdnstringNumer (E.164, bez plusa lub 9 cyfr = Polska); klucz upsertu np. "+48600100200"
first_namestring | nullImię - placeholder `{{imie}}` np. "Anna"
last_namestring | nullNazwisko - placeholder `{{nazwisko}}` np. "Nowak"
emailstring | nullPlaceholder `{{email}}`
fieldsobject | nullPola własne (do 20; klucz `[a-zA-Z_][a-zA-Z0-9_]{0,30}`) - placeholder `{{nazwa_pola}}` np. {"wizyta": "10.09 14:00"}
groupsarray<string>Nazwy lub id grup; nieistniejące nazwy są tworzone; zastępuje dotychczasowe przypisania np. ["VIP"]

Schemat: Contact

PoleTypOpis
idstring np. "ct_8fK2mQpL0aXz4Wv1"
msisdnstring np. "+48600100200"
first_namestring | null np. "Anna"
last_namestring | null np. "Nowak"
emailstring | null
fieldsobjectPola własne np. {"wizyta": "10.09 14:00"}
groupsarray<object>
created_atstring
updated_atstring

Schemat: Group

PoleTypOpis
idstring np. "gr_Zq7Lk2Pm9sT1"
namestring np. "VIP"
membersintegerLiczba kontaktów w grupie np. 2
created_atstring

Schemat: InboundMessage

PoleTypOpis
idstring np. "in_Xp4Rn8Kd2Lq6Wz1a"
fromstringNumer nadawcy (E.164) np. "+48600100200"
tostring | nullNumer odbiorczy, na który przyszła wiadomość np. "+48799000000"
textstringTreść; przy dopasowaniu po słowie kluczowym - bez tego słowa np. "TAK"
reply_tostring | nullId Twojej ostatniej wiadomości do tego numeru z ostatnich 30 dni (`msg_…`), jeśli była np. "msg_qY08hZ2mmDXAazdRTytS"
matched_bystring: prefix, last_messageJak wiadomość trafiła do Twojego konta: `prefix` - zaczynała się od Twojego słowa kluczowego, `last_message` - Ty ostatni pisałeś na ten numer
received_atstring
read_atstring | nullKiedy oznaczono jako przeczytaną (`mark_read=true` w `GET /v1/inbound` albo panel)

Schemat: WebhookEvent

PoleTypOpis
idstring np. "evt_…"
typestring: message.sent, message.delivered, message.undelivered, message.failed, message.expired, message.received, link.clicked
created_atstring
dataobject

Schemat: Error

PoleTypOpis
errorobject
request_idstring np. "req_DbIaEbKi5pbRgjCV"