Sari la conținut
Ghiduri tehnice

Integrare API SMS: ghid tehnic pentru dezvoltatori

Ghid tehnic de integrare API SMS: autentificare cu token, endpoint de trimitere, tratarea erorilor și securitate, cu exemple de cod complete.

Echipa BlueText 8 min citire

Când o echipă tehnică decide să trimită SMS-uri direct din aplicația proprie, nu mai are nevoie de interfața web de campanii — are nevoie de un API stabil, documentat și previzibil. Diferența dintre „trimit SMS-uri din platformă" și „trimit SMS-uri din codul meu" e diferența dintre o unealtă de marketing punctuală și o componentă de infrastructură pe care se bazează alte procese: confirmări de comandă, coduri de verificare, alerte operaționale. Acest ghid trece prin ce înseamnă practic o integrare API SMS — autentificare, structura unei cereri, tratarea erorilor, securitate și ce trebuie verificat înainte să pui codul în producție.

Când ai nevoie de API și când e suficientă interfața web

Nu orice trimitere de SMS justifică o integrare tehnică. Dacă lucrezi cu campanii ocazionale, liste de contacte relativ statice și nu ai nevoie ca trimiterea să pornească automat dintr-un alt sistem, interfața web e mai rapidă de folosit — încarci un CSV, personalizezi cu variabile și programezi campania. Am detaliat acest flux separat, în ghidul despre trimiterea de SMS în masă.

API-ul devine necesar când trimiterea trebuie declanșată de un eveniment din propriul tău sistem — magazin online, CRM, soft de programări sau orice altă platformă cu care vrei să integrezi trimiterea de SMS:

  • confirmare de comandă imediat după plasarea acesteia într-un magazin online;
  • cod de verificare la autentificare sau resetare parolă;
  • notificare de schimbare de status (livrare, programare, rezervare);
  • alertă operațională generată automat de un sistem intern (monitorizare, stocuri, plăți eșuate).

Regula practică: dacă trimiterea depinde de o acțiune a utilizatorului sau de o stare din baza ta de date, ai nevoie de API. Dacă depinde de o decizie de marketing luată manual, interfața web e suficientă și mai simplă de operat.

Cum arată o integrare tipică

O integrare API SMS are, în esență, trei piese: autentificare, o cerere de trimitere și interpretarea răspunsului.

Autentificare cu token Bearer

Autentificarea se face printr-un token trimis în header-ul Authorization, sub forma Bearer TOKEN. Tokenul se generează din contul de client și trebuie tratat ca o credențială — nu ca un parametru oarecare.

Endpoint-ul de trimitere și parametrii cererii

Un endpoint ilustrativ pentru trimitere arată așa: POST https://sms.bluetext.ro/api/v3/sms/send, cu corpul cererii în format JSON. Parametrii de bază, la nivel conceptual:

  • recipient — numărul destinatarului, în format internațional;
  • message — conținutul mesajului;
  • type — tipul de mesaj (de exemplu "plain" pentru text simplu);
  • schedule_time — opțional, pentru trimitere programată la o dată și oră ulterioară.

Ce conține răspunsul

Răspunsul la cererea de trimitere conține statusul cererii și lista destinatarilor acceptați, respectiv respinși de platformă la nivel de validare inițială (număr format greșit, câmp lipsă etc.). Structura exactă a câmpurilor de răspuns și codurile folosite sunt documentate în contul de client — nu le reproducem generic aici ca să nu inducem în eroare o structură care poate diferi față de ce vezi efectiv în documentație.

Exemple de cod

Mai jos sunt exemple generice, pentru patru limbaje uzuale. Toate trimit către același endpoint ilustrativ și folosesc autentificare Bearer.

cURL

curl -X POST https://sms.bluetext.ro/api/v3/sms/send \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "recipient": "+40712345678",
        "message": "Comanda ta a fost expediata.",
        "type": "plain"
      }'

PHP (cu Guzzle)

<?php

require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

$client = new Client([
    'base_uri' => 'https://sms.bluetext.ro',
    'timeout'  => 10,
]);

