Documentation technique

Documentation API SMS REST — Guide développeur

Envoi de SMS transactionnels et marketing, avec sandbox, idempotence, webhooks AR et SDK PHP.

REST JSON Auth Bearer Sandbox Idempotence Webhooks AR SDK PHP

Vous cherchez une vue d'ensemble ? Découvrez notre API SMS (fonctionnalités, tarifs, cas d'usage) .

Base URL : https://sms-proxima.com/api
Auth : Authorization: Bearer VOTRE_TOKEN
Format : application/json

🚀 Démarrage rapide

1

Créez un compte

Inscrivez-vous et attendez la validation de votre compte.

2

Générez votre clé

Depuis votre espace API, générez votre token Bearer.

3

Envoyez votre premier SMS

Testez en sandbox — aucun crédit débité.

curl -X POST https://sms-proxima.com/api/sms/send \
  -H "Authorization: Bearer VOTRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "33612345678",
    "sender": "BOUTIQUE",
    "message": "Votre commande est confirmée.",
    "sandbox": 1
  }'
// Avec le SDK officiel
// composer require sms-proxima/sdk
use SmsProxima\SmsProxima;
$sms = new SmsProxima('VOTRE_TOKEN');
$result = $sms->send('33612345678', 'BOUTIQUE', 'Votre commande est confirmée.', ['sandbox' => 1]);
echo $result['ticket']; // api-42-1712345678
const res = await fetch('https://sms-proxima.com/api/sms/send', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer VOTRE_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    to: '33612345678',
    sender: 'BOUTIQUE',
    message: 'Votre commande est confirmée.',
    sandbox: 1,
  }),
});
const data = await res.json();
console.log(data.ticket); // api-42-1712345678
import requests

response = requests.post(
    'https://sms-proxima.com/api/sms/send',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'},
    json={
        'to': '33612345678',
        'sender': 'BOUTIQUE',
        'message': 'Votre commande est confirmée.',
        'sandbox': 1,
    }
)
data = response.json()
print(data['ticket'])  # api-42-1712345678
// Réponse succès
{ "status": 1, "ticket": "api-42-1712345678", "cost": 1, "credits": 999 }

📐 Formats & validation

Numéros de téléphone

Plusieurs formats sont acceptés — l'API normalise automatiquement.

// France — tous ces formats sont équivalents
"0612345678" // format local
"33612345678" // format international
"+33612345678" // avec +
"0033612345678" // avec 00
"612345678" // sans indicatif
// International — mêmes variantes acceptées
"32612345678" // Belgique
"+32612345678" // Belgique avec +
"0032612345678" // Belgique avec 00
Expéditeur (sender)
  • Entre 4 et 11 caractères
  • Lettres A-Z, a-z et chiffres 0-9 uniquement
  • Pas d'accents, espaces, tirets ou caractères spéciaux
  • Pas que des chiffres
  • Pas 5 chiffres consécutifs
Longueur des messages & segments
SegmentsCaractères max (sans sender)Caractères max (avec sender + STOP)
1160148
2306294
3459447
6 (max)918906

Les caractères accentués courants (à, é, è, ù, €) sont acceptés en GSM7. Les emojis et caractères Unicode nécessitent une gestion spécifique — contactez le support.

🔑 Authentification

Toutes les requêtes doivent inclure ces headers :

Authorization: Bearer VOTRE_TOKEN
Accept: application/json
Content-Type: application/json

Test de connexion :

curl https://sms-proxima.com/api/ping \
  -H "Authorization: Bearer VOTRE_TOKEN"
$sms = new SmsProxima('VOTRE_TOKEN');
$result = $sms->ping();
// ["message" => "Authentifié avec succès", "user" => [...]]
const res = await fetch('https://sms-proxima.com/api/ping', {
  headers: { 'Authorization': 'Bearer VOTRE_TOKEN' },
});
const data = await res.json();
console.log(data.message); // Authentifié avec succès
import requests
res = requests.get('https://sms-proxima.com/api/ping',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'})
print(res.json()['message'])  # Authentifié avec succès
// Réponse
{ "message": "Authentifié avec succès", "user": { "id": 1, "email": "..." } }
POST /sms/send

📤 Envoi SMS

ChampTypeRequisDescription
tostring|arrayOuiUn numéro ou un tableau de numéros au format international
senderstringOuiExpéditeur — voir Formats & validation
messagestringOuiContenu du SMS — max 6 segments
stopintNon0 ou 1 — défaut 1 (mention STOP ajoutée)
timeToSendstringNonEnvoi différé — YYYY/MM/DD HH:MM ou YYYY-MM-DD HH:MM, obligatoirement dans le futur
sandboxintNon1 = simulation (SMS non envoyé, aucun crédit débité, même structure de réponse)
curl -X POST https://sms-proxima.com/api/sms/send \
  -H "Authorization: Bearer VOTRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to":"33612345678","sender":"BOUTIQUE","message":"Votre commande #1234 est confirmée."}'
