← Zpět na blog
24. října 2026·7 min čtení·Tým TopSMS

Automatické připomínky termínů přes API: naplánujte SMS 24 hodin předem a zrušte ji jedním voláním

Jak z rezervačního systému naplánovat SMS připomínku na konkrétní čas polem send_at (až 30 dní dopředu), dostat jobId, zrušit ji při odvolání termínu s vrácením kreditu a pojistit se Idempotency-Key. Kompletní curl, Node.js a PHP příklady.

Související služba: SMS pro zdravotnictví →

Rezervační systém zná termín ve chvíli, kdy ho zákazník vytvoří. Nejjednodušší způsob, jak poslat připomínku 24 hodin předem, tedy není cron, který každou hodinu prochází databázi, ale naplánovat SMS hned při vytvoření rezervace a při jejím zrušení plán odvolat. Přesně to umí pole send_at v TopSMS API. Tento článek ukazuje celý postup včetně zrušení s vrácením kreditu, ochrany proti duplicitám a hotových příkladů.

Krátká odpověď

KrokVoláníVýsledek
Naplánovat připomínkuPOST /api/sms/send s polem send_at202 se stavem scheduled a jobId
Zjistit stavGET /api/sms/jobs/{jobId}scheduled / queued / running / done / failed / cancelled
Zrušit při odvolání termínuDELETE /api/sms/jobs/{jobId}cancelled, cena se vrátí na kredit
Pojistit proti dvojímu odesláníhlavička Idempotency-Keyopakovaný požadavek vrátí původní odpověď, SMS neodejde znovu

send_at je ISO 8601 s časovou zónou (nebo Unix timestamp), nejvýš 30 dní dopředu. Kredit se strhne při naplánování a při zrušení se vrátí.

1. Naplánování SMS polem send_at

Do běžného odeslání přidáte jedno pole. Autentizace je Authorization: Bearer clientId:secret, klíč vytvoříte v dashboardu v sekci API přístup.

curl -X POST https://www.topsms.cz/api/sms/send \
  -H "Authorization: Bearer CLIENT_ID:SECRET" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: rez-18342-24h" \
  -d '{
    "to": "+420600000000",
    "text": "Dobry den, pripominame termin zitra 25. 10. v 9:30, Salon Iva, Brno. Zmena terminu: 541 123 456.",
    "from": "SalonIva",
    "send_at": "2026-10-24T09:30:00+02:00"
  }'

Odpověď je 202 Accepted:

{
  "ok": true,
  "scheduled": true,
  "id": "cmv...",
  "jobId": "cmw...",
  "status": "scheduled",
  "sendAt": "2026-10-24T07:30:00.000Z",
  "price": 0.98,
  "statusUrl": "https://www.topsms.cz/api/sms/jobs/cmw..."
}

Pravidla pro send_at:

  • Vždy s časovou zónou: +02:00, +01:00 nebo Z. Bez zóny API vrátí 400 s kódem invalid_send_at. Zónu nechte generovat knihovnu pro práci s časem, aby vám při přechodu letního a zimního času neodjela připomínka o hodinu jinam.
  • Nejvýš 30 dní dopředu. Pro rezervace dál v budoucnosti naplánujte SMS až ve chvíli, kdy se termín dostane do 30denního okna (např. nočním jobem).
  • Čas do 1 minuty od teď se pošle hned, bez plánování. Čas o více než několik minut v minulosti vrátí 400.
  • Cena odpovídá vašemu tarifu a počtu segmentů (0,98 Kč za segment do ČR a SR v základním tarifu). Text bez diakritiky se vejde do 160 znaků, s diakritikou jen 70; připomínky proto pište bez háčků a čárek, nebo krátce.

Pole from přijme jen schválené Sender ID vašeho účtu nebo výchozí TopSMS. Dokud jméno není schválené, pole vynechte.

2. Zrušení připomínky s vrácením kreditu

Zákazník termín zrušil nebo přesunul. Uložený jobId pošlete na:

curl -X DELETE https://www.topsms.cz/api/sms/jobs/cmw... \
  -H "Authorization: Bearer CLIENT_ID:SECRET"

Odpověď:

