Technical Documentation
Integrate EnvoiSMS.ma in under 15 minutes with our PHP, Node.js, and Python SDKs. Built for engineers.
Start here
Everything to get started before your first request.
EnvoiSMS.ma is a programmable messaging infrastructure built for Morocco. Our direct carrier routes with IAM, Inwi, and Orange guarantee minimal latency.
Generate your "env_live_..." API key from your EnvoiSMS.ma Console.
Use Bearer authentication in your HTTP headers for each request.
Test your integration using Sandbox mode to consume no real credits.
Integrate the WhatsApp Business API to divide your OTP costs by 10.
Configure a signed Webhook to receive delivery reports in real time.
Track your consumption and MAD invoices directly on your Dashboard.
// config/services.php
'envoisms' => [
'key' => env('ENVOISMS_API_KEY'),
],
// Usage
Http::withToken(config('services.envoisms.key'))
->post('https://api.envoisms.ma/v1/messages', [
'to' => '+212612345678',
'message' => 'Votre commande est en cours de livraison đźšš',
'from' => 'MaBoutique'
]); OpenAPI Spec Authentication
Bearer keys, headers, and security constraints.
Each /v1 endpoint requires a valid API key passed in the Authorization header as a Bearer token. Test and production keys can be generated or revoked from your console.
Authorization: Bearer env_live_xxx
X-RateLimit-Limit and X-RateLimit-Remaining returned with each call.
Requests coming from unconfigured IP addresses return a 401 status.
JSON, Authorization, X-EnvoiSMS.ma-Signature, and X-EnvoiSMS.ma-Version are supported.
POST /v1/messages HTTP/1.1
Host: api.envoisms.ma
Authorization: Bearer env_live_xxxxxxxx
Content-Type: application/json
Accept: application/jsonOpen Source
Official SDKs & Client Libraries
Integrate EnvoiSMS API into your application with our official open-source client libraries.
npm install envoismscomposer require envoisms/envoisms-phppip install envoismscomposer require envoisms/laravel-otp/v1/messagesSend a message
Sends a transaction or marketing message via SMS or WhatsApp Business API.
- Les sauts de ligne (\n) sont pleinement pris en charge sur tous les canaux et s'affichent correctement chez le destinataire.
- Le formatage de texte enrichi (gras, italique, etc.) n'est pas supporté par le canal SMS (texte brut uniquement).
- Le canal WhatsApp prend en charge le formatage de texte avec la syntaxe standard (*gras*, _italique_, ~barré~).
curl -X POST "https://api.envoisms.ma/v1/messages" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"to": "+212612345678",
"message": "Votre code de validation est 849204",
"from": "MaBoutique",
"channel": "whatsapp"
}'{
"id": "msg_8f2d...",
"to": "+212612345678",
"channel": "whatsapp",
"cascade": false,
"status": "queued",
"cost": {
"eur": 0.0118,
"mad": 0.13
},
"segments": 1,
"created_at": "2026-05-15T10:30:00Z"
}/v1/messages/bulkEnvoi groupé (Bulk)
Envoie jusqu'Ă 10 000 messages en un seul appel API avec des destinataires ou des contenus uniques.
- Les sauts de ligne (\n) sont pleinement pris en charge dans les corps des messages groupés.
- Le formatage de texte enrichi (gras, italique, etc.) n'est pas supporté par le canal SMS (texte brut uniquement).
- Le canal WhatsApp prend en charge le formatage de texte avec la syntaxe standard (*gras*, _italique_, ~barré~).
curl -X POST "https://api.envoisms.ma/v1/messages/bulk" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"to": "+212611111111",
"message": "Hello Client 1"
},
{
"to": "+212622222222",
"message": "Hello Client 2"
}
],
"from": "ENVOISMS",
"channel": "sms"
}'{
"batch_id": "batch_9a3c...",
"total": 2,
"channel": "sms",
"estimated_cost": {
"eur": 0.056,
"mad": 0.62
},
"messages": [
{
"id": "msg_1a2b...",
"to": "+212611111111",
"status": "queued"
},
{
"id": "msg_3c4d...",
"to": "+212622222222",
"status": "queued"
}
]
}/v1/messagesSend a message
Sends a transaction or marketing message via SMS or WhatsApp Business API.
curl -X GET "https://api.envoisms.ma/v1/messages?limit=50&offset=0" \
-H "Authorization: Bearer env_live_xxx"{
"data": [
{
"id": "msg_8f2d...",
"to": "+212612345678",
"channel": "whatsapp",
"body": "Votre code de validation est 849204",
"sender_id": "MaBanque",
"status": "delivered",
"cost_mad": 0.13,
"created_at": "2026-05-15T10:30:00Z"
}
],
"limit": 50,
"offset": 0,
"total": 1
}/v1/messages/:idGet message status
Retrieves the current status and delivery logs of a specific message.
curl -X GET "https://api.envoisms.ma/v1/messages/:id" \
-H "Authorization: Bearer env_live_xxx"{
"id": "msg_8f2d...",
"account_id": "acc_3f1a...",
"api_key_id": "key_e84c...",
"campaign_id": null,
"to": "+212612345678",
"channel": "whatsapp",
"body": "Votre code de validation est 849204",
"sender_id": "MaBanque",
"unicode": 0,
"segments": 1,
"status": "delivered",
"cost_eur": 0.0118,
"cost_mad": 0.13,
"metadata": "{\"purpose\": \"otp\"}",
"created_at": "2026-05-15T10:30:00Z"
}/v1/templatesLister les templates
Récupère tous les templates WhatsApp et SMS approuvés de votre compte.
curl -X GET "https://api.envoisms.ma/v1/templates" \
-H "Authorization: Bearer env_live_xxx"{
"data": [
{
"id": "tpl_1234...",
"name": "otp_verification",
"channel": "whatsapp",
"body": "Votre code de validation est {{1}}",
"status": "approved",
"category": "otp",
"created_at": "2026-05-15T10:30:00Z"
}
],
"total": 1
}/v1/templatesCréer un template
Soumet un nouveau template pour approbation par les opérateurs ou WhatsApp.
curl -X POST "https://api.envoisms.ma/v1/templates" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"id": "tpl_1234...",
"name": "otp_verification",
"status": "pending"
}/v1/sender-idsLister les Sender IDs
Récupère la liste de vos Sender IDs avec leur statut d'approbation.
curl -X GET "https://api.envoisms.ma/v1/sender-ids" \
-H "Authorization: Bearer env_live_xxx"{
"data": [
{
"id": "sid_9a8b...",
"sender_id": "MABANQUE",
"status": "approved",
"requested_at": "2026-05-10T09:00:00Z"
}
]
}/v1/sender-idsDemander un Sender ID
Soumet un nouveau Sender ID pour approbation (requis pour le Maroc).
curl -X POST "https://api.envoisms.ma/v1/sender-ids" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"id": "sid_9a8b...",
"sender_id": "MABANQUE",
"status": "pending"
}/v1/verify/sendSend an OTP code
Sends a one-time verification code. Two modes, your choice: "whatsapp" — managed verification, the simplest and cheapest (EnvoiSMS generates the code, delivers it on WhatsApp from a verified sender, then falls back to SMS automatically if unconfirmed within 60s; nothing to store on your side — code_length, expiry and template are ignored in this mode: the code is always 6 digits, valid 5 minutes) — or "sms" — you keep full control of the code, template and sender. Both modes are validated with the same /v1/verify/check call. Want your own brand on the managed SMS fallback? Available on request: [email protected].
curl -X POST "https://api.envoisms.ma/v1/verify/send" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"to": "+212612345678",
"brand": "MonApp",
"channel": "whatsapp",
"code_length": 6,
"expiry": 600
}'{
"session_id": "vrf_7e2a...",
"to": "+212612345678",
"channel": "whatsapp",
"expires_at": "2026-05-15T10:35:00Z",
"status": "sent",
"cost": { "eur": 0.025, "mad": 0.275 }
}/v1/verify/checkVerify an OTP
Validates the code entered by the user for a given verification session.
curl -X POST "https://api.envoisms.ma/v1/verify/check" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"session_id": "vrf_7e2a...",
"code": "849204"
}'{
"session_id": "vrf_7e2a...",
"verified": true,
"verified_at": "2026-05-15T10:35:12Z"
}/v1/verify/:idOTP session status
Retrieves the status (validated or expired) of a specific verification session.
curl -X GET "https://api.envoisms.ma/v1/verify/:id" \
-H "Authorization: Bearer env_live_xxx"{
"id": "vrf_7e2a...",
"to": "+212612345678",
"channel": "whatsapp",
"expires_at": "2026-05-15T10:40:00Z",
"verified_at": "2026-05-15T10:35:12Z",
"created_at": "2026-05-15T10:30:00Z"
}/v1/verify/lookupNumber Lookup
Validates the format, carrier network, line type, and geographic location of a phone number.
curl -X POST "https://api.envoisms.ma/v1/verify/lookup" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"number": "+212612345678",
"country_code": "MA"
}'{
"valid": true,
"number": "212612345678",
"local_format": "0612345678",
"international_format": "+212612345678",
"country_prefix": "212",
"country_code": "MA",
"country_name": "Morocco",
"location": "Casablanca",
"carrier": "Maroc Telecom (IAM)",
"line_type": "mobile"
}/v1/contactsList contacts
Retrieves contacts with optional keyword search or contact list filtering.
curl -X GET "https://api.envoisms.ma/v1/contacts?limit=50&offset=0" \
-H "Authorization: Bearer env_live_xxx"{
"data": [
{
"id": "ctc_a2b3...",
"phone": "+212612345678",
"name": "Karim Bennani",
"email": "[email protected]",
"custom1": "VIP",
"custom2": null,
"custom3": null,
"created_at": "2026-05-10T14:20:00Z"
}
],
"limit": 100,
"offset": 0,
"total": 1
}/v1/contactsList contacts
Retrieves contacts with optional keyword search or contact list filtering.
curl -X POST "https://api.envoisms.ma/v1/contacts" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"phone": "+212612345678",
"name": "Karim Bennani",
"email": "[email protected]",
"list_id": "lst_f84b..."
}'{
"id": "ctc_a2b3...",
"phone": "+212612345678",
"name": "Karim Bennani",
"email": "[email protected]",
"custom1": "VIP",
"custom2": null,
"custom3": null,
"created_at": "2026-05-10T14:20:00Z"
}/v1/contacts/importImporter des contacts
Importe massivement jusqu'Ă 5 000 contacts en un seul appel.
curl -X POST "https://api.envoisms.ma/v1/contacts/import" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{
"phone": "+212611111111",
"name": "Karim"
},
{
"phone": "+212622222222",
"name": "Youssef"
}
],
"list_id": "lst_f84b..."
}'{
"imported": 150,
"skipped": 3
}/v1/contacts/:idSupprimer un contact
Supprime définitivement un contact à partir de son identifiant unique.
curl -X DELETE "https://api.envoisms.ma/v1/contacts/:id" \
-H "Authorization: Bearer env_live_xxx"{
"deleted": true,
"id": "ctc_a2b3..."
}/v1/contacts/listsLister les listes
Récupère toutes les listes de contacts créées pour les campagnes de diffusion.
curl -X GET "https://api.envoisms.ma/v1/contacts/lists" \
-H "Authorization: Bearer env_live_xxx"{
"data": [
{
"id": "lst_f84b...",
"name": "Newsletter Clients",
"description": "Clients inscrits Ă notre lettre d'information",
"count": 1420,
"created_at": "2026-04-15T09:00:00Z"
}
]
}/v1/contacts/listsCréer une liste
Crée un nouveau groupe (liste de contacts) vide destiné aux campagnes.
curl -X POST "https://api.envoisms.ma/v1/contacts/lists" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Newsletter Clients",
"description": "Clients inscrits"
}'{
"id": "lst_f84b...",
"name": "Newsletter Clients",
"description": "Clients inscrits",
"count": 0
}/v1/optoutsLister les désinscriptions
Récupère la liste des numéros qui se sont désinscrits (STOP) de vos communications.
curl -X GET "https://api.envoisms.ma/v1/optouts" \
-H "Authorization: Bearer env_live_xxx"{
"data": [
{
"phone": "+212611111111",
"opted_out_at": "2026-06-01T12:00:00Z"
}
],
"total": 1
}/v1/optoutsAjouter une désinscription
Ajoute manuellement un numéro à votre liste de désinscription (blacklist globale).
curl -X POST "https://api.envoisms.ma/v1/optouts" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"success": true,
"phone": "+212611111111",
"opted_out_at": "2026-06-01T12:00:00Z"
}/v1/optouts/:phoneRetirer une désinscription
Retire un numéro de la liste de désinscription.
curl -X DELETE "https://api.envoisms.ma/v1/optouts/:phone" \
-H "Authorization: Bearer env_live_xxx"{
"deleted": true,
"phone": "+212611111111"
}/v1/campaignsLister les campagnes
Récupère toutes vos campagnes d'envoi programmé ou de diffusion en cours.
curl -X GET "https://api.envoisms.ma/v1/campaigns" \
-H "Authorization: Bearer env_live_xxx"{
"data": [
{
"id": "cmp_8d2a...",
"name": "Soldes d'été 2026",
"channel": "sms",
"list_id": "lst_f84b...",
"template_id": null,
"body": "Bonjour {{name}}, profitez de -50% sur toute la collection avec le code ETE50 !",
"sender_id": "SOLDES",
"status": "draft",
"scheduled_at": null,
"created_at": "2026-06-01T12:00:00Z"
}
]
}/v1/campaignsCréer une campagne
Enregistre une nouvelle campagne en tant que brouillon ou la planifie à une date précise.
curl -X POST "https://api.envoisms.ma/v1/campaigns" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Soldes d'été 2026",
"body": "Bonjour {{name}}, profitez de -50% avec le code ETE50 !",
"channel": "sms",
"list_id": "lst_f84b...",
"sender_id": "SOLDES"
}'{
"id": "cmp_8d2a...",
"status": "draft"
}/v1/campaigns/:idDétails d'une campagne
Récupère les détails, la planification et le statut d'exécution d'une campagne.
curl -X GET "https://api.envoisms.ma/v1/campaigns/:id" \
-H "Authorization: Bearer env_live_xxx"{
"id": "cmp_8d2a...",
"name": "Soldes d'été 2026",
"channel": "sms",
"list_id": "lst_f84b...",
"body": "Bonjour {{name}}, profitez de -50%...",
"sender_id": "SOLDES",
"status": "running",
"total_count": 1420,
"sent_count": 840,
"started_at": "2026-06-15T10:00:00Z",
"created_at": "2026-06-01T12:00:00Z"
}/v1/campaigns/:id/sendLancer une campagne
Démarre immédiatement la diffusion d'une campagne de type brouillon vers tous les contacts associés.
curl -X POST "https://api.envoisms.ma/v1/campaigns/:id/send" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"id": "cmp_8d2a...",
"queued": 1420,
"total": 1420
}/v1/webhooksLister les webhooks
Récupère la liste de tous vos endpoints de webhooks enregistrés.
curl -X GET "https://api.envoisms.ma/v1/webhooks" \
-H "Authorization: Bearer env_live_xxx"{
"data": [
{
"id": "whk_5f2b...",
"url": "https://mon-serveur.ma/api/envoisms-receiver",
"events": [
"message.delivered",
"message.failed"
],
"active": true,
"last_triggered_at": "2026-06-15T09:30:15Z",
"last_status": 200,
"created_at": "2026-05-01T10:00:00Z"
}
]
}/v1/webhooksCréer un Webhook
Enregistre une URL HTTPS de callback pour recevoir les notifications d'événements.
curl -X POST "https://api.envoisms.ma/v1/webhooks" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://mon-serveur.ma/api/envoisms-receiver",
"events": [
"message.delivered",
"message.failed"
]
}'{
"id": "whk_5f2b...",
"url": "https://mon-serveur.ma/api/envoisms-receiver",
"events": [
"message.delivered",
"message.failed"
],
"secret": "whsec_2f8a9e7d...",
"active": true
}/v1/webhooks/:idModifier un Webhook
Met à jour la configuration d'un webhook (URL, événements surveillés ou état actif).
curl -X PATCH "https://api.envoisms.ma/v1/webhooks/:id" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://mon-serveur.ma/api/envoisms-receiver-updated",
"active": false
}'{
"updated": true,
"id": "whk_5f2b..."
}/v1/webhooks/:idSupprimer un Webhook
Désactive et supprime logiquement un endpoint de webhook.
curl -X DELETE "https://api.envoisms.ma/v1/webhooks/:id" \
-H "Authorization: Bearer env_live_xxx"{
"deleted": true,
"id": "whk_5f2b..."
}/v1/webhooks/:id/testTester un Webhook
Déclenche un événement de test ("message.test") vers l'URL configurée du webhook.
curl -X POST "https://api.envoisms.ma/v1/webhooks/:id/test" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"queued": true,
"id": "whk_5f2b..."
}/v1/api-keysLister les clés API
Récupère la liste de toutes vos clés d'API actives ou révoquées.
curl -X GET "https://api.envoisms.ma/v1/api-keys" \
-H "Authorization: Bearer env_live_xxx"{
"data": [
{
"id": "key_e84c...",
"name": "Production Server",
"key_prefix": "env_live",
"ip_whitelist": [
"196.200.1.4"
],
"rate_limit": 100,
"permissions": [
"send",
"verify",
"status"
],
"active": true,
"last_used_at": "2026-06-15T10:30:00Z",
"created_at": "2026-05-01T08:00:00Z"
}
]
}/v1/api-keysCréer une clé API
Génère un nouveau jeton d'API sécurisé avec des permissions et restrictions spécifiques.
curl -X POST "https://api.envoisms.ma/v1/api-keys" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Server",
"permissions": [
"send",
"verify",
"status"
],
"ip_whitelist": [
"196.200.1.4"
],
"rate_limit": 100
}'{
"id": "key_e84c...",
"name": "Production Server",
"key_prefix": "env_live",
"api_key": "env_live_a8f7d6c5b4a3...",
"permissions": [
"send",
"verify",
"status"
],
"rate_limit": 100,
"warning": "The full API key is shown once. Store it securely."
}/v1/api-keys/:idModifier une clé API
Met à jour les permissions, restrictions IP ou l'état d'activation d'une clé API.
curl -X PATCH "https://api.envoisms.ma/v1/api-keys/:id" \
-H "Authorization: Bearer env_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Backup Server",
"active": true
}'{
"updated": true,
"id": "key_e84c..."
}/v1/api-keys/:idRévoquer une clé API
Révoque définitivement une clé API pour l'empêcher d'authentifier les requêtes.
curl -X DELETE "https://api.envoisms.ma/v1/api-keys/:id" \
-H "Authorization: Bearer env_live_xxx"{
"revoked": true,
"id": "key_e84c..."
}/v1/billing/balanceConsulter le solde
Consulte le solde disponible en Dirhams Marocains (MAD) ainsi que la devise et le forfait actif.
curl -X GET "https://api.envoisms.ma/v1/billing/balance" \
-H "Authorization: Bearer env_live_xxx"{
"balance_mad": 1492.5,
"currency": "MAD",
"plan": "croissance"
}/v1/analyticsStatistiques d'usage
Récupère des métriques clés sur vos envois (volumes totaux, taux de délivrabilité, et coûts facturés).
curl -X GET "https://api.envoisms.ma/v1/analytics" \
-H "Authorization: Bearer env_live_xxx"{
"summary": {
"total": 12840,
"delivered": 12570,
"delivery_rate": 97.9,
"cost_mad": 2663.1
}
}Webhooks Guide
Signed and secure delivery callbacks.
EnvoiSMS.ma posts JSON events to your server's HTTPS URL with an X-EnvoiSMS.ma-Signature header to authenticate the sender.
message.deliveredTriggered when the operator confirms successful delivery to the recipient's device.
message.failedTriggered when delivery fails (invalid number, expired, rejected by carrier).
message.expiredTriggered when the message expires in the operator queue.
message.inboundTriggered when a recipient sends a reply text message back to you (inbound SMS).
contact.optoutTriggered when a recipient unsubscribes using a STOP keyword or similar opt-out trigger.
verify.successTriggered immediately when an OTP session is successfully validated by a correct code.
import crypto from 'node:crypto';
export function verifySignature(body: string, sig: string, secret: string) {
const hmac = crypto.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from('sha256=' + hmac));
} OpenAPI Spec Errors
API error response structure.
All API errors return an appropriate HTTP code (4xx or 5xx) along with a predictable JSON envelope containing the error code and description.
{
"error": {
"code": "INVALID_PHONE",
"message": "to must be E.164 format, for example +212612345678",
"docs": "https://envoisms.ma/docs#errors"
}
}UNAUTHORIZEDThe API key is missing or invalid. Verify your Bearer token in the headers.
INSUFFICIENT_BALANCESolde insuffisant pour effectuer l'envoi.
INVALID_PHONEThe recipient number format is invalid. Use E.164 standard.
RATE_LIMITEDLimite de requêtes par minute dépassée.
CHANNEL_NOT_ALLOWEDLe canal demandé (ex: WhatsApp) n'est pas activé sur votre compte.
SENDER_ID_TOO_LONGLe Sender ID dépasse la limite de 11 caractères.
SENDER_ID_INVALIDLe Sender ID contient des caractères non autorisés.
SENDER_ID_NOT_APPROVEDLe Sender ID n'a pas encore été approuvé par les opérateurs.
SENDER_ID_PENDINGLe Sender ID est en cours d'approbation.
SENDER_ID_REJECTEDLe Sender ID a été rejeté par les opérateurs.
MISSING_FIELDUn champ obligatoire est manquant dans la requĂŞte.
CASCADE_TIMEOUTLe premier canal a expiré, basculement vers le canal secondaire (cascade).
UPSTREAM_ERRORErreur de livraison au niveau de l'opérateur ou de la passerelle.
OPTED_OUTLe numéro a refusé vos communications (STOP). Envoi interdit.
Limits
Constraints and quotas in the production environment.
100 requests / minute (scalable upon request).
1600 characters maximum per message.
Up to 10,000 messages per API call.
90 days for detailed reports.