---
title: "Wyślij SMS (jeden lub wielu odbiorców)"
method: POST
path: "/v1/messages"
tags: ["Wiadomości"]
---

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

`POST /v1/messages`

## Request

- Base URL: `https://api.przypominamy.com`
- URL: `https://api.przypominamy.com/v1/messages`
- Auth: HTTP bearer

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ść.

## Headers

- `Idempotency-Key` string

## Request body

- SendMessageRequest
  - `to` union, required: Numer odbiorcy, `"group:<id lub nazwa grupy>"` albo tablica numerów i grup (łącznie do 500 odbiorców po rozwinięciu, duplikaty usuwane)
    - string
    - string[]
  - `text` string: Treść. 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`.
  - `template_id` string: Id 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.
  - `params` object: Wartości placeholderów szablonu, np. `{ "kiedy": "jutro 10:00" }` → `{{kiedy}}`. Klucze bez rozróżniania wielkości liter. Tylko z `template_id`.
  - `from` string: Nadpis (nazwa nadawcy). Musi być aktywny na liście `GET /v1/senders`. Domyślnie nadpis konta.
  - `send_at` string, date-time: Zaplanowana wysyłka (ISO 8601), do 90 dni w przód. Daty w przeszłości = wysyłka natychmiast.
  - `send_window` string: Okno 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`.
  - `expires_at` string, date-time: Ważność: po tym czasie dostawca przestaje próbować doręczyć (status `expired`). Od 15 minut do 72 godzin po czasie wysyłki.
  - `reference` string: Twój identyfikator (np. id wizyty). Wraca w odpowiedzi, webhookach i jako filtr w `GET /v1/messages`.
  - `priority` boolean: SMS 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.

## Response `201`

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

- union
  - Message
    - `id` string
    - `type` 'sms' | 'mms' | 'vms': Kanał: SMS, MMS, wiadomość głosowa
    - `status` 'scheduled' | 'queued' | 'sent' | 'delivered' | 'undelivered' | 'failed' | 'expired' | 'rejected' | 'cancelled' | 'unknown': `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; `unknown` - dostawca nie potwierdził (timeout / 5xx), saldo zarezerwowane do uzgodnienia po idx albo DLR
    - `to` string
    - `from` string, nullable
    - `text` string: Treść po personalizacji - dokładnie to, co dostał odbiorca (link opt-out, śledzone linki `api.przypominamy.com/l/…` i placeholdery już podstawione)
    - `subject` string, nullable: Temat (tylko MMS)
    - `parts` integer
    - `cost_grosze` integer: Koszt w groszach (0 dla odrzuconych; po anulowaniu zwrócony na saldo)
    - `priority` boolean: Czy wysłano jako SMS priorytetowy (podwójna stawka)
    - `reference` string, nullable
    - `send_at` string, date-time, nullable: Termin wysyłki (po przesunięciu przez `send_window`, jeśli było)
    - `expires_at` string, date-time, nullable: Koniec prób doręczenia, gdy podano `expires_at`
    - `delivered_at` string, date-time, nullable
    - `error` string, nullable: Powód odrzucenia, gdy status = failed lub rejected (np. „Numer na czarnej liście (opt-out)”)
    - `created_at` string, date-time
    - `updated_at` string, date-time
  - BatchResult
    - `count` integer: Liczba unikalnych odbiorców (po rozwinięciu grup)
    - `accepted` integer: Ilu odbiorców przyjęto do wysyłki (bez `failed` i `rejected`)
    - `total_cost_grosze` integer
    - `test_mode` boolean: `true` na koncie testowym (koszt z puli testowej, nie z salda); pomijane na koncie live
    - `messages` Message[]
      - `id` string
      - `type` 'sms' | 'mms' | 'vms': Kanał: SMS, MMS, wiadomość głosowa
      - `status` 'scheduled' | 'queued' | 'sent' | 'delivered' | 'undelivered' | 'failed' | 'expired' | 'rejected' | 'cancelled' | 'unknown': `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; `unknown` - dostawca nie potwierdził (timeout / 5xx), saldo zarezerwowane do uzgodnienia po idx albo DLR
      - `to` string
      - `from` string, nullable
      - `text` string: Treść po personalizacji - dokładnie to, co dostał odbiorca (link opt-out, śledzone linki `api.przypominamy.com/l/…` i placeholdery już podstawione)
      - `subject` string, nullable: Temat (tylko MMS)
      - `parts` integer
      - `cost_grosze` integer: Koszt w groszach (0 dla odrzuconych; po anulowaniu zwrócony na saldo)
      - `priority` boolean: Czy wysłano jako SMS priorytetowy (podwójna stawka)
      - `reference` string, nullable
      - `send_at` string, date-time, nullable: Termin wysyłki (po przesunięciu przez `send_window`, jeśli było)
      - `expires_at` string, date-time, nullable: Koniec prób doręczenia, gdy podano `expires_at`
      - `delivered_at` string, date-time, nullable
      - `error` string, nullable: Powód odrzucenia, gdy status = failed lub rejected (np. „Numer na czarnej liście (opt-out)”)
      - `created_at` string, date-time
      - `updated_at` string, date-time

## Other responses

- `400`: Błąd walidacji
- `401`: Brak lub nieprawidłowy klucz API
- `402`: Niewystarczające środki (prepaid) albo nieopłacone zestawienie miesięczne (postpaid) - nic nie zostało wysłane
- `403`: Klucz bez wymaganego zakresu (albo konto zawieszone / testowe wysyła na niezweryfikowany numer)
- `404`: Nieznana grupa w polu `to`
- `409`: Idempotency-Key użyty z inną treścią albo operacja w toku lub nierozstrzygnięta
- `422`: Odrzucone przez dostawcę SMS (numer, nadpis, długość)
- `429`: Przekroczono limit żądań
- `502`: Błąd lub brak odpowiedzi dostawcy SMS (502/504)

---

[API](https://skmtc.dev/przypominamy/apis/przypominamy-com-sms-api.md) · [All operations](https://skmtc.dev/przypominamy/apis/przypominamy-com-sms-api/llms.txt) · [OpenAPI document](https://skmtc.dev/przypominamy/apis/przypominamy-com-sms-api/revisions/c20f9cfc2a7d?raw)