{ "ok": true, "id": "cmw...", "status": "cancelled", "cancelled": 1, "refunded": 0.98 }

Cena se vrátila na kredit. Dvě situace, se kterými musí váš kód počítat:

OdpověďVýznamCo udělat
409 s code: "not_cancellable"Zpráva se už odesílá nebo odešla.Nic, připomínka už u zákazníka je. Zalogujte a pokračujte.
404jobId neexistuje nebo nepatří k vašemu klíči.Zkontrolujte uložené ID.

Zrušení vyžaduje scope send, čtení stavu scope read. Přesun termínu řešte jako zrušení + nové naplánování s novým Idempotency-Key.

3. Idempotency-Key = ID rezervace

Když vašemu serveru vypadne spojení uprostřed požadavku, nevíte, zda SMS byla naplánována. Bez ochrany byste ji při opakování naplánovali dvakrát a zákazník by dostal dvě připomínky. Hlavička Idempotency-Key to řeší: opakovaný požadavek se stejným klíčem vrátí původní odpověď s hlavičkou Idempotent-Replayed: true a nic nového nevznikne.

Doporučený tvar klíče je ID rezervace plus označení připomínky, například rez-18342-24h a rez-18342-2h. Pravidla:

  • 1 až 255 tisknutelných ASCII znaků bez mezer, platnost 24 hodin, vázaný na váš API klíč;
  • stejný klíč s jiným tělem vrátí 422 (idempotency_mismatch), proto po přesunu termínu použijte nový klíč, třeba s pořadovým číslem verze: rez-18342-24h-v2;
  • chyby 401, 402, 409, 429 a většina 5xx se neukládají, takže po odstranění příčiny můžete stejný klíč použít znovu.

4. Vzor: připomínka 24 hodin a 2 hodiny předem

V praxi funguje nejlépe dvojice zpráv: den předem (zákazník si může termín ještě přesunout) a dvě hodiny předem (už nezapomene). Postup při vytvoření rezervace:

  1. Spočítejte send_at pro oba časy z termínu rezervace.
  2. Pošlete dva požadavky POST /api/sms/send, každý s vlastním Idempotency-Key.
  3. Oba jobId uložte k rezervaci.
  4. Při zrušení zavolejte DELETE na oba; 409 not_cancellable berte jako „už odešlo".
  5. Pokud je termín do 2 hodin od vytvoření, druhou zprávu vynechte; pokud je do 24 hodin, vynechte první.

Kdy připomínky posílat a jaké texty fungují, rozebírá článek SMS připomínky termínů.

Node.js

const BASE = 'https://www.topsms.cz/api/sms';
const AUTH = 'Bearer ' + process.env.TOPSMS_KEY; // "clientId:secret"

async function scheduleSms({ to, text, sendAt, key }) {
  const res = await fetch(`${BASE}/send`, {
    method: 'POST',
    headers: { Authorization: AUTH, 'Content-Type': 'application/json', 'Idempotency-Key': key },
    body: JSON.stringify({ to, text, send_at: sendAt.toISOString() }),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
  return data.jobId; // null, pokud byl cas do 1 minuty a SMS odesla hned
}

async function cancelSms(jobId) {
  const res = await fetch(`${BASE}/jobs/${jobId}`, { method: 'DELETE', headers: { Authorization: AUTH } });
  if (res.status === 409) return 'already_sent';
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return 'cancelled';
}

// pri vytvoreni rezervace
const start = new Date('2026-10-25T09:30:00+02:00');
const text = 'Dobry den, pripominame termin 25. 10. v 9:30, Salon Iva. Zmena: 541 123 456.';
const job24 = await scheduleSms({ to: '+420600000000', text, sendAt: new Date(start - 24 * 3600e3), key: 'rez-18342-24h' });
const job2  = await scheduleSms({ to: '+420600000000', text, sendAt: new Date(start - 2 * 3600e3),  key: 'rez-18342-2h' });
// ulozte job24 a job2 k rezervaci; pri zruseni: await cancelSms(job24); await cancelSms(job2);

toISOString() vrací čas v UTC se sufixem Z, což API přijme; převod z místního času rezervace řeší Date sám.

PHP

<?php
function topsms(string $method, string $path, ?array $body = null, ?string $key = null): array {
    $headers = ['Authorization: Bearer ' . getenv('TOPSMS_KEY'), 'Content-Type: application/json'];
    if ($key) $headers[] = 'Idempotency-Key: ' . $key;
    $ch = curl_init('https://www.topsms.cz/api/sms' . $path);
    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POSTFIELDS => $body ? json_encode($body) : null,
    ]);
    $data = json_decode(curl_exec($ch), true) ?: [];
    $data['httpStatus'] = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    return $data;
}