$result = $sms->send('33612345678', 'BOUTIQUE', 'Votre commande #1234 est confirmée.');
const res = await fetch('https://sms-proxima.com/api/sms/send', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer VOTRE_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({ to: '33612345678', sender: 'BOUTIQUE', message: 'Votre commande #1234 est confirmée.' }),
});
const data = await res.json();
import requests
res = requests.post('https://sms-proxima.com/api/sms/send',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'},
    json={'to': '33612345678', 'sender': 'BOUTIQUE', 'message': 'Votre commande #1234 est confirmée.'})
data = res.json()
curl -X POST https://sms-proxima.com/api/sms/send \
  -H "Authorization: Bearer VOTRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to":["33612345678","33687654321","33698765432"],"sender":"BOUTIQUE","message":"Vos soldes commencent demain !"}'
$result = $sms->send(
    ['33612345678', '33687654321', '33698765432'],
    'BOUTIQUE',
    'Vos soldes commencent demain !'
);
const res = await fetch('https://sms-proxima.com/api/sms/send', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer VOTRE_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    to: ['33612345678', '33687654321', '33698765432'],
    sender: 'BOUTIQUE',
    message: 'Vos soldes commencent demain !',
  }),
});
res = requests.post('https://sms-proxima.com/api/sms/send',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'},
    json={'to': ['33612345678', '33687654321'], 'sender': 'BOUTIQUE', 'message': 'Vos soldes commencent demain !'})
curl -X POST https://sms-proxima.com/api/sms/send \
  -H "Authorization: Bearer VOTRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to":"33612345678","sender":"BOUTIQUE","message":"N oubliez pas votre RDV demain a 14h.","timeToSend":"2026-04-15 09:00"}'
$result = $sms->send('33612345678', 'BOUTIQUE', 'N oubliez pas votre RDV demain a 14h.',
    ['timeToSend' => '2026-04-15 09:00']);
const res = await fetch('https://sms-proxima.com/api/sms/send', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer VOTRE_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    to: '33612345678', sender: 'BOUTIQUE',
    message: 'N oubliez pas votre RDV demain a 14h.',
    timeToSend: '2026-04-15 09:00',
  }),
});
res = requests.post('https://sms-proxima.com/api/sms/send',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'},
    json={'to': '33612345678', 'sender': 'BOUTIQUE',
          'message': 'N oubliez pas votre RDV demain a 14h.', 'timeToSend': '2026-04-15 09:00'})
curl -X POST https://sms-proxima.com/api/sms/send \
  -H "Authorization: Bearer VOTRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to":"33612345678","sender":"TEST","message":"Test integration.","sandbox":1}'
# SMS non envoyé, crédits non débités, réponse identique à un vrai envoi
$result = $sms->send('33612345678', 'TEST', 'Test integration.', ['sandbox' => 1]);
const res = await fetch('https://sms-proxima.com/api/sms/send', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer VOTRE_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({ to: '33612345678', sender: 'TEST', message: 'Test integration.', sandbox: 1 }),
});
res = requests.post('https://sms-proxima.com/api/sms/send',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'},
    json={'to': '33612345678', 'sender': 'TEST', 'message': 'Test integration.', 'sandbox': 1})

Réponse succès

{
"status": 1,
"ticket": "api-1-1712345678",
"cost": 1,
"credits": 999,
"total": 1
}

Réponse erreur

{
"status": 0,
"message": "Ce numéro est en liste noire.",
"code": "MOBILE_BLACKLISTED",
"ticket": null
}

Codes machine possibles

CodeHTTPDescription
ACCOUNT_NOT_VALIDATED403Compte en attente de validation
INSUFFICIENT_CREDITS402Crédits insuffisants
INVALID_TIME_FORMAT422Format de timeToSend invalide
INVALID_TIME_PAST422La date d'envoi est dans le passé
MOBILE_BLACKLISTED422Numéro en liste noire (STOP)
SENDER_NOT_ALLOWED422Expéditeur non autorisé
SUPPLIER_ERROR502Erreur fournisseur — contacter le support

🔁 Idempotence (anti double-envoi)

Le endpoint POST /sms/send supporte l'idempotence pour éviter les doubles envois en cas de retry réseau.

curl -X POST https://sms-proxima.com/api/sms/send \
  -H "Authorization: Bearer VOTRE_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{"to":"33612345678","sender":"BOUTIQUE","message":"..."}'
