Skip to main content
For developers

SMS API in Spain: a multichannel messaging REST API for SMS, WhatsApp and Telegram

Integrate SMS, WhatsApp Business API and Telegram sending with a single JSON REST API: X-Api-Key authentication, native idempotency, status webhooks signed with HMAC-SHA256, configurable rate limit, clear errors and a sandbox mode for integrating without spending a euro.

  • Native idempotency
  • HMAC-SHA256 signed webhooks
  • Sandbox at no cost
  • Balance that never expires

Send your first SMS with the REST API in five minutes

No mandatory SDK, no IP whitelist, no talking to sales to enable channels: one HTTPS request with JSON and your message is queued.

1. Create your account

Sign up for free. The account starts as pending and a person reviews it before enabling real sending; sandbox mode lets you integrate and test the API without spending balance and without any message going out.

2. Copy your credentials

In the dashboard you will find your api_key (format sk_live_…) and your api_secret. They are sent in the X-Api-Key and X-Api-Secret headers of each request, always over HTTPS. The secret is shown only once, when it is generated. If you are coming from another platform, they are the same two fields you already have configured: only the values change.

3. Make the POST

Call POST /api/v1/messages with the channel, the recipient in E.164 format and the text. The sender goes in from and is optional: if you do not set it, the platform's default sender is used. The response returns the message created, its cost in euros and its status.

terminal — send an SMS
curl -X POST https://app.smsverifica.com/api/v1/messages \
  -H "X-Api-Key: sk_live_tu_api_key" \
  -H "X-Api-Secret: tu_api_secret" \
  -H "Idempotency-Key: pedido-1234-confirmacion" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "sms",
    "to": "+34612345678",
    "from": "MITIENDA",
    "body": "Your order 1234 has been shipped. You will receive it tomorrow before 14:00."
  }'
response — 201 Created
{
  "data": {
    "id": 98231,
    "channel": "sms",
    "direction": "out",
    "to": "+34612345678",
    "from": "MITIENDA",
    "status": "queued",
    "cost_eur": "0.0390",
    "queued_at": "2026-07-08T10:15:02+02:00",
    "created_at": "2026-07-08T10:15:02+02:00"
  }
}

The recipient is normalised to E.164 and the country prefix is detected automatically to apply the correct rate (see the SMS rates by country). The cost is deducted from your balance transactionally when queued and, if the message fails permanently, it is refunded automatically.

A single multichannel messaging API: SMS, WhatsApp Business API and Telegram

The same endpoint, the same JSON and the same webhooks for all three channels: switching from SMS to WhatsApp or Telegram means changing the value of one field. That is a WhatsApp Business API and a Telegram API that do not force you to learn three different integrations.

Sending a WhatsApp Business API template

Send templates approved by Meta with variables and state the conversation category for exact per-message pricing (WhatsApp prices by category). Free text within the 24-hour service window is also supported.

terminal — send WhatsApp with a template
curl -X POST https://app.smsverifica.com/api/v1/messages \
  -H "X-Api-Key: sk_live_tu_api_key" \
  -H "X-Api-Secret: tu_api_secret" \
  -H "Idempotency-Key: entrega-5566-aviso" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "whatsapp",
    "to": "+34612345678",
    "template_name": "aviso_entrega",
    "template_vars": { "1": "Maria", "2": "Thursday from 9:00 to 14:00" },
    "category": "utility"
  }'

Sending a Telegram message (€0.010 per message)

Connect your own bot and send Telegram notifications at €0.010 per message. Our Telegram webhook automatically captures the chat_id when the customer starts a conversation with your bot; from then on, you send using their phone number as the reference.

terminal — send Telegram
curl -X POST https://app.smsverifica.com/api/v1/messages \
  -H "X-Api-Key: sk_live_tu_api_key" \
  -H "X-Api-Secret: tu_api_secret" \
  -H "Idempotency-Key: visita-889-recepcion" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "telegram",
    "to": "+34612345678",
    "body": "Your visitor has just arrived at reception. Automatic notice from QRACCESO."
  }'

Checking your balance

