How to send your first SMS via API in 5 minutes — the complete guide
Most "SMS gateways" take days to set up: an application form, a contract, a sales call, a proprietary SDK to install. We go the other way — your first SMS through the API goes out in 5 minutes: create an account, generate a token, make one HTTP request. In this guide we walk the whole path: from the account, through working code in four languages, to webhooks, idempotency and error handling — the things that decide whether an integration survives contact with production.
Step 1: account and Bearer Token
Create an account on the sign-up page — you get 100 free SMS, no credit card and no contract. Activation is instant, so you are not waiting on sales approval. In the panel go to Settings → API → Generate and create a Bearer Token. Treat it like a password — keep it in environment variables (e.g. ACTIO_TOKEN), never in a repository or front-end code. If it leaks, revoke it in the panel and generate a new one; the old one stops working immediately.
Step 2: the first request (curl)
The fastest test is a single call from the terminal. The endpoint accepts JSON and returns a message ID and status:
curl -X POST https://msg-api.actio.pl/api/sms \
-H "Authorization: Bearer $ACTIO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"from": "YourBrand",
"to": "48732129000",
"body": "Your login code: 482910"
}'Three fields do the work: from (sender name or E.164 number), to (recipient in E.164 without the "+"), and body (UTF-8 text). Full reference, including optional fields like scheduled_at and idempotency_key, is in the documentation.
Step 3: integrate in your stack
The API is plain REST, so it works with any language that speaks HTTP — no closed libraries to install. In Node.js the built-in fetch is enough; in Python use requests.post(...), in PHP cURL, in Go the standard net/http. Ready snippets in five languages are in the documentation — copy, swap the token, done.
Step 4: webhooks instead of polling
Sending an SMS is only half the story — you want to know it arrived. Instead of polling the API in a loop (slow and costly), configure a webhook: you point to your URL and we push an event on every status change — sms.delivered, sms.failed, sms.expired, sms.bounced. The payload includes message_id, a timestamp and the destination carrier, so your system reacts in real time — for example retrying on another number when an SMS bounces.
Idempotency and error handling
In production, resilience to repeats matters. If your server sends the same request twice (timeout, queue retry), without protection the recipient gets two messages. The fix is the idempotency_key field (UUID v4): the same key guarantees the message goes out only once. Also handle the common status codes up front: 401 (bad token), 402 (insufficient credits), 422 (invalid number or body), 429 (rate limit — check the Retry-After header).
One API, three common use cases
The same API covers three very different scenarios without changing the integration: transactional notifications, 2FA / OTP codes and bulk campaigns to thousands of recipients. Billing is pay-as-you-go, with no subscription or entry threshold — check the rate for your volume in the pricing.
FAQ
Do I need a contract to test the API?+
No. You sign up with email, get 100 free SMS and test right away — no contract, no credit card.
Which languages have code samples?+
curl, Node.js, Python, PHP and Go — all in the documentation, ready to copy and swap the token.
How do I know an SMS was delivered?+
A webhook pushes an event on every status change (delivered, failed, expired, bounced) to your URL, in real time and at no extra cost.
How do I avoid double sends on retry?+
Use the idempotency_key field (UUID v4). The same key guarantees the message goes out only once, even if the request fires several times.