try {
    $response = $client->post('/api/v3/sms/send', [
        'headers' => [
            'Authorization' => 'Bearer ' . getenv('BLUETEXT_API_TOKEN'),
            'Content-Type'  => 'application/json',
        ],
        'json' => [
            'recipient' => '+40712345678',
            'message'   => 'Comanda ta a fost expediata.',
            'type'      => 'plain',
        ],
    ]);

    $data = json_decode($response->getBody(), true);
} catch (RequestException $e) {
    error_log('Eroare trimitere SMS: ' . $e->getMessage());
    // aici intervine logica de retry cu backoff
}

Python (cu requests)

import os
import requests

API_TOKEN = os.environ["BLUETEXT_API_TOKEN"]

response = requests.post(
    "https://sms.bluetext.ro/api/v3/sms/send",
    headers={
        "Authorization": f"Bearer {API_TOKEN}",
        "Content-Type": "application/json",
    },
    json={
        "recipient": "+40712345678",
        "message": "Comanda ta a fost expediata.",
        "type": "plain",
    },
    timeout=10,
)

response.raise_for_status()
data = response.json()

JavaScript (fetch)

const response = await fetch("https://sms.bluetext.ro/api/v3/sms/send", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.BLUETEXT_API_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    recipient: "+40712345678",
    message: "Comanda ta a fost expediata.",
    type: "plain",
  }),
});

if (!response.ok) {
  throw new Error(`Eroare la trimitere: ${response.status}`);
}

const data = await response.json();

Documentația completă, cu toți parametrii disponibili și structura exactă a răspunsului, este disponibilă în contul de client.

Gestionarea erorilor: retry, backoff și idempotency

O integrare care funcționează „de obicei" nu e suficient de bună pentru un flux critic precum confirmarea unei comenzi. Câteva principii de bază:

  1. Retry cu backoff exponențial — dacă cererea eșuează din cauza unei probleme temporare de rețea sau a unui răspuns de eroare de partea serverului, reîncearcă după un interval care crește progresiv (de exemplu 1s, 2s, 4s, 8s), nu imediat și nu la infinit.
  2. Limitează numărul de reîncercări — după un număr fix de tentative eșuate, oprește-te și loghează eroarea pentru investigare manuală, în loc să intri într-o buclă.
  3. Idempotency — dacă retrimiți aceeași cerere după un timeout, ai riscul să trimiți mesajul de două ori dacă prima cerere a ajuns la destinație dar răspunsul nu a mai ajuns înapoi la tine. Generează un identificator unic per cerere de business (de exemplu ID-ul comenzii) și păstrează-l în sistemul tău, ca să poți verifica dacă o trimitere pentru acel eveniment a avut deja loc înainte de a retrimite.
  4. Nu trata orice eroare la fel — o eroare de autentificare (token invalid) nu se rezolvă prin retry, ci prin verificarea configurației. O eroare de validare (număr greșit formatat) nu se rezolvă prin retry, ci prin corectarea datelor de intrare.

Securitate: token, whitelist de IP-uri, rotația tokenului

Câteva reguli care ar trebui să fie non-negociabile într-o integrare de producție (detaliem cum tratăm securitatea și GDPR-ul la nivel de platformă):

  • Tokenul nu se ține niciodată în cod — se pune într-o variabilă de mediu sau într-un manager de secrete, niciodată hardcodat într-un fișier care ajunge în controlul de versiuni.
  • Whitelist de IP-uri — dacă serverele de la care trimiți cereri au adrese IP fixe, restricționează accesul la API doar de la acele IP-uri, ca strat suplimentar de protecție.
  • Rotația periodică a tokenului — un token care circulă mult timp fără să fie schimbat crește riscul de expunere. Rotește-l periodic și asigură-te că procesul de deploy poate prelua noul token fără downtime.
  • Un token per mediu — token separat pentru development, staging și producție, ca o scurgere dintr-un mediu de test să nu compromită producția.

Rate limiting și volume mari

