Sms-gateway via API på 10 minuter i Node.js
September 2, 2026 · 6 min läsning · Uppdaterad October 9, 2026
För att skicka ett sms från Node.js räcker ett enda POST-anrop till https://volai.cz/v1/messages med rubriken Authorization: Bearer vk_... och en JSON-kropp {to, body}. Node 20 har fetch inbyggt, så inget extra paket behövs. Ett fungerande exempel finns direkt under det här stycket, med felhantering och idempotens, så att ett nätverksavbrott inte skickar samma meddelande två gånger.
Det här behövs
- Node.js 18 eller nyare -
fetchär inbyggt från och med den versionen; vi rekommenderar den aktuella LTS-linjen som stöds (24, läge per 2 september 2026). - Ett konto hos volai och en API-nyckel från portalen (Inställningar -> API och MCP) i formen
vk_.... - Minst en påfyllning av saldot. Sms går iväg först efter den första påfyllningen, välkomstsaldot kan inte användas till dem - samtal går att prova med det, textmeddelanden inte.
- Mottagarens telefonnummer i Tjeckien eller Slovakien (
+420eller+421) - till andra länder skickar vi inte sms. - Något eget telefonnummer behövs INTE. Meddelandena går ut under det delade namnet
SMSinfo- operatörerna i de tjeckiska näten tillåter bara godkända namn, ett eget avsändarnamn kan inte ställas in för den delade avsändaren, och på SMSinfo kan mottagaren inte svara. Ange därför identiteten direkt i meddelandetexten, som i exemplet nedan. Om det ska gå att svara, skicka meddelandet från ett eget mobilnummer (tillägg, se anmärkningen längre ner).
Skicka det första sms:et
Anropet behöver bara två fält: to (mottagarens nummer) och body (meddelandetexten). Svaret innehåller meddelandets id, status, priset i hundradelar (priceHal) och antalet segment (segments) - till båda kommer vi strax tillbaka.
const response = await fetch("https://volai.cz/v1/messages", {
method: "POST",
headers: {
Authorization: "Bearer vk_DIN_NYCKEL",
"Content-Type": "application/json",
},
body: JSON.stringify({
to: "+420777123456",
body: "Hej från volai! - Min app",
}),
});
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 }Vad kostar sms och vad är segment?
Ett sms i ett segment kostar 1,36 kr exklusive moms (pris enligt läget per 2 september 2026). Hur många segment ett meddelande tar beror på om det innehåller tecken utanför GSM-7-alfabetet - operatörerna delar upp sms enligt standarden GSM 03.38:
| Teckenkodning | Tecken i 1:a segmentet | Tecken i följande delar |
|---|---|---|
| GSM-7 (vanlig latinsk text utan diakritiska tecken) | 160 | 153 |
| UCS-2 (med diakritiska eller icke-latinska tecken) | 70 | 67 |
Det räcker med ETT tecken utanför det grundläggande GSM-7-alfabetet (tecken med diakritiska tecken, emoji, de flesta icke-latinska skrifter) så växlar HELA meddelandet till UCS-2, även om bara en enda bokstav i texten har ett diakritiskt tecken. Tips: för att säkert rymmas i ett segment, skriv utan diakritiska tecken.
Exempel: meddelande med diakritiska tecken över 70 tecken
Det här meddelandet har 127 tecken och innehåller diakritiska tecken, så det räknas som UCS-2 (gräns på 67 tecken per segment i ett flerdelat meddelande) - det blir 2 segment, alltså 2,72 kr, inte 1,36 kr:
await fetch("https://volai.cz/v1/messages", {
method: "POST",
headers: {
Authorization: "Bearer vk_DIN_NYCKEL",
"Content-Type": "application/json",
},
body: JSON.stringify({
to: "+420777123456",
body: "Hej, vi påminner om din tid i morgon kl. 10:00 - passar den inte, svara på det här meddelandet så hittar vi en annan tid. Tack!",
}),
});
// -> { id: "msg_9a3f1c7d", status: "sent", priceHal: 272, segments: 2 }Idempotens: säker omsändning av anropet
Skicka dessutom rubriken Idempotency-Key med en valfri egen sträng, till exempel beställnings-ID. Om anropet misslyckas på grund av ett nätverksavbrott och flödet upprepar det med SAMMA rubrik returnerar volai det sparade svaret från det första försöket och skickar inte meddelandet en andra gång - nyckeln gäller i 24 timmar.
curl -X POST https://volai.cz/v1/messages \
-H "Authorization: Bearer vk_DIN_NYCKEL" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: bestallning-4471" \
-d '{"to": "+420777123456", "body": "Din beställning nr 4471 har tagits emot."}'Hantera API-nyckeln säkert
API-nyckeln (vk_...) väger lika tungt som ett lösenord - den som känner till den kan skicka meddelanden i kontots namn och göra av med saldot. Skriv den därför aldrig i källkod som checkas in i repot. Den hör hemma i en miljövariabel (process.env.VOLAI_API_KEY i Node.js) eller i den hemlighetshanterare som hostingleverantören erbjuder.
// .env.local (checka aldrig in i repot)
// VOLAI_API_KEY=vk_din_nyckel
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 }),
});Anropa endpointen alltid från servern, inte från webbläsaren - den som läser nyckeln i webbläsarens utvecklarverktyg kan börja skicka egna meddelanden från kontot. Om nyckeln har läckt (till exempel av misstag i en commit), skapa en ny i portalen och spärra den gamla - det gamla värdet slutar fungera omedelbart.
Prova först på ett säkert sätt
Innan sms-utskicket kopplas till en skarp process (till exempel orderbekräftelse), skicka de första meddelandena till ett eget telefonnummer. Då syns exakt det kunden kommer att se - hur avsändaren SMSinfo ser ut, hur lång leveranstiden är och om segmenten räknas som väntat. Byt först därefter ut to mot kundens riktiga nummer.
Vad gör man när API:et returnerar ett fel?
Ett misslyckat svar har alltid formen {error: {code, message}} och en HTTP-status som beror på typen av fel:
| Status | Kod | Vad det betyder |
|---|---|---|
| 400 | invalid_number | Inte ett giltigt tjeckiskt eller slovakiskt telefonnummer. |
| 400 | invalid_body | Meddelandetexten måste vara 1 till 765 tecken. |
| 400 | unsupported_country | Nummer utanför Tjeckien och Slovakien, dit skickar vi inte sms. |
| 400 | recipient_cannot_receive_sms | Fast telefon - sms:et skulle inte nå fram. Ingenting debiteras. |
| 402 | insufficient_credit | Saldot räcker inte till priset för alla meddelandets segment, eller så har kontot ännu inte fyllt på saldo - sms går iväg först efter den första påfyllningen, välkomstsaldot kan inte användas till dem. |
| 429 | rate_limited | Fler än 1 sms per 2 sekunder, eller fler än 100 sms per konto och dag. |
| 502 | send_failed | Telefonnätet avvisade anropet. Saldot debiteras inte, försök igen. |
| 502 | send_unknown | Vi lämnade över meddelandet till nätet, men bekräftelsen uteblev - det debiteras, skicka det inte igen på måfå. |
Vilka statusar kan ett meddelande ha?
Fältet status i listan (GET /v1/messages) och i detaljen för ett enskilt meddelande antar fem värden: pending (sparat, skickas ännu), sent (operatören har bekräftat avsändningen), failed (operatören avvisade - debiteras inte), unknown (leveransbekräftelsen uteblev, typiskt en timeout hos operatören - debiteras ändå fullt ut, eftersom meddelandet kan ha nått fram) och received (bara för mottagna meddelanden, alltså med direction=in; skickade meddelanden har det inte).
Varje meddelande har också fälten direction (out för skickade, in för mottagna), smsNumber (numret som meddelandet gick ut från eller kom in på; för meddelanden under det delade namnet SMSinfo är det null) och deliveryStatus (delivered eller undelivered, leveranskvitto från operatören; uppstår bara för sms som skickats från ett mobilnummer, för övriga meddelanden är det null).
Hur skickar man många sms på en gång?
Hastighetsgränsen tillåter högst ett sms per två sekunder och konto och högst 100 sms per dag. Vid utskick av flera meddelanden på en gång (till exempel påminnelser om möten) är det enklare att vänta en kort stund mellan anropen än att fånga rate_limited och försöka igen:
const message = "Påminnelse om din tid i morgon - Min app";
for (const to of recipients) {
const response = await fetch("https://volai.cz/v1/messages", {
method: "POST",
headers: {
Authorization: "Bearer vk_DIN_NYCKEL",
"Content-Type": "application/json",
},
body: JSON.stringify({ to, body: message }),
});
if (!response.ok) {
const { error } = await response.json();
console.error("volai " + to + ": " + error.code);
}
// Gränsen är högst 1 sms per 2 sekunder och konto - en kort paus mellan
// anropen är enklare än att hantera rate_limited och försöka igen.
await new Promise((resolve) => setTimeout(resolve, 2100));
}Sms tas emot av två sorters nummer
Röstnummer hos volai tar inte emot sms, så ett svar på ett meddelande som skickats under det delade namnet SMSinfo dyker inte upp någonstans. För att ta emot och skicka sms från ett eget nummer finns tillägget mobilnummer: ett tjeckiskt mobilnummer enbart för sms, utan samtal, 290 kr per 30 dagar exklusive moms. Alternativet är nummer för samtal och sms: en fast linje i Prag där både samtal och sms tas emot, 49 kr per 30 dagar exklusive moms (avgiften dras först efter aktiveringen, som vanligtvis tar upp till 1 arbetsdag). För båda ingår mottagna sms i priset. Mottagna meddelanden läses via GET /v1/messages?direction=in, via MCP-verktyget list_messages eller via webhooken message.received och vi sparar dem i 90 dagar; att skicka från ett mobilnummer kostar 1,90 kr per segment, från nummer för samtal och sms 2,50 kr per segment, och går bara till tjeckiska nummer. Från ett nummer skickas sms med fältet fromNumber i POST /v1/messages (numret hämtas från GET /v1/sms-numbers eller från GET /v1/voice-sms-numbers). Det dagliga taket för utskick från ett nummer är 20 sms per konto de första 30 dagarna efter att numret köpts, därefter 50. På ett konto kan det finnas högst två mobilnummer, och de kan köpas först efter den första påfyllningen av saldot; detsamma gäller nummer för samtal och sms: högst två per konto, och de kan beställas först efter den första påfyllningen. Verifieringskoder från tjänster (banker, Google och liknande) garanterar vi inte, numren är avsedda för skrivande med människor och mottagning har vi verifierat i O2:s nät. Detaljer finns i avsnitten Mobilnummer och nummer för samtal och sms i API-dokumentationen. När Twilio är det bättre valet för att ta emot sms beskrivs i jämförelsen mellan Twilio och volai.
Sammanfattning: ett anrop till POST /v1/messages med fälten to och body skickar ett sms, rubriken Idempotency-Key skyddar flödet mot dubbla utskick när anropet upprepas, och priset räknas per segment beroende på om texten innehåller tecken utanför GSM-7. Håll nyckeln utanför repot och skicka det första meddelandet till dig själv.
Vad händer härnäst
Den fullständiga referensen till REST-API:et (nummer, samtal, webhooks, agenter) finns på /docs/api. Vill du veta direkt när volai lämnat över meddelandet till operatören, utan att polla GET /v1/messages? Prenumerera på händelsen message.sent - den bekräftar bara att operatören tagit emot meddelandet, inte leverans till telefonen (för meddelanden under det delade namnet ser volai det inte, se ovan; meddelanden som skickats från ett eget mobilnummer har leveranskvitto) - se dokumentationen om webhooks. Och om förutom sms också ett telefonnummer som självt svarar på samtal behövs, ta en titt på AI-receptionisten.
Testa volai - de första 50 kr bjuder vi på
Ett konto skapas på en minut och ett startsaldo för samtal och ett nummer finns direkt - sms går att skicka efter den första påfyllningen.
Vad händer härnäst
Relaterade artiklar
Fem frågor innan du skaffar en AI-receptionist
Pris, start på 5 minuter, vidarekoppling av nummer från O2/T-Mobile/Vodafone, slovakiska nummer och moms - fem svar direkt ur volais prislista och inställningar.
Ringa en kund från ett n8n-workflow
Ring en kund direkt från n8n: en HTTP Request-nod mot volais REST-API, data från workflowet i agentens prompt och samtalets resultat tillbaka via webhook.
Så ger du Claude Code ett telefonnummer via MCP
Installera volai i Claude Code med ett enda kommando, ge det ett telefonnummer och låt det ringa och skicka sms bara med en prompt - utan kod och utan API-dokumentation.