$start = new DateTimeImmutable('2026-10-25 09:30', new DateTimeZone('Europe/Prague'));
$text  = 'Dobry den, pripominame termin 25. 10. v 9:30, Salon Iva. Zmena: 541 123 456.';

$r = topsms('POST', '/send', [
    'to' => '+420600000000',
    'text' => $text,
    'send_at' => $start->modify('-24 hours')->format(DATE_ATOM), // vcetne +02:00
], 'rez-18342-24h');
$jobId = $r['jobId'] ?? null; // ulozit k rezervaci

// pri zruseni terminu
$c = topsms('DELETE', '/jobs/' . $jobId);
// $c['status'] === 'cancelled' nebo $c['httpStatus'] === 409 (uz odeslano)

DATE_ATOM vrací tvar 2026-10-24T09:30:00+02:00, tedy přesně to, co send_at očekává. Pro odesílání bez plánování můžete použít i knihovnu topsms/topsms-php, odkaz je v dokumentaci API.

5. Testování bez odeslání a bez útraty

Při vytváření API klíče zaškrtněte Testovací klíč. Nic neodešle ani neúčtuje, ale vrací stejné odpovědi jako ostrý klíč, včetně simulovaných doručenek na webhook. Jedna výjimka se týká právě plánování: testovací klíč s send_at vrátí 200 se "scheduled": true, ale bez jobId, takže zrušení si otestujete až s ostrým klíčem. Na to stačí 10 testovacích SMS, které dostanete po registraci; zrušená připomínka se navíc vrátí na kredit, takže test nic nestojí.

6. Doručenky k naplánovaným zprávám

Naplánovaná zpráva má po odeslání stejný životní cyklus jako běžná SMS: sent, delivered, případně failed s důvodem v errorCode. Pokud chcete v rezervačním systému vidět, že připomínka dorazila, nastavte u API klíče webhook URL. Při doručení či selhání pošleme HTTP POST s podpisem X-TopSMS-Signature (HMAC-SHA256 těla), 3 pokusy doručení. Podrobnosti najdete na stránce Webhooky, přehled stavů a chybových kódů v článku Proč SMS nedorazila.

Shrnutí pro vývojáře

  • send_at v ISO 8601 se zónou, max 30 dní, odpověď 202 + jobId, kredit se strhne hned.
  • DELETE /api/sms/jobs/{jobId} zruší a vrátí kredit; 409 not_cancellable znamená, že už odešlo.
  • Idempotency-Key = ID rezervace + typ připomínky; po přesunu termínu nový klíč.
  • Rate limit je 60 požadavků za minutu na klíč (v dashboardu zvýšíte až na 1 000), což pro rezervační systém bohatě stačí.
  • Pro hromadné naplánování (třeba všechny zítřejší termíny jedním voláním) funguje send_at i v POST /api/sms/send-bulk až pro 500 příjemců.

Příklady textů připomínek pro ordinace, salony a restaurace najdete na stránce SMS připomínka rezervace pro lékaře a v přehledu SMS pro zdravotnictví.

Jak začít

  • Registrace zdarma, trvá minutu, API klíč máte v dashboardu hned.
  • 10 testovacích SMS a testovací klíč, který nic neúčtuje, na odladění celého postupu.
  • Úplná dokumentace včetně OpenAPI: REST API.
apipřipomínkyrezervacevývojáři
SMS pro zdravotnictví

Připomínky termínů a výsledků, méně nedostavení se pacientů. Od 0,88 Kč za SMS, bez paušálu, 10 testovacích SMS.

Registrovat zdarma →Více o službě →