Orice API de trimitere are limite de rată — un număr maxim de cereri acceptate într-un interval de timp. Pentru volume mari, asta înseamnă câteva lucruri practice:

  • nu trimite toate mesajele dintr-un batch simultan, printr-o buclă fără pauze — distribuie cererile în timp sau folosește o coadă de procesare (queue);
  • tratează explicit răspunsul care indică depășirea limitei de rată, cu o pauză și reîncercare, nu cu eșec silențios;
  • dacă ai nevoie constantă de volume mari, discută cu furnizorul limitele aplicabile contului tău, ca să proiectezi coada de procesare în funcție de ele, nu pe presupuneri.

Cum verifici statusul mesajelor

Statusul mesajelor trimise se verifică prin platformă și prin API — nu prin webhook-uri de status de livrare, pentru că acest canal nu funcționează pe bază de webhook. Practic, sistemul tău interoghează periodic starea unei trimiteri în loc să aștepte o notificare push. Dacă procesul tău de business are nevoie de confirmarea că un mesaj a fost livrat (nu doar acceptat de platformă), construiește o verificare programată (polling) după trimitere, nu o presupunere că totul a mers bine doar pentru că cererea inițială a primit răspuns de succes.

Cum testezi fără să trimiți SMS reale

Înainte să pui o integrare în producție, ai nevoie să o testezi fără să consumi SMS-uri reale și fără să deranjezi numere adevărate:

  • folosește un mediu de testare separat de cel de producție, cu propriul token;
  • testează fluxul complet (construirea cererii, trimiterea, interpretarea răspunsului, gestionarea erorilor) cu numere de test proprii, nu cu baza de clienți;
  • simulează explicit scenariile de eroare — token invalid, număr greșit formatat, timeout de rețea — ca să te asiguri că logica de retry și logging chiar funcționează, nu doar calea fericită.

Ce loghezi de partea ta

Jurnalul de mesaje trimise există și în platformă, dar merită să ții și propriul tău jurnal, la nivel de aplicație:

Ce loghezi De ce contează
ID-ul intern al evenimentului (comandă, cont, tranzacție) Leagă trimiterea de contextul de business, util la audit și suport
Timestamp-ul cererii și al răspunsului Permite diagnosticarea întârzierilor și a timeout-urilor
Statusul răspunsului API Diferențiază cererile acceptate de cele respinse la validare
Numărul de reîncercări Arată dacă o trimitere a avut nevoie de retry și de câte ori
Erorile complete (nu doar mesajul generic) Accelerează investigarea când ceva nu funcționează

Acest jurnal propriu completează jurnalul din platformă și te ajută dacă vreodată trebuie să reconstitui exact ce s-a întâmplat cu o trimitere anume, fără să depinzi exclusiv de interfața web.

Întrebări frecvente

Pot testa integrarea fără să trimit SMS-uri reale către clienți?

Da, dacă folosești numere de test proprii și un mediu separat de producție pentru validarea fluxului tehnic — autentificare, formatul cererii, tratarea erorilor.

Ce fac dacă primesc erori intermitente de rețea?

Implementează retry cu backoff exponențial și un număr limitat de reîncercări. Nu retrimite la infinit și nu retrimite imediat, fără pauză între tentative.

Cum evit trimiterea dublă a aceluiași mesaj?

Folosește un identificator unic per eveniment de business (de exemplu ID-ul comenzii) și verifică în sistemul tău dacă evenimentul a fost deja procesat înainte de a retrimite o cerere după un timeout.

Există webhook-uri pentru statusul de livrare?

Nu. Canalul e one-way SMS, fără webhook-uri de status de livrare — statusul se verifică prin platformă și prin API.

Unde găsesc documentația completă, cu toți parametrii și codurile de răspuns?

În contul tău de client. Exemplele din acest articol sunt generice, pentru a ilustra structura unei integrări — parametrii și câmpurile exacte de răspuns sunt detaliate acolo.

Pentru context legat de costuri și volum, articolul despre cât costă SMS marketing în România explică structura de preț pe care o vezi și în contul de client, iar dacă procesezi date personale prin API, merită parcurs și ghidul despre GDPR, consimțământ și opt-out.

Vrei să pui în practică ce ai citit?

Spune-ne ce vrei să trimiți și către câți oameni. Îți răspundem cu prețul pe SMS și cu pașii de pornire.

Alte articole

Toate articolele