SMS brána přes API za 10 minut v Node.js
2. 9. 2026 · 6 minut čtení
Abys z Node.js poslal SMS, stačí jeden POST požadavek na https://volai.cz/v1/messages s hlavičkou Authorization: Bearer vk_... a JSON tělem {to, body}. Node 20 má fetch vestavěný, takže nepotřebuješ žádný balíček navíc. Funkční příklad je hned pod tímhle odstavcem, včetně ošetření chyb a idempotence, aby ti výpadek sítě neposlal stejnou zprávu dvakrát.
Co budeš potřebovat
- Node.js 18 nebo novější -
fetchje ve vestavěné knihovně už od téhle verze; doporučujeme aktuální podporovanou LTS řadu (24, stav k 2. 9. 2026). - Účet na volai a API klíč z portálu (Nastavení -> API a MCP), ve tvaru
vk_.... - Telefonní číslo příjemce v Česku nebo na Slovensku (
+420nebo+421) - jiné země posílání SMS v MVP nepodporuje. - Vlastní telefonní číslo NEPOTŘEBUJEŠ. Odesílatel je vždy pevné jméno
volai- operátoři nedovolují nastavit vlastní jméno odesílatele SMS. Svou identitu proto napiš přímo do textu zprávy, tak jako v příkladu níž.
Pošli první SMS
Requestu stačí dvě pole: to (číslo příjemce) a body (text zprávy). Odpověď vrátí id zprávy, status, cenu v haléřích (priceHal) a počet segmentů (segments) - k oběma se za chvíli vrátíme.
const response = await fetch("https://volai.cz/v1/messages", {
method: "POST",
headers: {
Authorization: "Bearer vk_TVUJ_KLIC",
"Content-Type": "application/json",
},
body: JSON.stringify({
to: "+420777123456",
body: "Ahoj z volai! - Moje Appka",
}),
});
if (!response.ok) {
const { error } = await response.json();
throw new Error("volai " + error.code + ": " + error.message);
}
const message = await response.json();
console.log(message);
// { id: "msg_7c1f9a2e", status: "sent", priceHal: 136, segments: 1 }Kolik stojí SMS a co jsou segmenty?
Jedna SMS do jednoho segmentu stojí 1,36 Kč bez DPH (cena platná k 2. 9. 2026). Kolik segmentů zpráva zabere, závisí na tom, jestli obsahuje diakritiku - operátoři počítají SMS podle standardu GSM 03.38:
| Kódování | Znaků v 1. segmentu | Znaků v dalších dílech |
|---|---|---|
| GSM-7 (bez diakritiky) | 160 | 153 |
| UCS-2 (s diakritikou) | 70 | 67 |
Stačí JEDEN znak mimo základní GSM-7 abecedu - typicky česká diakritika (ě š č ř ž ý á í ů ď ť ň) - a celá zpráva přepne na UCS-2, i kdyby byl ve zprávě jen jeden háček. Tip: chceš-li se spolehlivě vejít do jednoho segmentu, piš bez diakritiky.
Příklad: zpráva s diakritikou nad 70 znaků
Tahle zpráva má 112 znaků a obsahuje diakritiku, takže se počítá jako UCS-2 (limit 67 znaků na segment u vícedílné zprávy) - vyjde na 2 segmenty, tedy 2,72 Kč, ne 1,36 Kč:
await fetch("https://volai.cz/v1/messages", {
method: "POST",
headers: {
Authorization: "Bearer vk_TVUJ_KLIC",
"Content-Type": "application/json",
},
body: JSON.stringify({
to: "+420777123456",
body: "Příliš žluťoučký kůň úpěl ďábelské ódy - a tahle věta má přes sedmdesát znaků, takže spadne do druhého segmentu.",
}),
});
// -> { id: "msg_9a3f1c7d", status: "sent", priceHal: 272, segments: 2 }Idempotence: bezpečné opakování požadavku
Pošli navíc hlavičku Idempotency-Key s libovolným vlastním řetězcem, třeba ID objednávky. Když požadavek selže na výpadku sítě a workflow ho zopakuje se STEJNOU hlavičkou, volai vrátí uloženou odpověď z prvního pokusu a zprávu neodešle podruhé - klíč platí 24 hodin.
curl -X POST https://volai.cz/v1/messages \
-H "Authorization: Bearer vk_TVUJ_KLIC" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: objednavka-4471" \
-d '{"to": "+420777123456", "body": "Vaše objednávka č. 4471 byla přijata."}'Bezpečně zacházej s API klíčem
API klíč (vk_...) má stejnou váhu jako heslo - kdokoli ho zná, může tvým jménem posílat zprávy a utrácet kredit z tvého účtu. Do zdrojového kódu, který commitneš do repozitáře, ho proto nepiš nikdy. Patří do proměnné prostředí (process.env.VOLAI_API_KEY v Node.js) nebo do správce tajemství, který používá tvůj hosting.
// .env.local (nikdy necommituj do repozitáře)
// VOLAI_API_KEY=vk_tvuj_klic
const response = await fetch("https://volai.cz/v1/messages", {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.VOLAI_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ to, body }),
});Endpoint volej vždy ze serveru, ne z prohlížeče - kdokoli by si klíč přečetl v developerských nástrojích prohlížeče a začal na tvůj účet posílat vlastní zprávy. Uniknul-li klíč (třeba omylem v commitu), vygeneruj si v portálu nový a ten starý zneplatni - stará hodnota přestane fungovat okamžitě.
Vyzkoušej to nejdřív bezpečně
Než napojíš odesílání SMS na skutečný proces (třeba potvrzení objednávky), pošli první pár zpráv na vlastní telefonní číslo. Uvidíš přesně to, co uvidí zákazník - jak vypadá odesílatel volai, jak dlouho doručení trvá a jestli se diakritika počítá tak, jak čekáš. Teprve pak přepni to na skutečné číslo zákazníka.
Co dělat, když API vrátí chybu?
Neúspěšná odpověď má vždy tvar {error: {code, message}} a HTTP status podle typu chyby:
| Stav | Kód | Co to znamená |
|---|---|---|
| 400 | invalid_number | To není platné české nebo slovenské telefonní číslo. |
| 400 | invalid_body | Text zprávy musí mít 1 až 765 znaků. |
| 400 | unsupported_country | Číslo mimo ČR/SR - v MVP nepodporujeme. |
| 400 | recipient_cannot_receive_sms | Pevná linka - SMS by nedorazila. Nic se neúčtuje. |
| 402 | insufficient_credit | Kredit nepokryje cenu všech segmentů zprávy. |
| 429 | rate_limited | Víc než 1 SMS za 2 vteřiny, nebo přes 100 SMS na účet denně. |
| 502 | send_failed | Telefonní síť žádost odmítla. Kredit se nestrhl, zkus to znovu. |
| 502 | send_unknown | Zprávu jsme předali síti, potvrzení nedorazilo - účtuje se, neposílej ji prosím znovu naslepo. |
Jaké stavy může zpráva mít?
Pole status ve výpisu (GET /v1/messages) i v detailu jedné zprávy nabývá čtyř hodnot: pending (uložená, ještě se odesílá), sent (operátor odeslání potvrdil), failed (operátor odmítl - neúčtuje se) a unknown (potvrzení o doručení nedorazilo, typicky timeout na straně operátora - přesto se účtuje plnou cenou, protože zpráva mohla dojít).
Jak rozeslat víc SMS najednou?
Rate limit dovoluje nejvýš jednu SMS za dvě vteřiny na účet a nejvýš 100 SMS denně. Pro rozeslání víc zpráv najednou (třeba připomínek schůzek) je jednodušší mezi požadavky krátce počkat, než chytat rate_limited a zkoušet znovu:
const messageText = "Připomínáme zítřejší termíny - Moje Appka";
for (const to of recipients) {
const response = await fetch("https://volai.cz/v1/messages", {
method: "POST",
headers: {
Authorization: "Bearer vk_TVUJ_KLIC",
"Content-Type": "application/json",
},
body: JSON.stringify({ to, body: messageText }),
});
if (!response.ok) {
const { error } = await response.json();
console.error("volai " + to + ": " + error.code);
}
// Limit je nejvýš 1 SMS za 2 vteřiny na účet - krátká pauza mezi
// požadavky je jednodušší než řešit rate_limited a zkoušet znovu.
await new Promise((resolve) => setTimeout(resolve, 2100));
}Příchozí SMS API nevidí
volai SMS jen ODESÍLÁ, přijímat je neumí. Odpověď zákazníka na tvoji zprávu se nikde neobjeví - ani v GET /v1/messages, ani ve webhooku. Na obousměrnou komunikaci přes SMS zatím nespoléhej; kdy je pro tenhle případ lepší volba Twilio, popisuje srovnání Twilio a volai.
Shrnutí: jeden POST /v1/messages s poli to a body pošle SMS, hlavička Idempotency-Key ochrání workflow před dvojím odesláním při opakování požadavku a cena se počítá po segmentech podle toho, jestli text obsahuje diakritiku. Klíč drž mimo repozitář a nejdřív si pošli zprávu sám sobě.
Co dál
Plná reference REST API (čísla, hovory, webhooky, agenti) je na /docs/api. Chceš vědět hned, jakmile volai zprávu předá operátorovi, bez pollování GET /v1/messages? Přihlas se k odběru události message.sent - potvrzuje jen převzetí operátorem, ne doručení do telefonu (to volai nevidí, viz výš) - viz dokumentace webhooků. A pokud kromě SMS potřebuješ i telefonní číslo, které samo zvedá hovory, mrkni na AI recepční.
Vyzkoušej volai - prvních 50 Kč na nás
Založíš účet za minutu a rovnou máš na kontě startovní kredit na hovory, SMS i číslo.
Související články
Jak zavolat zákazníkovi z n8n workflow
Zavolej zákazníkovi přímo z n8n: HTTP Request node na REST API volai, proměnné z workflow v promptu agenta a výsledek hovoru zpátky webhookem.
Jak dát Claude Code telefonní číslo přes MCP
Nainstaluj volai do Claude Code jedním příkazem, dej mu telefonní číslo a nech ho zavolat i poslat SMS jen promptem - bez psaní kódu, bez API dokumentace.
Kolik stojí AI recepční pro malou firmu
Rozpad ceny AI recepční na telefonu: číslo, minuty a agent z ceníku volai, tři scénáře podle provozu a srovnání s tím, co dnes účtují čeští poskytovatelé.