One-time codes and 2FA by SMS
Confirm a phone number at sign-up, protect logins with a second factor or approve a payment. With the Verify API you make two calls: one sends the code, the other checks it. Generating the code, its validity and the limits against abuse are handled by the gateway.
A typical login code: your name as the sender, the code, its validity and a warning.
- 2 callsPOST /api/verify/send and /api/verify/check
- 5 attemptsper code, at most 5 codes per number per hour
- €0.084per SMS to Germany, Austria and the rest of the EU
Where SMS codes make sense
An SMS code works on every phone without installing an app, which is why it remains the default for:
- Sign-up and phone verification: check that the number belongs to the person registering before you activate an account.
- Two-factor login (2FA): a second step after the password, or the fallback when a user has lost access to an authenticator app.
- Confirming sensitive actions: changing a password or payout details, approving an order or a payment.
For a comparison of SMS codes with TOTP apps and passkeys, including SIM swap risks, see our OTP via SMS implementation guide.
How the Verify API works
- Your application calls
POST /api/verify/sendwith the phone number and your brand name. The gateway generates the code and sends it by SMS. - The user types the code into your form.
- You call
POST /api/verify/checkwith theidfrom step 1 and the code. The answer isvalid: truewith statusapproved, or not.
You neither generate nor store the code: the gateway keeps only an HMAC fingerprint of it. A new code to the same number invalidates the previous one.
Limits against abuse are built in
OTP endpoints attract brute-force attempts and bots that request codes in bulk to run up your SMS bill. The Verify API enforces these limits on its side:
- a code is valid for 60 to 1,800 seconds (default 5 minutes)
- 5 attempts per code
- at most 5 codes per number per hour and 30 seconds between two codes
Keep your own limits per IP address and per account on top; the guide linked above shows how. A retry after a network error is safe with an Idempotency-Key header, which also applies to /api/verify/send.
Test without sending anything
Create a test key in the dashboard: it sends and charges nothing, and the code is always 123456. Your sign-up flow can be tested end to end, including the error paths, before you switch to a live key. A live account starts with 10 free SMS.
The sender is your approved sender name; until it is approved, codes go out as “TopSMS”. A message under a name is one-way: the recipient cannot reply, which is exactly what you want for codes.
The two calls
Authentication as for every endpoint: Authorization: Bearer CLIENT_ID:SECRET. Request and response, as in the documentation:
POST /api/verify/send
{ "to": "+4915112345678", "brand": "MyShop" }
→ { "ok": true, "id": "cmv...", "status": "pending", "expiresAt": "...", "price": 2.04 }
POST /api/verify/check
{ "id": "cmv...", "code": "482913" }
→ { "valid": true, "status": "approved" }The API reports amounts in CZK, the currency in which credit is held: 2.04 CZK corresponds to €0.084. More details and examples are on the Verify API page (Czech).
Frequently asked questions
What does a verification code cost?
A code is charged like a normal SMS to the destination country: €0.084 to Germany, Austria and the rest of the EU. There is no monthly fee and no separate charge for the check call.
Do I have to generate and store the codes myself?
No. The Verify API generates the code, sends it and checks it. The gateway keeps only an HMAC fingerprint of the code, not the code itself, so there is nothing for you to store.
How long is a code valid and how many attempts are allowed?
Between 60 and 1,800 seconds, 5 minutes by default. Each code allows 5 attempts, and at most 5 codes per number can be sent per hour with at least 30 seconds between two codes.
Can I test the integration without sending real SMS?
Yes. A test key sends and charges nothing and the code is always 123456. Once your flow works, create a live key; a new account comes with 10 free SMS.
Can the code arrive under my company name?
Yes, with your approved sender name of up to 11 characters. Until it is approved, messages are sent as TopSMS. Recipients cannot reply to a message sent under a name.
Read more
- OTP via SMS: a secure implementation, and when to choose TOTP or a passkey instead
- Alphanumeric sender ID in Germany and Austria
- API documentation: Verify API
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
- 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.
- SMS API for developersREST and JSON, webhooks, Idempotency-Key, test keys, OpenAPI and an MCP server.