terminal — account balance
curl https://app.smsverifica.com/api/v1/account/balance \
  -H "X-Api-Key: sk_live_tu_api_key" \
  -H "X-Api-Secret: tu_api_secret"

# {"data":{"balance_eur":"842.3100"}}

Creating a complete campaign with a single request

This is rarely seen on the Spanish market: a real campaigns API. With POST /api/v1/campaigns you launch a bulk send to a whole contact list, with date scheduling and a prior balance check; the platform calculates the cost, queues the messages and updates the counters of sent, delivered, failed and read in real time.

terminal — create a scheduled campaign
curl -X POST https://app.smsverifica.com/api/v1/campaigns \
  -H "X-Api-Key: sk_live_tu_api_key" \
  -H "X-Api-Secret: tu_api_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "sms",
    "name": "October MOT reminder",
    "contact_list_id": 42,
    "body": "Your MOT expires this month. Book an appointment at your usual garage.",
    "scheduled_at": "2026-10-01T09:00:00+02:00"
  }'

# {"data":{"id":57,"status":"scheduled","total":1840,"cost_estimate":"71.7600", ...}}

If you prefer to start with the dashboard before integrating, the user manual goes through every screen with screenshots.

Certified messaging through the API: two endpoints and into production

Certified messaging —a file of chained evidence and a verifiable PDF— is included in the same REST API, with no separate modules or additional contracts: not every provider offers it through the API, and anyone who integrated someone else's and was left without it can migrate here with two endpoints. The certification surcharge is €0.25 per message, the same on all three channels, on top of the channel price.

terminal — send a certified notification
curl -X POST https://app.smsverifica.com/api/v1/certified \
  -H "X-Api-Key: sk_live_tu_api_key" \
  -H "X-Api-Secret: tu_api_secret" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: notif-2026-0001" \
  -d '{
    "channel": "sms",
    "to": "+34612345678",
    "subject": "Payment demand",
    "content": "Full text that will be certified in the evidence file."
  }'

# {"data":{"id":31,"status":"queued","content_hash":"5f1c…","portal_url":"…/c/…", ...}}
# The evidence PDF, whenever you need it: GET /api/v1/certified/31/certificate

Available today only to Spain (+34) and as a non-qualified electronic registered delivery service (art. 3.36 of the eIDAS Regulation), with a qualified time stamp from Camerfirma on every file — the limits and what each thing proves, on the certified messaging page.

All the API v1 endpoints

REST API v1 endpoints (prefix /api/v1)
Method and pathWhat it does
POST /messagesSends an SMS, WhatsApp or Telegram message. Accepts Idempotency-Key.
GET /messages/{id}Retrieves a message: status, cost, timestamps for its whole life cycle.
GET /messagesLists your messages with pagination and filters.
POST /campaignsCreates and confirms a bulk campaign over a contact list, with optional scheduling.
GET /campaigns/{id}Campaign statistics: sent, delivered, failed, read and cost.
POST /verify/startSends an OTP verification code by SMS, WhatsApp or Telegram.
POST /verify/checkChecks the OTP code (a wrong code is 200 with status: invalid).
POST /certifiedSends a certified communication: evidence file + recipient portal.
GET /certified/{id}Status of the certified file: opens, reading, signature.
GET /certified/{id}/certificateDownloads the evidence PDF (issued on request).
GET /account/balanceBalance in euros, in real time.
GET /pricing/smsSMS rates by country prefix, always up to date.
GET /sendersYour senders and their status in the CNMC Alias Registry: whether they would go out with your brand, with the backup sender or be rejected when sending to Spain.
GET /senders/checkThe same for a specific send (from and to), before sending it.

Native idempotency: retry without fear of duplicate sends

A network timeout at the worst moment and your customer receives the same SMS twice... and you pay for it twice. With SMSverifica that cannot happen.

Add the Idempotency-Key header to your POST /messages with a unique identifier for your operation (for example, pedido-1234-confirmacion). If you repeat the request — because your job retried it, because there was a timeout, because your process restarted — the API does not create a second message or charge twice: it returns the original response with the header X-Idempotency-Replayed: true.

