Documentation de l'API AdaSMS.ma

Envoyez des SMS vers les numéros marocains depuis votre application : une API REST en JSON, une clé par application, des exemples prêts à copier.

Créer un compte Accéder à mon espace https://api.adasms.ma/v1
Sommaire

Introduction

L'API AdaSMS.ma envoie des SMS unitaires ou en masse vers les numéros marocains, permet de suivre chaque message, de partager des documents par lien sécurisé (AdaLink) et de consulter votre solde. Vos systèmes peuvent aussi être prévenus en temps réel par webhook.

URL de base

text
https://api.adasms.ma/v1

Toutes les requêtes passent en HTTPS. Les corps de requête et de réponse sont en JSON (sauf l'envoi de fichiers AdaLink, en multipart/form-data).

Format des réponses

Chaque réponse contient success (true ou false). En cas d'erreur, message explique le problème et, pour les erreurs à traiter dans votre code, code donne une valeur stable (voir Codes d'erreur).

iLes messages d'erreur (message) sont rédigés en français. Dans votre code, fiez-vous au statut HTTP et au champ code, jamais au texte du message.

Authentification

Chaque requête porte votre clé API dans l'en-tête X-API-Key. Créez vos clés dans votre espace client, menu Clés API : une clé par application, que vous pouvez désactiver à tout moment.

http
X-API-Key: adasms_VOTRE_CLE

Une clé se compose de adasms_ suivi de 48 caractères hexadécimaux.