$result = $sms->send('33612345678', 'BOUTIQUE', '...', [
    'idempotencyKey' => '550e8400-e29b-41d4-a716-446655440000',
]);
const res = await fetch('https://sms-proxima.com/api/sms/send', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer VOTRE_TOKEN',
    'Content-Type': 'application/json',
    'Idempotency-Key': '550e8400-e29b-41d4-a716-446655440000',
  },
  body: JSON.stringify({ to: '33612345678', sender: 'BOUTIQUE', message: '...' }),
});
res = requests.post('https://sms-proxima.com/api/sms/send',
    headers={
        'Authorization': 'Bearer VOTRE_TOKEN',
        'Idempotency-Key': '550e8400-e29b-41d4-a716-446655440000',
    },
    json={'to': '33612345678', 'sender': 'BOUTIQUE', 'message': '...'})
  • Maximum 255 caractères — valide 24 heures
  • Scope : par utilisateur et par endpoint
  • Si rejouée dans les 24h → réponse originale avec header Idempotency-Replayed: true
  • Seules les réponses HTTP 2xx sont mises en cache
Recommandation : générez un UUID v4 côté client pour chaque requête logique et stockez-le avec votre commande.
GET /credits

💳 Crédits disponibles

curl https://sms-proxima.com/api/credits \
  -H "Authorization: Bearer VOTRE_TOKEN"
$credits = $sms->credits(); // int
const res = await fetch('https://sms-proxima.com/api/credits', {
  headers: { 'Authorization': 'Bearer VOTRE_TOKEN' },
});
const { credits } = await res.json();
res = requests.get('https://sms-proxima.com/api/credits',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'})
credits = res.json()['credits']
{ "credits": 1200 }
POST /sms/count

🔢 Comptage de caractères

Calculez le nombre de segments SMS avant envoi.

curl -X POST https://sms-proxima.com/api/sms/count \
  -H "Authorization: Bearer VOTRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message":"Votre code : 1234"}'
$result = $sms->count('Votre code : 1234');
// ["nb_sms" => 1, "nb_caracteres" => 18]
const res = await fetch('https://sms-proxima.com/api/sms/count', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer VOTRE_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({ message: 'Votre code : 1234' }),
});
const { nb_sms, nb_caracteres } = await res.json();
res = requests.post('https://sms-proxima.com/api/sms/count',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'},
    json={'message': 'Votre code : 1234'})
data = res.json()  # {"nb_sms": 1, "nb_caracteres": 18}
{ "nb_sms": 1, "nb_caracteres": 18 }
GET /sms/{tracker}/deliveries

📬 Accusés de réception

Liste paginée des AR reçus pour une campagne. Seuls les destinataires ayant généré un retour opérateur apparaissent. Pour les autres, consultez GET /campaigns (champ pending).

Paramètre de pagination : ?page=1 — 100 résultats par page.

curl "https://sms-proxima.com/api/sms/api-1-1712345678/deliveries?page=1" \
  -H "Authorization: Bearer VOTRE_TOKEN"
$deliveries = $sms->deliveries('api-1-1712345678');
const res = await fetch('https://sms-proxima.com/api/sms/api-1-1712345678/deliveries?page=1', {
  headers: { 'Authorization': 'Bearer VOTRE_TOKEN' },
});
const data = await res.json();
res = requests.get('https://sms-proxima.com/api/sms/api-1-1712345678/deliveries',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'},
    params={'page': 1})
data = res.json()
{
"tracker": "api-1-1712345678",
"data": [{
"mobile": "33612345678",
"status": "delivered",
"operator": "orange",
"is_stop": false,
"received_at": "2026-03-01T10:00:05+00:00"
}],
"total": 1, "per_page": 100, "current_page": 1, "last_page": 1
}
statusDescription
deliveredSMS remis au destinataire
failedÉchec de remise (numéro invalide, hors service…)
pendingEn attente de retour opérateur
GET /campaigns

📋 Historique campagnes

Retour paginé (50/page) avec statistiques d'envoi par campagne. Paramètre : ?page=1.

{
"data": [{
"ticket": "api-1-1712345678",
"sender": "BOUTIQUE",
"date": "2026-03-01 14:00:00",
"count": 100,
"received": 87,
"pending": 10,
"error": 2,
"stop": 1
}],
"total": 42, "per_page": 50, "current_page": 1
}
Le champ pending indique le nombre de destinataires pour lesquels aucun AR n'a encore été reçu. Pour les détails par destinataire, utilisez GET /sms/{ticket}/deliveries.

🚫 Blacklist

MéthodeEndpointDescription
GET/blacklistListe des numéros blacklistés
POST/blacklistAjouter — body : {"mobile": "33612345678"}
DELETE/blacklist/{mobile}Retirer un numéro