This is native sending idempotency, built into the API itself, and it is a real differentiator: none of the Spanish SMS providers documents it in its API, and neither do the big international messaging platforms on their sending endpoint. If you build serious systems — queues, retries with backoff, workers — you know exactly why it matters.

The check, documentation in hand and with the date consulted, is in the comparisons with Twilio, LabsMobile, Esendex, Instasent and BulkGate (in Spanish).

second identical request — response replayed
# We repeat the same POST with the same Idempotency-Key
curl -i -X POST https://app.smsverifica.com/api/v1/messages \
  -H "Idempotency-Key: pedido-1234-confirmacion" \
  ...

HTTP/2 201
X-Idempotency-Replayed: true

# Same JSON, same message id: zero duplicates, zero double charges

Status webhooks signed with HMAC-SHA256, with retries and manual resend

Receive on your server every status transition — message.sent, message.delivered, message.failed, message.read, message.received and campaign.completed — with a cryptographic signature that lets you verify the notice is authentic. Of the Spanish providers whose documentation we reviewed in July 2026, none signed their delivery notifications; we sign all of them.

POST to your endpoint — signed payload
X-Signature: sha256=7f83b1657ff1fc53b92dc18148a1d6...
Content-Type: application/json

{
  "event": "message.delivered",
  "delivery_id": 4521,
  "timestamp": "2026-07-08T10:15:09+02:00",
  "data": {
    "id": 98231,
    "channel": "sms",
    "to": "+34612345678",
    "status": "delivered",
    "delivered_at": "2026-07-08T10:15:08+02:00"
  }
}
verifying the signature in PHP
// You define the secret per webhook in your dashboard
$cuerpo = file_get_contents('php://input');
$esperada = 'sha256=' . hash_hmac('sha256', $cuerpo, $secreto);

if (hash_equals($esperada, $_SERVER['HTTP_X_SIGNATURE'] ?? '')) {
    // Authentic payload: process the event
}

HMAC-SHA256 signature

Every delivery carries the header X-Signature: sha256=<hmac> calculated over the exact body with your secret. Verifying it takes three lines of code in any language.

Automatic retries

If your endpoint does not respond 2xx, we retry up to 5 times with increasing waits (1 min, 5 min, 15 min, 1 h, 4 h). At-least-once semantics: use delivery_id to deduplicate.

Log and manual resend

Every attempt is recorded in your dashboard with the response code and date. Was your server down? Resend the delivery manually with one click, without opening tickets.

Sandbox mode: integrate the API without spending a single euro

A documented simulation environment, at no cost: integrate and test without spending balance and without any real message going out.

With sandbox mode enabled, your API requests behave exactly as in production — the same endpoints, the same responses, the same signed webhooks — but no message goes out to the network and the cost is 0.0000 of balance. The simulator goes through the message's whole life cycle: queued → sent → delivered (or failed/read), firing your webhooks at each transition so you can test your integration end to end.

You also have test numbers (magic numbers) that force each final status — delivered, failed, read — so you can check how your application reacts to each scenario, including the automatic refund of a failed send. All documented in your dashboard, with no card and no expiry of the test account.

How it works, without embellishment: signing up creates the account in pending status and in sandbox mode; in sandbox no message goes out and no balance is spent. A person reviews the sign-up before enabling real sending. Any questions, write to us.

What you can test in sandbox

  • SMS, WhatsApp and Telegram sends with a real JSON response
  • Signed status webhooks at every transition
  • Statuses forced with test numbers: delivered, failed, read
  • Idempotency with Idempotency-Key and replayed responses
  • Complete campaigns with a cost estimate
  • Error handling: 402, 422, 429 and per-field validation

Clear JSON errors and a configurable rate limit per account

All errors share the same format — {"error":{"code":"<slug>","message":"..."}} — with a stable code you can program against and a human-readable message. Validation errors include the details per field.