!La clé n'est affichée qu'une seule fois, à sa création. Conservez-la côté serveur (variable d'environnement, coffre de secrets) et ne l'intégrez jamais dans une application mobile ou une page web. En cas de perte, créez une nouvelle clé et désactivez l'ancienne.

Erreurs d'authentification

Statut HTTPCodeCause
401—En-tête X-API-Key absent
401—Clé inconnue, désactivée ou mal formée
403—Compte suspendu
403SENDER_EXPIREDClé liée à un Sender ID expiré ou inactif
429RATE_LIMITEDPlus de 20 clés mal formées depuis la même adresse IP en 10 minutes

Numéros de téléphone

AdaSMS.ma envoie uniquement vers les numéros marocains. Trois formats sont acceptés, partout (envoi unitaire, envoi en masse, AdaLink) ; espaces, tirets, points et parenthèses sont ignorés. Les numéros sont enregistrés et renvoyés au format +212XXXXXXXXX.

FormatExempleEnregistré comme
+212XXXXXXXXX+212600000001+212600000001
212XXXXXXXXX212600000001+212600000001
0XXXXXXXXX06 00 00 00 01+212600000001

Un numéro illisible renvoie une erreur 400. Un numéro étranger (par exemple +33…) renvoie une erreur 400 avec le code NON_MOROCCAN_NUMBER, sans aucun débit ; dans un envoi en masse, toute la requête est alors refusée.

Segments et encodage

Un SMS est facturé par segment. Le nombre de segments dépend de la longueur du texte et de son encodage, détecté automatiquement :

Encodage1 segmentPlusieurs segments
GSM-7 (alphabet standard)160 caractères153 caractères par segment
Unicode / UCS-2 (arabe, emojis, certains accents)70 caractères67 caractères par segment

Un texte est limité à 10 segments (1 530 caractères GSM-7 ou 670 en Unicode) ; au-delà, l'API répond 400 TEXT_TOO_LONG. En GSM-7, les caractères ^ { } \ [ ] ~ | € comptent double.

iUn seul caractère hors de l'alphabet GSM-7 fait passer tout le texte en Unicode. Pièges courants : ê â î ô û ë ï ç. Avec gsm_replace: true, ces caractères sont remplacés par leur équivalent GSM-7 avant l'envoi.

Limites de débit

POST /messages, POST /bulk et GET /account sont limités par fenêtre de 60 secondes :

PérimètreLimite par fenêtre de 60 s
Par clé API600 requêtes
Par adresse IP1 200 requêtes

Au-delà, l'API répond 429 avec le code RATE_LIMITED et l'en-tête Retry-After (délai en secondes). Pour envoyer beaucoup de messages, préférez POST /bulk (jusqu'à 1 000 destinataires par requête). Besoin d'une limite plus élevée ? Écrivez à support@adasms.ma.

Référence de l'API

Envoyer un SMS

POST/v1/messages

Envoie un SMS à un numéro marocain. Le coût est débité au moment de l'envoi (prix unitaire de votre plan × nombre de segments). Si l'envoi échoue chez l'opérateur, le montant est recrédité sur votre solde.

Soumis à la limite de débit. Voir ›

Corps de la requête

Corps en JSON.

ChampTypeRequisDescription
tostringOuiNuméro marocain : +212XXXXXXXXX, 212XXXXXXXXX ou 0XXXXXXXXX (espaces, tirets, points et parenthèses ignorés). Ramené au format +212XXXXXXXXX.
textstringOuiTexte du SMS, 10 segments au maximum (1 530 caractères GSM-7 ou 670 en Unicode). Voir « Segments et encodage ».
fromstring—Votre Sender ID (nom d'expéditeur) validé. Obligatoire dès que vous avez au moins un Sender ID validé. Sans Sender ID validé, laissez-le vide : l'expéditeur partagé est utilisé pour un nombre limité d'envois de découverte. Si votre clé API est associée à un Sender ID, celui-ci est toujours utilisé.
typestring—Étiquette libre (ex. otp, alerte, promo), reprise dans le message et les webhooks. Par défaut : transactional
referencestring—Votre référence libre (ASCII imprimable, 64 caractères maximum), pour retrouver vos messages avec GET /messages?reference=….
gsm_replaceboolean—Remplace avant l'envoi les caractères Unicode courants par leur équivalent GSM-7 (ê→e, ç→c, «→", —→-, …→...). Le texte enregistré est le texte remplacé. Par défaut : false

Requête

bash
curl -X POST "https://api.adasms.ma/v1/messages" \
  -H "X-API-Key: adasms_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "+212600000001",
  "text": "Votre code de vérification : 847291",
  "from": "MonService",
  "type": "otp",
  "reference": "CMD-2026-001"
}'

Réponse 202

Envoi accepté.

json
{
  "success": true,
  "messageId": "3f6c2a91-5b7e-4d0a-9c1e-2b8f4e6d7a10",
  "status": "sent",
  "providerMessageId": "9a8b7c6d-0000-4e1f-8a2b-3c4d5e6f7a8b",
  "cost": "0.4900",
  "channel": "sms",
  "downgraded": false,
  "segments": 1,
  "encoding": "GSM7",
  "reference": "CMD-2026-001"
}
Champs de la réponse
ChampTypeDescription
messageIdstring
statusstringsent = transmis à l'opérateur ; queued = en attente de transmission. Valeurs : queued, sent
providerMessageIdstringIdentifiant attribué par l'opérateur.
coststringMontant débité en MAD HT (prix d'un segment × segments), 4 décimales.
providerstringDéconseillé Champ technique conservé pour compatibilité ; sa valeur peut changer sans préavis. Ne l'utilisez pas.
channelstringValeurs : sms
downgradedbooleantrue si le message est parti en SMS alors qu'une règle de votre compte prévoyait un autre canal.
segmentsinteger
encodingstringValeurs : GSM7, UCS2
referencestring | null

Erreurs

Statut HTTPCodeCause
400—to ou text absent
400—Numéro illisible (formats acceptés, voir « Numéros de téléphone »)
400NON_MOROCCAN_NUMBERNuméro hors Maroc
400—reference invalide (ASCII imprimable, 64 caractères maximum)
400TEXT_TOO_LONGTexte de plus de 10 segments
400DEFAULT_SENDER_FORBIDDENfrom absent alors que vous avez un Sender ID validé
400DEFAULT_SENDER_QUOTA_EXCEEDEDEnvois de découverte avec l'expéditeur partagé épuisés
401, 403—Clé API absente ou invalide, compte suspendu, Sender ID de la clé expiré : voir Authentification.
402INSUFFICIENT_CREDITSolde insuffisant
403EMAIL_NOT_VERIFIEDAdresse e-mail du compte non confirmée
429RATE_LIMITEDLimite de débit atteinte
502—Échec de l'envoi

Rechercher par référence

GET/v1/messages

Retourne vos messages dont le champ reference est exactement la valeur fournie : 100 au maximum, du plus récent au plus ancien.

Paramètres de requête

ChampTypeRequisDescription
referencestringOuiRéférence fournie à l'envoi.

Requête

bash
curl "https://api.adasms.ma/v1/messages?reference=CMD-2026-001" \
  -H "X-API-Key: adasms_VOTRE_CLE"

Réponse 200

Messages trouvés (liste éventuellement vide).

json
{
  "success": true,
  "messages": [
    {
      "id": "3f6c2a91-5b7e-4d0a-9c1e-2b8f4e6d7a10",
      "to": "+212600000001",
      "from": "MonService",
      "type": "otp",
      "channel": "sms",
      "status": "sent",
      "text": "Votre code de vérification : 847291",
      "cost": "0.49",
      "billingOutcome": "charged",
      "segments": 1,
      "encoding": "GSM7",
      "reference": "CMD-2026-001",
      "providerMessageId": "9a8b7c6d-0000-4e1f-8a2b-3c4d5e6f7a8b",
      "errorMessage": null,
      "createdAt": "2026-11-10T09:00:00.000Z",
      "updatedAt": "2026-11-10T09:00:01.200Z"
    }
  ]
}
Champs de la réponse
ChampTypeDescription
messagesarray<object>
messages[].idstring
messages[].tostringNuméro au format +212XXXXXXXXX.
messages[].fromstring | null
messages[].typestring
messages[].channelstringValeurs : sms
messages[].statusstringqueued = en attente ; sent = transmis à l'opérateur ; delivered = remis au téléphone (selon l'opérateur, pas encore disponible) ; failed = échec. Valeurs : queued, sent, delivered, failed
messages[].textstring
messages[].coststringMontant débité en MAD HT ("0" si l'envoi a échoué).
messages[].providerstring | nullDéconseillé Champ technique conservé pour compatibilité ; ne l'utilisez pas.
messages[].billingOutcomestringcharged = facturé ; refunded = recrédité après un incident ; not_charged = refusé avant l'envoi, non facturé. Valeurs : charged, refunded, not_charged
messages[].segmentsinteger
messages[].encodingstringValeurs : GSM7, UCS2
messages[].referencestring | null
messages[].providerMessageIdstring | null
messages[].errorMessagestring | nullMotif de l'échec, texte libre.
messages[].createdAtstring
messages[].updatedAtstring

Erreurs

Statut HTTPCodeCause
400—Paramètre reference absent
401, 403—Clé API absente ou invalide, compte suspendu, Sender ID de la clé expiré : voir Authentification.

Consulter un message

GET/v1/messages/{messageId}

Retourne un message de votre compte.

Paramètres de chemin

ChampTypeRequisDescription
messageIdstringOuiIdentifiant renvoyé à l'envoi (messageId).

Requête

bash
curl "https://api.adasms.ma/v1/messages/3f6c2a91-5b7e-4d0a-9c1e-2b8f4e6d7a10" \
  -H "X-API-Key: adasms_VOTRE_CLE"

Réponse 200

Le message.

json
{
  "success": true,
  "message": {
    "id": "3f6c2a91-5b7e-4d0a-9c1e-2b8f4e6d7a10",
    "to": "+212600000001",
    "from": "MonService",
    "type": "otp",
    "channel": "sms",
    "status": "sent",
    "text": "Votre code de vérification : 847291",
    "cost": "0.49",
    "billingOutcome": "charged",
    "segments": 1,
    "encoding": "GSM7",
    "reference": "CMD-2026-001",
    "providerMessageId": "9a8b7c6d-0000-4e1f-8a2b-3c4d5e6f7a8b",
    "errorMessage": null,
    "createdAt": "2026-11-10T09:00:00.000Z",
    "updatedAt": "2026-11-10T09:00:01.200Z"
  }
}
Champs de la réponse
ChampTypeDescription
messageobject
message.idstring
message.tostringNuméro au format +212XXXXXXXXX.
message.fromstring | null
message.typestring
message.channelstringValeurs : sms
message.statusstringqueued = en attente ; sent = transmis à l'opérateur ; delivered = remis au téléphone (selon l'opérateur, pas encore disponible) ; failed = échec. Valeurs : queued, sent, delivered, failed
message.textstring
message.coststringMontant débité en MAD HT ("0" si l'envoi a échoué).
message.providerstring | nullDéconseillé Champ technique conservé pour compatibilité ; ne l'utilisez pas.
message.billingOutcomestringcharged = facturé ; refunded = recrédité après un incident ; not_charged = refusé avant l'envoi, non facturé. Valeurs : charged, refunded, not_charged
message.segmentsinteger
message.encodingstringValeurs : GSM7, UCS2
message.referencestring | null
message.providerMessageIdstring | null
message.errorMessagestring | nullMotif de l'échec, texte libre.
message.createdAtstring
message.updatedAtstring

Erreurs

Statut HTTPCodeCause
401, 403—Clé API absente ou invalide, compte suspendu, Sender ID de la clé expiré : voir Authentification.
404—Message introuvable

Envoyer des SMS en masse

POST/v1/bulk

Envoie jusqu'à 1 000 SMS en une requête, avec un texte commun ou un texte par destinataire. Les numéros acceptent les mêmes formats que l'envoi unitaire. Les doublons (après mise au format +212) ne sont envoyés qu'une fois. Le coût total est vérifié puis débité avant l'envoi ; chaque message refusé par l'opérateur est recrédité. Si un seul numéro est invalide ou hors Maroc, toute la requête est refusée et rien n'est débité.

Soumis à la limite de débit. Voir ›

Corps de la requête

Corps en JSON.

ChampTypeRequisDescription
recipientsarray<string | object>OuiNuméros, ou objets {to, text, reference}. 1 000 au maximum.
recipients[].tostringOuiNuméro marocain : +212XXXXXXXXX, 212XXXXXXXXX ou 0XXXXXXXXX (espaces, tirets, points et parenthèses ignorés). Ramené au format +212XXXXXXXXX.
recipients[].textstring—Texte propre à ce destinataire (sinon le texte commun).
recipients[].referencestring—Votre référence libre (ASCII imprimable, 64 caractères maximum), pour retrouver vos messages avec GET /messages?reference=….
textstring—Texte commun, obligatoire si un destinataire n'a pas son propre texte.
fromstring—Votre Sender ID validé (mêmes règles que POST /messages).
typestring—Étiquette libre. Par défaut : bulk
gsm_replaceboolean—Remplacement GSM-7 appliqué à chaque texte (voir POST /messages). Par défaut : false

Requête

Texte commun

bash
curl -X POST "https://api.adasms.ma/v1/bulk" \
  -H "X-API-Key: adasms_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{
  "recipients": [
    "+212600000001",
    "0600000002",
    "212600000003"
  ],
  "text": "Votre commande #4521 a été expédiée.",
  "from": "MaBoutique"
}'

Texte par destinataire

bash
curl -X POST "https://api.adasms.ma/v1/bulk" \
  -H "X-API-Key: adasms_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{
  "from": "MaBoutique",
  "recipients": [
    {
      "to": "+212600000001",
      "text": "Bonjour Karim, votre solde est de 250 MAD.",
      "reference": "CLI-001"
    },
    {
      "to": "0600000002",
      "text": "Bonjour Salma, votre solde est de 80 MAD.",
      "reference": "CLI-002"
    }
  ]
}'

Réponse 202

Lot traité. Le détail de chaque message est disponible avec GET /bulk/{batchId}.

json
{
  "success": true,
  "batchId": "7c1d9e20-4a3b-4f6e-8d2c-1a0b9c8d7e6f",
  "total": 3,
  "status": "completed",
  "estimatedCost": "1.4700"
}
Champs de la réponse
ChampTypeDescription
batchIdstring
totalintegerNombre de destinataires après suppression des doublons.
statusstringfailed si tous les messages ont échoué. Valeurs : completed, failed
estimatedCoststringMontant débité avant l'envoi, en MAD HT ; les messages en échec sont recrédités.

Erreurs

Statut HTTPCodeCause
400—recipients absent ou vide
400—Plus de 1 000 destinataires
400—Numéro illisible ou texte absent (détail par destinataire dans errors)
400NON_MOROCCAN_NUMBERNuméro hors Maroc (détail par destinataire dans errors)
400—reference invalide (ASCII imprimable, 64 caractères maximum)
400TEXT_TOO_LONGTexte de plus de 10 segments
400DEFAULT_SENDER_FORBIDDENfrom absent alors que vous avez un Sender ID validé
400DEFAULT_SENDER_QUOTA_EXCEEDEDEnvois de découverte avec l'expéditeur partagé épuisés
401, 403—Clé API absente ou invalide, compte suspendu, Sender ID de la clé expiré : voir Authentification.
402INSUFFICIENT_CREDITSolde insuffisant
403EMAIL_NOT_VERIFIEDAdresse e-mail du compte non confirmée
429RATE_LIMITEDLimite de débit atteinte
502—Échec de l'envoi

Consulter un lot

GET/v1/bulk/{batchId}

Retourne un lot de votre compte et le statut de chacun de ses messages.

Paramètres de chemin

ChampTypeRequisDescription
batchIdstringOuiIdentifiant renvoyé à l'envoi (batchId).

Requête

bash
curl "https://api.adasms.ma/v1/bulk/7c1d9e20-4a3b-4f6e-8d2c-1a0b9c8d7e6f" \
  -H "X-API-Key: adasms_VOTRE_CLE"

Réponse 200

Le lot, ses messages et leur décompte.

json
{
  "success": true,
  "batch": {
    "id": "7c1d9e20-4a3b-4f6e-8d2c-1a0b9c8d7e6f",
    "clientId": "0b5e8f2a-1c3d-4e6f-9a7b-8c9d0e1f2a3b",
    "type": "bulk",
    "channel": "sms",
    "status": "completed",
    "totalMessages": 3,
    "sentCount": 3,
    "failedCount": 0,
    "estimatedCost": "1.47",
    "actualCost": "1.47",
    "createdAt": "2026-11-10T09:00:00.000Z",
    "updatedAt": "2026-11-10T09:00:01.200Z"
  },
  "messages": [
    {
      "id": "5e2a7b10-9c4d-4f1e-8a3b-6d7c8e9f0a1b",
      "to": "+212600000001",
      "status": "sent",
      "providerMessageId": "9a8b7c6d-0000-4e1f-8a2b-3c4d5e6f7a8c",
      "cost": "0.49",
      "billingOutcome": "charged",
      "errorMessage": null,
      "createdAt": "2026-11-10T09:00:00.100Z"
    }
  ],
  "summary": {
    "total": 3,
    "sent": 3,
    "failed": 0,
    "pending": 0
  }
}
Champs de la réponse
ChampTypeDescription
batchobject
batch.idstring
batch.clientIdstring
batch.typestring
batch.channelstringValeurs : sms
batch.statusstringValeurs : processing, completed, failed
batch.totalMessagesinteger
batch.sentCountinteger
batch.failedCountinteger
batch.estimatedCoststring
batch.actualCoststring
batch.createdAtstring
batch.updatedAtstring
messagesarray<object>
messages[].idstring
messages[].tostring
messages[].statusstringValeurs : queued, sent, delivered, failed
messages[].providerMessageIdstring | null
messages[].coststring
messages[].billingOutcomestringValeurs : charged, refunded, not_charged
messages[].errorMessagestring | null
messages[].createdAtstring
summaryobject
summary.totalinteger
summary.sentinteger
summary.failedinteger
summary.pendingintegerMessages encore en attente (queued).

Erreurs

Statut HTTPCodeCause
401, 403—Clé API absente ou invalide, compte suspendu, Sender ID de la clé expiré : voir Authentification.
404—Lot introuvable

Solde du compte

GET/v1/account

Retourne le solde, le plan, le mode de facturation et le prix d'un segment SMS de votre compte.

Soumis à la limite de débit. Voir ›

Requête

bash
curl "https://api.adasms.ma/v1/account" \
  -H "X-API-Key: adasms_VOTRE_CLE"

Réponse 200

Informations du compte.

json
{
  "success": true,
  "account": {
    "name": "Ma Société",
    "plan": "starter",
    "billingMode": "prepaid",
    "balance": "549.8100",
    "currency": "MAD",
    "smsUnitPrice": "0.4900",
    "estimatedSmsRemaining": 1122
  }
}
Champs de la réponse
ChampTypeDescription
accountobject
account.namestring
account.planstringCode du plan (starter, business, enterprise).
account.billingModestringValeurs : prepaid, postpaid
account.balancestringSolde en MAD HT, 4 décimales, identique au tableau de bord.
account.currencystringValeurs : MAD
account.smsUnitPricestringPrix d'un segment SMS de votre plan, en MAD HT.
account.estimatedSmsRemaininginteger | nullNombre de SMS d'un segment GSM-7 que couvre le solde (partie entière de balance ÷ smsUnitPrice) ; 0 si le solde est nul ou négatif ; null en postpayé.

Erreurs

Statut HTTPCodeCause
401, 403—Clé API absente ou invalide, compte suspendu, Sender ID de la clé expiré : voir Authentification.
429RATE_LIMITEDLimite de débit atteinte

Webhooks

Un webhook prévient votre serveur d'un événement (SMS envoyé, SMS en échec, envoi en volume ou campagne terminés) par une requête POST en JSON. Créez-le dans votre espace client, menu Webhooks : URL de réception en HTTPS et événements choisis. Le secret de signature est affiché une seule fois, à la création (ou quand vous en générez un nouveau).

En-têtes envoyés

En-têteValeur
Content-Typeapplication/json
X-AdaSMS-EventNom de l'événement, par exemple message.sent
X-AdaSMS-TimestampDate d'envoi de la requête (ISO 8601)
X-AdaSMS-Signaturesha256= suivi de la signature HMAC-SHA256 du corps brut, calculée avec votre secret

Vérifier la signature (Node.js)

javascript
const crypto = require('crypto');
const express = require('express');
const app = express();

function signatureValide(corpsBrut, secret, entete) {
  const attendue = 'sha256=' + crypto.createHmac('sha256', secret).update(corpsBrut).digest('hex');
  return entete.length === attendue.length
    && crypto.timingSafeEqual(Buffer.from(attendue), Buffer.from(entete));
}

// Lire le corps brut : la signature porte sur les octets reçus.
app.post('/webhooks/adasms', express.raw({ type: 'application/json' }), (req, res) => {
  const entete = req.get('X-AdaSMS-Signature') || '';
  if (!signatureValide(req.body, process.env.ADASMS_WEBHOOK_SECRET, entete)) {
    return res.sendStatus(401);
  }
  const evenement = JSON.parse(req.body.toString('utf8'));
  console.log(evenement.event, evenement.data);
  res.sendStatus(200);
});

Vérifier la signature (PHP)

php
<?php
$corps   = file_get_contents('php://input');
$entete  = $_SERVER['HTTP_X_ADASMS_SIGNATURE'] ?? '';
$attendu = 'sha256=' . hash_hmac('sha256', $corps, getenv('ADASMS_WEBHOOK_SECRET'));

if (!hash_equals($attendu, $entete)) {
    http_response_code(401);
    exit;
}
$evenement = json_decode($corps, true);
http_response_code(200);

Vérifier la signature (Python)

python
import hashlib, hmac, os
from flask import Flask, request, abort

app = Flask(__name__)

@app.post('/webhooks/adasms')
def webhook():
    attendu = 'sha256=' + hmac.new(os.environ['ADASMS_WEBHOOK_SECRET'].encode(),
                                   request.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(attendu, request.headers.get('X-AdaSMS-Signature', '')):
        abort(401)
    evenement = request.get_json()
    return '', 200

Réponse et nouvelles tentatives

Répondez par un statut 2xx en moins de 10 secondes. Sinon (erreur, délai dépassé), AdaSMS.ma renvoie le même événement 1 minute puis 5 minutes plus tard : 3 tentatives au total. Traitez les événements de façon idempotente (par exemple avec messageId), un même événement pouvant arriver deux fois.

Événements

ÉvénementDéclenché quand
message.sentUn SMS envoyé avec POST /messages a été transmis à l'opérateur.
message.failedUn SMS envoyé avec POST /messages a été refusé ; son montant a été recrédité (cost vaut "0.0000").
batch.completedUn envoi en volume lancé depuis le tableau de bord (ou une campagne) est terminé. Les lots envoyés avec POST /bulk sont traités pendant la requête : ils ne déclenchent pas ce webhook, la réponse contient déjà leur résultat.
campaign.completedUne campagne est terminée (status completed) ou a été arrêtée en cours d'envoi (status stopped).
campaign.failedUne campagne programmée n'a pas pu être lancée à l'heure prévue (par exemple solde insuffisant) ; rien n'a été débité.

message.sent — SMS transmis à l'opérateur

json
{
  "event": "message.sent",
  "timestamp": "2026-11-10T09:00:01.000Z",
  "data": {
    "messageId": "3f6c2a91-5b7e-4d0a-9c1e-2b8f4e6d7a10",
    "to": "+212600000001",
    "from": "MonService",
    "type": "otp",
    "channel": "sms",
    "status": "sent",
    "cost": "0.4900",
    "segments": 1,
    "encoding": "GSM7",
    "reference": "CMD-2026-001",
    "billingOutcome": "charged",
    "providerMessageId": "9a8b7c6d-0000-4e1f-8a2b-3c4d5e6f7a8b",
    "clientTxnId": null,
    "networkErrorCode": null,
    "errorMessage": null,
    "batchId": null,
    "campaignId": null
  }
}

message.failed — SMS en échec

json
{
  "event": "message.failed",
  "timestamp": "2026-11-10T09:00:01.000Z",
  "data": {
    "messageId": "3f6c2a91-5b7e-4d0a-9c1e-2b8f4e6d7a11",
    "to": "+212600000002",
    "from": "MonService",
    "type": "transactional",
    "channel": "sms",
    "status": "failed",
    "cost": "0.0000",
    "segments": 1,
    "encoding": "GSM7",
    "reference": null,
    "billingOutcome": "not_charged",
    "providerMessageId": null,
    "clientTxnId": null,
    "networkErrorCode": null,
    "errorMessage": "Destinataire rejeté",
    "batchId": null,
    "campaignId": null
  }
}

batch.completed — Envoi en volume terminé

json
{
  "event": "batch.completed",
  "timestamp": "2026-11-10T09:05:00.000Z",
  "data": {
    "batchId": "7c1d9e20-4a3b-4f6e-8d2c-1a0b9c8d7e70",
    "totalMessages": 250,
    "sentCount": 248,
    "failedCount": 2,
    "actualCost": "121.5200",
    "status": "completed",
    "campaignId": null
  }
}

campaign.completed — Campagne terminée

json
{
  "event": "campaign.completed",
  "timestamp": "2026-11-10T10:00:00.000Z",
  "data": {
    "campaignId": "4e6a8c0e-2b3d-4f5a-9b7c-1d3e5f7a9b0c",
    "totalMessages": 500,
    "sentCount": 497,
    "failedCount": 3,
    "actualCost": "243.5300",
    "status": "completed"
  }
}

campaign.failed — Campagne programmée non lancée

json
{
  "event": "campaign.failed",
  "timestamp": "2026-11-10T08:00:00.000Z",
  "data": {
    "campaignId": "4e6a8c0e-2b3d-4f5a-9b7c-1d3e5f7a9b0d",
    "name": "Promo novembre",
    "scheduledAt": "2026-11-10T08:00:00.000Z",
    "error": "Solde insuffisant : coût 243.5300 MAD, solde 12.0000 MAD"
  }
}

Codes d'erreur

Valeurs stables du champ code, à utiliser dans votre code. Les autres erreurs n'ont pas de code : fiez-vous au statut HTTP.

CodeStatut HTTPDescription
NON_MOROCCAN_NUMBER400Le numéro n'est pas un numéro marocain (+212 suivi de 9 chiffres). Rien n'est débité.
TEXT_TOO_LONG400Le texte dépasse 10 segments (1 530 caractères GSM-7 ou 670 en Unicode).
DEFAULT_SENDER_FORBIDDEN400Vous avez un Sender ID validé, l'expéditeur partagé n'est plus disponible ; indiquez from.
DEFAULT_SENDER_QUOTA_EXCEEDED400Vos envois de découverte avec l'expéditeur partagé sont épuisés ; demandez votre Sender ID.
INSUFFICIENT_CREDIT402Solde insuffisant. Rien n'est débité ; rechargez votre compte.
EMAIL_NOT_VERIFIED403L'adresse e-mail du compte n'est pas confirmée ; l'envoi est bloqué jusqu'à sa confirmation.
SENDER_EXPIRED403La clé API est liée à un Sender ID expiré ou inactif ; renouvelez-le ou changez la clé.
RATE_LIMITED429Trop de requêtes ; attendez le délai de l'en-tête Retry-After.

Tarifs

Crédit prépayé, sans engagement ni abonnement. Le prix d'un SMS dépend de votre plan et se compte par segment (voir Segments et encodage). Le montant est débité à l'envoi et recrédité si l'opérateur refuse le message.

PlanPrix par segmentVolume
Starter0,49 MAD HTmoins de 10 000 SMS/mois
Business0,35 MAD HT10 000 à 99 999 SMS/mois
Enterprise0,30 MAD HT100 000+ SMS/mois

Prix par lien, selon sa durée de validité : chaque jour est facturé au tarif de sa tranche. Le SMS qui porte le lien est facturé en plus, au prix de votre plan.

Durée de validitéTarif HT par jourExemple
1 à 7 jours1,40 MAD1 j = 1,40 · 7 j = 9,80 MAD
8 à 14 jours0,70 MAD14 j = 14,70 MAD
15 à 30 jours0,30 MAD30 j = 19,50 MAD
Plus de 30 joursSur devis—

GET /account renvoie le prix d'un segment de votre plan (smsUnitPrice) et votre solde.

Démarrage rapide

  1. Créez votre compte sur app.adasms.ma et confirmez votre adresse e-mail : l'envoi est bloqué tant qu'elle n'est pas confirmée.
  2. Créez une clé API dans le menu Clés API et copiez-la (elle ne sera plus affichée).
  3. Envoyez votre premier SMS :
bash
curl -X POST https://api.adasms.ma/v1/messages \
  -H "X-API-Key: adasms_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"to": "0600000001", "text": "Bonjour depuis AdaSMS.ma"}'

Une réponse 202 avec "success": true confirme l'envoi. Sans Sender ID validé, laissez from vide : l'expéditeur partagé est utilisé pour vos envois de découverte. Pour envoyer sous votre nom, demandez un Sender ID depuis votre espace client.

Réservé à votre espace client

Vos clés API, le secret de vos webhooks, l'historique de vos messages, vos factures et vos Sender ID se gèrent dans votre espace client, app.adasms.ma. Une question ? support@adasms.ma.

🍪 Ce site utilise des cookies pour améliorer votre expérience et analyser le trafic.