Ajout

curl -X POST https://sms-proxima.com/api/blacklist \
  -H "Authorization: Bearer VOTRE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mobile":"33612345678"}'
$sms->addToBlacklist('33612345678');
await fetch('https://sms-proxima.com/api/blacklist', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer VOTRE_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({ mobile: '33612345678' }),
});
requests.post('https://sms-proxima.com/api/blacklist',
    headers={'Authorization': 'Bearer VOTRE_TOKEN'},
    json={'mobile': '33612345678'})

Réponse

{
"status": 1,
"message": "Numéro ajouté en liste rouge.",
"mobile": "33612345678"
}
Un numéro ayant répondu STOP ne peut pas être retiré via l'API.

🔔 Webhook accusés de réception

Configurez une URL HTTPS depuis votre espace API. SMS Proxima envoie un POST JSON à chaque AR opérateur.

Header envoyéValeur
X-SMSP-Eventdelivery.receipt
X-SMSP-IdIdentifiant du message
X-SMSP-TimestampTimestamp Unix
Idempotency-KeyIdentifiant du message (anti-doublon)
{
"version": "v1",
"event": "delivery.receipt",
"event_id": "1711175235",
"campaign_id": 1234,
"message": { "to": "33612345678" },
"delivery": {
"status": "delivered",
"received_at": "2026-03-01T09:59:55+00:00"
}
}

Exemple de réception en PHP

// webhook.php — votre endpoint
$payload = json_decode(file_get_contents('php://input'), true);
$eventId = $payload['event_id'] ?? null;

// Anti-doublon : vérifiez que cet event_id n'a pas déjà été traité
if (alreadyProcessed($eventId)) {
    http_response_code(200);
    exit;
}

$status = $payload['delivery']['status']; // "delivered", "failed"
$mobile = $payload['message']['to'];

// Votre logique métier ici
markDelivered($mobile, $status);

http_response_code(200); // Répondre 2xx sous 6 secondes
Votre endpoint doit répondre en HTTP 2xx sous 6 secondes. Retry automatique jusqu'à 8 fois sur 24h (1min, 5min, 15min, 1h, 3h, 6h, 12h, 24h). Utilisez event_id ou le header Idempotency-Key pour détecter les doublons.

📦 SDK PHP officiel

Compatible PHP 7.4+, zéro dépendance, open source.

// Installation
composer require sms-proxima/sdk

// Envoi simple
use SmsProxima\SmsProxima;
$sms = new SmsProxima('VOTRE_TOKEN');
$result = $sms->send('33612345678', 'BOUTIQUE', 'Commande confirmée');

// Gestion des erreurs
use SmsProxima\Exceptions\InvalidSenderException;
use SmsProxima\Exceptions\MobileBlacklistedException;
use SmsProxima\Exceptions\InsufficientCreditsException;
use SmsProxima\Exceptions\SmsProximaException;

try {
    $sms->send(...);
} catch (InvalidSenderException $e) { // expéditeur invalide
} catch (MobileBlacklistedException $e) { // numéro STOP
} catch (InsufficientCreditsException $e) { // crédits insuffisants
} catch (SmsProximaException $e) { // autre erreur — $e->getApiCode()
}

🔒 Bonnes pratiques

  • Ne jamais exposer votre token côté client — l'appel API doit toujours venir de votre serveur, jamais depuis du JavaScript public ou une app mobile.
  • Utilisez l'idempotence sur vos retries — en cas d'erreur réseau, rejouez la requête avec le même Idempotency-Key pour éviter les doubles envois.
  • Testez toujours en sandbox d'abord — paramètre sandbox: 1, réponse identique à un vrai envoi, aucun crédit débité.
  • Stockez les événements webhook pour traitement asynchrone — enregistrez le payload en base à la réception, traitez-le dans un job. Évite les timeouts et garantit la cohérence.
  • Régénérez votre token en cas de compromission — depuis votre espace API, la régénération est immédiate et invalide l'ancien token.

⚠️ Codes HTTP

Les codes HTTP indiquent le résultat au niveau transport. Les codes machine (code dans le body) précisent la raison métier.

CodeDescription
200Succès
201Ressource créée (ex : ajout blacklist)
400Requête malformée (ex : clé d'idempotence trop longue)
402Crédits insuffisants
403Accès refusé (compte non validé, tracker invalide, numéro STOP protégé)
404Ressource introuvable
409Conflit (ex : numéro déjà en blacklist)
422Paramètres invalides — voir le champ code dans la réponse
502Erreur fournisseur — contacter le support

Prêt à intégrer l'API ?

Créez un compte, générez votre clé et envoyez votre premier SMS en quelques minutes.