SMS API for developers
Plain HTTP and JSON over HTTPS, no SDK required. One request sends an SMS, delivery reports arrive by signed webhook, and retries are safe with an Idempotency-Key. Test keys send nothing and cost nothing, so you can build the whole integration before topping up.
A typical system message sent from your backend under your app name.
- 1 requestPOST /api/sms/send, JSON in and out
- 500recipients per bulk request, counted as one request
- €0for test keys: nothing is sent or charged
REST, JSON and API keys
The production base URL is https://www.topsms.cz. You authenticate with an API key in the Authorization: Bearer clientId:secret header; the secret is stored only as a hash, so save it when you create the key.
- Scopes:
sendfor sending,readfor status and credit. Optionally an IP whitelist per key. - Up to 10 active keys per account, each with its own name, so you can separate projects or cost centres.
- Rate limit per key: 60 requests per minute by default, adjustable up to 1,000.
- Bulk:
/api/sms/send-bulktakes up to 500 recipients, the same text or a different one for each. Above 50 recipients the API answers202with ajobIdand the queue sends within seconds to minutes.
Delivery reports by webhook
Set a webhook URL on the API key and every status change (delivered, undelivered, expired) is pushed to your server as a JSON POST with the header X-TopSMS-Signature: sha256=…, an HMAC-SHA256 of the raw body with your webhook secret. We try three times (immediately, after 30 seconds, after 2 minutes) with a 5-second timeout and expect HTTP 2xx.
Prefer polling? Query GET /api/sms/status/{id}. In the dashboard, each key has a log of the last 100 calls and webhook attempts, including your server’s response, kept for 30 days.
Safe retries and test mode
After a timeout you do not know whether the request went through. Send it again with the same Idempotency-Key and the SMS is not sent twice: you get the original response with Idempotent-Replayed: true. The key is valid for 24 hours; a different body with the same key returns 422, a request still running 409. It works on /api/sms/send, /api/sms/send-bulk and /api/verify/send.
A test key returns the same responses as a live key, plus "test": true, and after 2 to 4 seconds simulates the status change and the webhook. Numbers ending in 0000 simulate a failure, 0001 an expiry.
OpenAPI, PHP library and MCP
- OpenAPI 3.0: openapi.yaml for Postman, Insomnia or a generated client.
- PHP:
composer require topsms/topsms-phpfor sending, status, credit and webhook signature verification. - MCP server: the npm package
topsms-mcplets Claude, Cursor and other AI assistants send SMS, schedule and cancel them, send verification codes and check status and credit through the same API. See MCP server. - For coding assistants: llms.txt and the authentication guide for automated clients.
Building login codes? Use the Verify API rather than sending codes yourself. Prices are the same as in the dashboard: €0.084 per SMS to Germany, Austria and the rest of the EU, no API fees.
Sending an SMS from Node.js
The Node.js sample from the documentation, with an Idempotency-Key added; the same request in curl, PHP, Python, C# and Java is there too.
const res = await fetch("https://www.topsms.cz/api/sms/send", {
method: "POST",
headers: {
"Authorization": "Bearer CLIENT_ID:SECRET",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({ to: "+4915112345678", text: "MyApp: your data export is ready.", from: "MyApp" }),
})
console.log(await res.json())The response contains id (use it to query the status), smsCount (charged parts) and price. Amounts in the API are in CZK, the currency in which credit is held. In production, generate the key once per logical message and reuse it for retries.
Frequently asked questions
Do I need an SDK?
No. The API is plain HTTP and JSON over HTTPS, so any HTTP client works: curl, fetch, Guzzle, requests. For PHP there is an optional library, topsms/topsms-php, and the OpenAPI specification lets you generate a client.
How do I test without sending real SMS?
Create a test key in the dashboard. It sends and charges nothing, returns the same responses as a live key with "test": true, and simulates status changes and webhooks after 2 to 4 seconds.
How are webhooks secured?
Each webhook carries the header X-TopSMS-Signature with an HMAC-SHA256 of the raw request body, signed with the webhook secret shown when you create the key. Verify it over the raw body, not over parsed JSON.
What are the rate limits?
Per API key, 60 requests per minute by default, adjustable in the dashboard up to 1,000. A bulk request counts as one request even when it carries up to 500 messages.
Can AI agents use the API?
Yes. The official MCP server topsms-mcp exposes sending, scheduling, status, verification codes and credit as tools for Claude, Cursor and other assistants. It calls the same REST API, with the same prices and limits.
Read more
- How to integrate an SMS API: step-by-step guide in 5 minutes
- OTP via SMS: a secure implementation
- How to choose an SMS gateway for your business
- MCP server for AI assistants
Try it with 10 free SMS
Free account, active as soon as you confirm your mobile number. No credit card, no monthly fee, prepaid credit that never expires.
More use cases
- OTP and verification codesLogin codes, 2FA and phone verification with the Verify API: we generate, send and check the code.
- Order and shipping notificationsOrder received, shipped, ready for pickup: SMS from WooCommerce, other shops and your own system.
- Appointment remindersFewer no-shows at practices, workshops and salons with reminders scheduled via send_at.
- Payment reminders from lexoffice and sevDeskAutomatic SMS for overdue invoices: connect with an API key, choose the days, check the preview.