API v1 error codes
HTTPCodeWhen it happens
401unauthorizedInvalid API key or secret.
402insufficient_balanceInsufficient balance: the message or campaign is not queued. There are never half-done sends.
403account_not_activeAccount pending approval or suspended.
404not_foundThe resource does not exist or belongs to another account (multi-tenant isolation).
422validation_failedInvalid data; includes details with the errors per field.
422wa_outside_windowWhatsApp free text outside the 24 h service window: use a template.
422telegram_no_chat_idThe contact has not yet started a conversation with your Telegram bot.
422no_providerThere is no provider configured for that channel on your account.
422no_pricingDestination prefix without a rate: we never send blindly, or for free by mistake.
429rate_limitedYour requests-per-minute limit has been exceeded.

Rate limit per account, not per platform

Each account has its own limit — 60 requests per minute by default, which can be raised according to your real volume —, so other customers' traffic never affects yours. For bulk sending you do not need to hammer the API: POST /campaigns dispatches thousands of messages with a single request and with controlled throttling towards the operators.

402: no balance, no surprises

If your balance does not cover the send you receive an immediate 402 insufficient_balance and nothing is queued. The balance deduction is transactional, with an automatic refund if the message fails permanently, and you can enable auto top-up with a threshold so that the balance never holds you back. See the balance model with no expiry.

A multi-tenant platform with accounts approved manually

The delivery quality of your SMS depends on the reputation of the routes. That is why we do not let just anyone in.

Every sign-up at SMSverifica is reviewed by a person before the account is activated. That anti-spam filter keeps our routes and senders clean, and aims to make sure your legitimate traffic —your OTPs, your delivery notices, your campaigns— does not share a route with junk. Sandbox mode does not wait for that review: it opens on its own when you verify your email, and the human review then unlocks real sending and payments.

Isolation between accounts is total: your messages, contacts, campaigns and credentials live under your account_id and are invisible to any other account. Channel credentials are stored encrypted in the database and you can rotate your api_secret from the dashboard at any time.

  • Manual anti-spam approval: better reputation for routes and senders
  • Multi-tenant isolation verified with automatic tests
  • Encrypted credentials and self-service secret rotation
  • GDPR and LSSI: servers in the EU and Spanish invoicing with VAT
  • Configurable routing per channel: each account defines its primary provider and, if it has a second one contracted, a backup one within the same channel
  • A balance that never expires: your integration balance never expires

Frequently asked questions about the SMS and messaging API

Can I use the SMS API from PHP, Python, Node.js or any other language?

Yes. It is a standard REST API with JSON over HTTPS: any language that can make an HTTP request can send SMS, WhatsApp and Telegram messages. The curl examples on this page carry over as they are to PHP (cURL/Guzzle), Python (requests), Node.js (fetch/axios), Java, C# or Go.

Do I need a card to test the API?

No, and neither does sandbox mode: it simulates the message's whole life cycle (queued, sent, delivered, failed, read) at zero cost and without any real message going out. Real sending is enabled when a person reviews and approves your account.

How do I receive the delivery statuses of messages?

In two ways: by querying GET /api/v1/messages/{id} or, better, by receiving status webhooks on your server (message.sent, message.delivered, message.failed, message.read, message.received and campaign.completed). Each webhook is signed with HMAC-SHA256 in the X-Signature header and retried automatically with increasing waits if your endpoint does not respond.

What happens if my account runs out of balance?

The API responds 402 with the code insufficient_balance and the message is not queued: there are never half-done sends or billing surprises. You can enable auto top-up with a threshold so the balance replenishes itself.

What request limit does the API have?

Each account has its own rate limit, 60 requests per minute by default, which can be raised on request according to your volume. If you exceed it you receive a standard 429 (rate_limited). For bulk sending use POST /campaigns: a single request for thousands of recipients.

What happens if I send the same POST /messages request twice?

If you include the Idempotency-Key header, the second request does not generate a duplicate send or charge: the API returns the original response with the header X-Idempotency-Replayed: true. It is native API idempotency, ideal for safe retries after a timeout.

Create your account and send your first SMS through the API

A free account with no card, sandbox mode with no card, sign-up reviewed by hand, a balance that never expires and support in Spanish from people who have read the same documentation as you. Building user verification? See also the OTP verification API by SMS.