Documentación completa (Scalar)
openapi.json openapi.yaml Postman Collection
🧪 Modo Sandbox (Prueba sin coste)Clave API activa:
env_test_demo_2026
Las peticiones de la consola interactiva y Swagger UI se ejecutan en directo en https://api.envoisms.ma.

Start here

Todo para comenzar antes de la primera solicitud.

EnvoiSMS.ma es una infraestructura de mensajería programable diseñada para Marruecos. Nuestras rutas locales hacia IAM, Inwi y Orange, con conmutación automática entre rutas, mantienen una latencia baja.

Scalar • Business Grade
Documentación Interactiva Completa (Scalar)

Pruebe endpoints en vivo, explore esquemas OpenAPI 3.1 y genere código en cURL, PHP, Node.js, Python y Go al instante.

Abrir documentación completa Scalar
URL basehttps://api.envoisms.ma
Versión API/v1 (Estable)
Formato de datosapplication/json; charset=utf-8
AutenticaciónAuthorization: Bearer smr_xxx
Límite por defecto60 a 1 200 peticiones / minuto por clave según el plan
Formato de númeroE.164 (ej: +212612345678)
Canales activosSMS a operadores marroquíes (rutas locales), WhatsApp Business API (AtlasAI™)
Motor de IA propietarioAtlasAI™ — el motor detrás de Ghita, su asistente de WhatsApp (Conversational Engine, Voice, Vision — integrado WABA)
LocalizaciónAlojada en Marruecos — Cloud Edge EnvoiSMS 🇲🇦
01

Genere su clave API "smr_..." desde su Consola EnvoiSMS.ma.

02

Use la autenticación Bearer en sus cabeceras HTTP para cada petición.

03

Pruebe su integración con claves Sandbox (env_test_...) en la URL live para validar sus llamadas sin consumir crédito real.

04

Integre WhatsApp Business API para dividir sus costes de OTP por 10.

05

Configure un Webhook firmado para recibir los acuses de entrega en tiempo real.

06

Siga su consumo y sus facturas en MAD directamente en su Dashboard.

Enviar su primer mensaje
// 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

Autenticación

Claves Bearer, headers y restricciones de seguridad.

Cada endpoint /v1 requiere una clave API válida transmitida en el header Authorization como token Bearer. Las claves de prueba y producción se pueden generar o revocar desde su consola.

Autorización

Authorization: Bearer smr_xxx

Cabeceras de límite de tasa

X-RateLimit-Limit y X-RateLimit-Remaining se devuelven en cada llamada.

Listas de IP permitidas

Las peticiones de direcciones IP no configuradas devuelven un estado 401.

CORS Soportado

JSON, Authorization, X-EnvoiSMS.ma-Signature y X-EnvoiSMS.ma-Version están soportados.

Ejemplo de cabeceras HTTP
POST /v1/messages HTTP/1.1
Host: api.envoisms.ma
Authorization: Bearer smr_xxxxxxxx
Content-Type: application/json
Accept: application/json

Open Source

SDKs Oficiales y Librerías

Integre la API de EnvoiSMS en su aplicación con nuestras librerías de código abierto oficiales.

NPM PackageTypeScript & JavaScript
Node.js / TypeScript
npm install envoisms
GitHub Repository
Composer PackagePHP 8.0+
PHP Client
composer require envoisms/envoisms-php
GitHub Repository
PyPI PackagePython 3.8+
Python Client
pip install envoisms
GitHub Repository
Notification ChannelLaravel 9 - 11
Laravel OTP Package
composer require envoisms/laravel-otp
GitHub Repository
Go ModuleGo 1.20+
Go Client
go get github.com/envoisms/envoisms-go
GitHub Repository
Model Context ProtocolClaude, Cursor, AI Agents
MCP Server
npx -y @envoisms/mcp-server
GitHub Repository
DocsMessages/messages
POSThttps://api.envoisms.ma/v1/messages
Bearer Auth

Enviar un mensaje

Envía un SMS o un mensaje de WhatsApp Business a un destinatario único.

Cuerpo de la petición
CampoTipoEstadoDescripción
tostringRequeridoNúmero de teléfono en formato E.164 (+212...).
messagestringRequeridoContenido de texto (máx. 1600 caracteres). También se acepta con el nombre "body".
fromstringOpcionalSender ID personalizado (ej: NOMBRE_MARCA). Por defecto "EnvoiSMS".
channelstringOpcional"sms" o "whatsapp". Por defecto "sms". "whatsapp" envía desde su propio número de WhatsApp Business conectado (si no, 403 WHATSAPP_NOT_CONNECTED). Para enviar un texto ordinario a un cliente que usa WhatsApp basta "sms": sin conexión, sin plantilla, sin ventana de 24 h. Salvo que sea una plantilla, un mensaje de WhatsApp solo se acepta si el contacto le escribió en las últimas 24 horas — si no, 400 OUT_OF_24H_WINDOW, sin ningún cargo (con cascade, se omite WhatsApp y se usa el canal siguiente).
cascadebooleanOpcionalSi está activado, intenta WhatsApp y pasa a SMS: de inmediato si WhatsApp rechaza el mensaje o informa de su fallo (no registrado en WhatsApp, ventana de 24 h cerrada…), o si no llega ningún acuse de entrega dentro de cascade_timeout (120 s por defecto). Solo se factura el envío que realmente salió: un WhatsApp rechazado o fallido no se factura y usted paga solo el SMS. Un WhatsApp que sigue sin acuse de entrega sí salió (aún puede entregarse cuando el teléfono se reconecte): se factura junto con su SMS de respaldo y se reembolsa si WhatsApp informa después de su fallo. Consejo: dé a su plantilla de WhatsApp un tiempo de vida (TTL) no mayor que cascade_timeout, para que un teléfono que vuelve a conectarse no reciba ambos.
cascade_timeoutintegerOpcionalCon cascade: segundos de espera de un acuse de entrega antes del siguiente canal, de 30 a 43200 (12 h). Por defecto: 120. Más corto = respaldo más rápido pero más envíos dobles facturados; más largo = menos duplicados.
metadataobjectOpcionalPares clave-valor personalizados almacenados con el mensaje y transmitidos en los webhooks (no se devuelven en los endpoints GET /v1/messages). Una clave tiene significado para la plataforma: purpose: "otp" señala un código de un solo uso que usted genera y activa la reentrega automática (ver notas).
buttonsarrayOpcionalArray de objetos de botones interactivos de WhatsApp (máx. 3, tipo "copy" | "url" | "call").
interactiveobjectOpcionalObjeto de mensaje interactivo enriquecido de WhatsApp: menús de lista desplegable ("list"), botones de respuesta rápida ("button"), formularios nativos ("flow"), botón de enlace ("cta_url": action {"name":"cta_url","parameters":{"display_text","url"}}) o solicitud de ubicación ("location_request_message").
templateobjectOpcional(WhatsApp) Plantilla aprobada de su cuenta: {"name", "language"}, valores en metadata.variables. Único tipo de mensaje permitido fuera de la ventana de 24 horas; tarificado según la categoría de la plantilla.
image | video | audio | document | stickerobjectOpcional(WhatsApp) Multimedia por "id" (medio ya subido) O por "link" (URL https), nunca ambos. "caption" en imagen, vídeo y documento; "filename" en documento.
reactionobjectOpcional(WhatsApp) {"message_id": wamid, "emoji": "👍"} — reacciona a un mensaje de la conversación; un emoji vacío retira la reacción. No se factura.
contactsarrayOpcional(WhatsApp) Fichas de contacto (máx. 20): name.formatted_name obligatorio; phones, emails, urls, addresses, org, birthday opcionales.
locationobjectOpcional(WhatsApp) Ubicación: {"latitude", "longitude", "name"?, "address"?}.
contextobjectOpcional(WhatsApp) {"message_id": wamid} — responde citando un mensaje anterior. Válido en todos los tipos salvo reaction.
phone_number_idstringOpcional(WhatsApp) Número conectado que envía; por defecto su número predeterminado.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • ¿Envía códigos OTP? Dos enfoques. /v1/verify/send gestiona todo el ciclo (generación, entrega, validación, expiración) y sigue siendo la vía recomendada. Si genera sus propios códigos y los envía aquí, añada metadata: {"purpose": "otp"}: ante un fallo de entrega confirmado por la red en un número marroquí mientras el código sigue vigente (menos de 10 minutos), la plataforma lo reenvía automáticamente una vez por una ruta SMS alternativa — mismo identificador de mensaje, sin coste adicional. Sin esta etiqueta, el mensaje se trata como un SMS ordinario.
  • WhatsApp: salvo que sea una plantilla, un mensaje (texto, multimedia, reacción, contactos, ubicación, interactivo) solo se envía a un contacto que escribió a su número en las últimas 24 horas; si no, la petición se rechaza con 400 OUT_OF_24H_WINDOW antes de cualquier cargo. Con una clave sandbox el envío sigue simulándose y la respuesta indica el rechazo en "warnings". Para mostrar «escribiendo…» mientras prepara la respuesta, vea POST /v1/messages/typing.
  • Los saltos de línea (\n) son totalmente compatibles en todos los canales y se muestran correctamente en el destinatario.
  • El formato de texto enriquecido (negrita, cursiva, etc.) no está soportado en el canal SMS (solo texto plano).
  • El canal WhatsApp admite el formato de texto con la sintaxis estándar (*negrita*, _cursiva_, ~tachado~).
POSThttps://api.envoisms.ma/v1/messages
curl -X POST "https://api.envoisms.ma/v1/messages" \
  -H "Authorization: Bearer smr_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.03,
    "mad": 0.33
  },
  "segments": 1,
  "created_at": "2026-05-15T10:30:00Z"
}
DocsMessages/messages/bulk
POSThttps://api.envoisms.ma/v1/messages/bulk
Bearer Auth

Envío masivo (Bulk)

Envía hasta 10 000 mensajes en una sola llamada API con destinatarios o contenidos únicos.

Cuerpo de la petición
CampoTipoEstadoDescripción
messagesarrayRequeridoArray de objetos que contienen "to", "message" (o "body") y un objeto opcional "metadata".
fromstringOpcionalSender ID global para todo el lote.
channelstringOpcionalCanal global ("sms" o "whatsapp"). Por defecto "sms".
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • Los saltos de línea (\n) son totalmente compatibles en los cuerpos de los mensajes masivos.
  • El formato de texto enriquecido (negrita, cursiva, etc.) no está soportado en el canal SMS (solo texto plano).
  • El canal WhatsApp admite el formato de texto con la sintaxis estándar (*negrita*, _cursiva_, ~tachado~).
POSThttps://api.envoisms.ma/v1/messages/bulk
curl -X POST "https://api.envoisms.ma/v1/messages/bulk" \
  -H "Authorization: Bearer smr_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"
    }
  ]
}
DocsMessages/messages/typing
POSThttps://api.envoisms.ma/v1/messages/typing
Bearer Auth

Indicador de escritura de WhatsApp

Marca como leído un mensaje de WhatsApp recibido y muestra «escribiendo…» a su autor mientras prepara la respuesta (desaparece al responder o tras unos 25 s). No es un mensaje: no se almacena ni se factura nada.

Cuerpo de la petición
CampoTipoEstadoDescripción
message_idstringRequeridoIdentificador de WhatsApp (wamid) del mensaje recibido al que responde.
typing_indicatorbooleanOpcionalfalse envía solo la confirmación de lectura. Por defecto: true.
phone_number_idstringOpcionalNúmero conectado que recibió el mensaje; por defecto su número predeterminado.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/messages/typing
curl -X POST "https://api.envoisms.ma/v1/messages/typing" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "status": "ok",
  "message_id": "wamid.HBgLMjEyNjEyMzQ1Njc4FQIAEhgg",
  "typing_indicator": true
}
DocsMessages/messages
GEThttps://api.envoisms.ma/v1/messages
Bearer Auth

Listar mensajes

Recupera una lista paginada de todos los mensajes enviados desde la cuenta.

Parámetros Query
ParámetroTipoEstadoDescripción
limitintegerOpcionalNúmero de resultados a devolver (1-200, por defecto: 50).
offsetintegerOpcionalNúmero de resultados a omitir para la paginación (por defecto: 0).
statusstringOpcionalFiltrar por estado (queued, sent, delivered, failed, undeliverable, unconfirmed).
channelstringOpcionalFiltrar por canal (sms, whatsapp).
from_datestringOpcionalFiltrar por fecha de inicio (formato ISO 8601).
to_datestringOpcionalFiltrar por fecha de fin (formato ISO 8601).
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/messages
curl -X GET "https://api.envoisms.ma/v1/messages?limit=50&offset=0" \
  -H "Authorization: Bearer smr_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
}
DocsMessages/messages/:id
GEThttps://api.envoisms.ma/v1/messages/:id
Bearer Auth

Estado del mensaje

Consulta los detalles y el estado de entrega en tiempo real de un mensaje específico.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • Estados posibles: queued, sent, delivered, failed, undeliverable, unconfirmed. "unconfirmed" significa que el operador nunca confirmó ni negó la entrega — un acuse que llegue más tarde todavía puede sustituirlo.
  • El campo metadata proporcionado en el envío no se devuelve aquí; se transmite en los webhooks.
GEThttps://api.envoisms.ma/v1/messages/:id
curl -X GET "https://api.envoisms.ma/v1/messages/:id" \
  -H "Authorization: Bearer smr_xxx"
{
  "id": "msg_8f2d...",
  "campaign_id": null,
  "to": "+212612345678",
  "channel": "sms",
  "body": "Votre code de validation est 849204",
  "sender_id": "MaBanque",
  "unicode": 0,
  "segments": 1,
  "status": "delivered",
  "error_code": null,
  "error_message": null,
  "cost_eur": 0.0436,
  "cost_mad": 0.48,
  "scheduled_at": null,
  "sent_at": "2026-05-15T10:30:02Z",
  "delivered_at": "2026-05-15T10:30:05Z",
  "failed_at": null,
  "operator": "Maroc Telecom",
  "sandbox": 0,
  "created_at": "2026-05-15T10:30:00Z"
}
DocsMessages/templates
GEThttps://api.envoisms.ma/v1/templates
Bearer Auth

Listar plantillas

Recupera todas las plantillas de WhatsApp y SMS aprobadas de su cuenta.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/templates
curl -X GET "https://api.envoisms.ma/v1/templates" \
  -H "Authorization: Bearer smr_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
}
DocsMessages/templates
POSThttps://api.envoisms.ma/v1/templates
Bearer Auth

Crear una plantilla

Envía una nueva plantilla para su aprobación por los operadores o WhatsApp.

Cuerpo de la petición
CampoTipoEstadoDescripción
namestringRequeridoNombre interno de la plantilla.
channelstringRequerido"sms" o "whatsapp".
bodystringRequeridoContenido del mensaje con variables (ej: {{1}}).
categorystringOpcionalCategoría de la plantilla (ej: "otp", "marketing").
languagestringOpcionalWhatsApp: código de idioma de Meta (ej: "fr", "ar", "en_US"). Por defecto "fr".
sample_valuesobject | string[]OpcionalWhatsApp: un valor de ejemplo por variable, obligatorio para la revisión de Meta (ej: {"1": "Amine"} o ["Amine"]).
header_example_urlstringOpcionalWhatsApp, encabezado de imagen/vídeo/documento: enlace https público a un archivo de ejemplo, enviado a Meta para la revisión.
add_security_recommendationbooleanOpcionalWhatsApp, categoría "authentication": añade el aviso de seguridad de Meta. El texto del cuerpo lo fija Meta; también se acepta code_expiration_minutes (1-90).
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • Una plantilla de WhatsApp pasa primero la revisión de EnvoiSMS (pending_admin) y luego se envía a Meta en su propia cuenta de WhatsApp Business (pending_meta). Solo Meta la aprueba (approved); su categoría final es la que asigna Meta.
POSThttps://api.envoisms.ma/v1/templates
curl -X POST "https://api.envoisms.ma/v1/templates" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "id": "tpl_1234...",
  "name": "order_confirmation",
  "channel": "whatsapp",
  "language": "fr",
  "status": "pending_admin"
}
DocsMessages/templates/sync
POSThttps://api.envoisms.ma/v1/templates/sync
Bearer Auth

Sincronizar plantillas desde Meta

Importa todas las plantillas de su cuenta de WhatsApp Business (estado, categoría, calidad). Una plantilla que Meta ya no tiene pasa a deleted_on_meta.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/templates/sync
curl -X POST "https://api.envoisms.ma/v1/templates/sync" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "ok": true,
  "wabas": ["1234567890"],
  "fetched": 12,
  "updated": 9,
  "inserted": 3,
  "marked_deleted": 1,
  "complete": true,
  "errors": []
}
DocsMessages/sender-ids
GEThttps://api.envoisms.ma/v1/sender-ids
Bearer Auth

Listar Sender IDs

Recupera la lista de sus Sender IDs con su estado de aprobación.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/sender-ids
curl -X GET "https://api.envoisms.ma/v1/sender-ids" \
  -H "Authorization: Bearer smr_xxx"
{
  "data": [
    {
      "id": "sid_9a8b...",
      "sender_id": "MABANQUE",
      "status": "approved",
      "requested_at": "2026-05-10T09:00:00Z"
    }
  ]
}
DocsMessages/sender-ids
POSThttps://api.envoisms.ma/v1/sender-ids
Bearer Auth

Solicitar un Sender ID

Envía un nuevo Sender ID para su aprobación (requerido para Marruecos).

Cuerpo de la petición
CampoTipoEstadoDescripción
sender_idstringRequeridoEl nombre de remitente deseado (máx. 11 caracteres).
rc_urlstringOpcionalEnlace al Registro Mercantil (Registre de Commerce) para verificación.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/sender-ids
curl -X POST "https://api.envoisms.ma/v1/sender-ids" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "id": "sid_9a8b...",
  "sender_id": "MABANQUE",
  "status": "pending"
}
DocsWhatsApp/whatsapp/profile
GEThttps://api.envoisms.ma/v1/whatsapp/profile
Bearer Auth

Perfil de WhatsApp Business

Consulta la información pública de su perfil verificado de WhatsApp Business (nombre, foto, descripción, dirección, sitio web).

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/whatsapp/profile
curl -X GET "https://api.envoisms.ma/v1/whatsapp/profile" \
  -H "Authorization: Bearer smr_xxx"
{
  "about": "Service client officiel EnvoiSMS.ma",
  "address": "Casablanca, Maroc",
  "description": "Infrastructure de messagerie programmable pour les entreprises au Maroc.",
  "email": "[email protected]",
  "websites": [
    "https://votremarque.ma"
  ],
  "profile_picture_url": "https://pps.whatsapp.net/v/..."
}
DocsWhatsApp/whatsapp/profile
POSThttps://api.envoisms.ma/v1/whatsapp/profile
Bearer Auth

Actualizar perfil de WhatsApp

Actualiza la información visible para sus clientes en su perfil oficial de WhatsApp Business.

Cuerpo de la petición
CampoTipoEstadoDescripción
aboutstringOpcionalEstado corto de texto (máx. 139 caracteres).
descriptionstringOpcionalDescripción detallada de su empresa (máx. 512 caracteres).
addressstringOpcionalDirección física de su oficina o tienda.
emailstringOpcionalDirección de correo electrónico de contacto con el cliente.
websitesarrayOpcionalArray con hasta 2 URLs de su sitio web.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/whatsapp/profile
curl -X POST "https://api.envoisms.ma/v1/whatsapp/profile" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "success": true,
  "updated_at": "2026-08-30T10:00:00Z"
}
DocsVerify/verify/send
POSThttps://api.envoisms.ma/v1/verify/send
Bearer Auth

Generar un OTP

Envía un código de verificación de un solo uso. Dos modos a elegir: "whatsapp" — verificación gestionada, la más simple (EnvoiSMS genera el código y lo entrega por WhatsApp desde un remitente verificado; si Meta rechaza el envío por WhatsApp, el código sale por SMS; con una aplicación Verify configurada con auto_cascade, el SMS también sale al expirar el plazo del canal, 30 s por defecto; ningún código que almacenar de su lado) — o "sms" — usted mantiene el control total del código, la plantilla y el remitente. En ambos casos, la validación se hace con la misma llamada /v1/verify/check. ¿Quiere su propia marca en el respaldo SMS de la verificación gestionada? Disponible bajo petición: [email protected].

Cuerpo de la petición
CampoTipoEstadoDescripción
tostringRequeridoDestinatario en formato E.164.
channelstringOpcional"whatsapp" (verificación gestionada: WhatsApp, respaldo SMS si Meta rechaza el envío o, con auto_cascade, tras el plazo del canal; código válido 10 min, 3 intentos, facturada por verificación a la tarifa WhatsApp OTP) o "sms" (código generado para usted, enviado con su marca). Por defecto: "sms".
app_idstringOpcionalID de la aplicación Verify configurada en el panel de control (ej: vra_...). Aplica automáticamente los parámetros de código, tiempos y la cascada de canales.
brandstringOpcional(Canal sms) Nombre de marca mostrado (ej: MonApp, máx. 32 car.). Por defecto "EnvoiSMS".
code_lengthintegerOpcional(Canal sms) Longitud del código generado (de 4 a 8 dígitos, por defecto: 6).
expiryintegerOpcionalDuración de validez del código en segundos (de 60 a 1800, por defecto: 600). En el canal whatsapp se limita a 600 (límite de la plantilla de autenticación).
cascadearrayOpcional(Canal sms) Lista ordenada de canales para el cambio automático en cascada (ej: ["whatsapp", "sms"]).
templatestringOpcional(Canal sms) Texto personalizado con las variables {{code}} y {{brand}}. En modo whatsapp, el mensaje localizado (fr/en/es) se gestiona por usted.
otp_button_textstringOpcional(Canal whatsapp) Etiqueta personalizada para el botón de copia automática de WhatsApp (máx. 25 car.).
web_otp_domainstringOpcional(Opcional, canal sms) Dominio web de destino para autocompletado W3C WebOTP (ej: "https://misitio.ma"). Agrega @dominio #code al SMS.
app_hashstringOpcional(Opcional, canal sms) Hash de firma de la app Android de 11 caracteres (SMS Retriever API) para detección automática en Android.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • Autocompletado OTP (iOS y Android): Para permitir que sus usuarios completen automáticamente el código recibido con 1 toque sobre su teclado, simplemente agregue autocomplete="one-time-code" e inputmode="numeric" al campo <input> de su sitio.
  • Tiempo de espera anti-spam (cooldown): El campo "resend_after_seconds" indica el tiempo de espera exacto antes de reintentar (60 s para WhatsApp según Meta, 30 s para SMS). Se aplica un límite diario de 10 verificaciones por número.
POSThttps://api.envoisms.ma/v1/verify/send
curl -X POST "https://api.envoisms.ma/v1/verify/send" \
  -H "Authorization: Bearer smr_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",
  "resend_after_seconds": 60,
  "fallback_channels": ["sms", "whatsapp"],
  "expires_at": "2026-05-15T10:35:00Z",
  "status": "sent",
  "cost": { "eur": 0.05, "mad": 0.55 }
}
DocsVerify/verify/resend
POSThttps://api.envoisms.ma/v1/verify/resend
Bearer Auth

Reenviar código OTP (SMS o WhatsApp)

Reenvía el mismo código OTP activo por SMS o WhatsApp tras expirar el tiempo de espera (30 s para SMS, 60 s para WhatsApp). No genera nuevo código, evitando conflictos.

Cuerpo de la petición
CampoTipoEstadoDescripción
session_idstringRequeridoIdentificador de sesión recibido en la llamada inicial a /v1/verify/send.
channelstringOpcionalCanal de reenvío objetivo ("sms" | "whatsapp"). Por defecto: "sms".
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • Disponible en todos los planes, incluido Starter: /v1/verify/resend requiere el mismo permiso "verify" que /v1/verify/send, nada más.
  • Desde dónde cuenta: el tiempo de espera corre desde la última entrega real, no desde su llamada — 60 s tras una entrega WhatsApp, 30 s tras un SMS. GET /v1/verify/{session_id} devuelve la cuenta atrás en curso ("resend_available_in_seconds") y la cabecera Retry-After del 429 lleva los segundos exactos restantes. La ventana es propia de su cuenta y del número: el tráfico de otro cliente hacia el mismo número nunca le bloquea.
  • Claves sandbox (env_test_): no se entrega nada y no se cobra nada. La respuesta lleva entonces "sandbox": true y "sandbox_code", para que un reenvío simulado nunca se confunda con uno realmente entregado. Una clave sandbox solo puede reenviar sesiones que ella creó, y una clave live solo sesiones live.
POSThttps://api.envoisms.ma/v1/verify/resend
curl -X POST "https://api.envoisms.ma/v1/verify/resend" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "session_id": "vrf_7e2a...",
  "message_id": "wamid.HBgMMjEy...",
  "to": "+212612345678",
  "channel": "whatsapp",
  "status": "sent",
  "resend_after_seconds": 60,
  "expires_at": "2026-05-15T10:35:00Z"
}
DocsVerify/verify/check
POSThttps://api.envoisms.ma/v1/verify/check
Bearer Auth

Verificar un OTP

Valida el código proporcionado por el usuario para una sesión de verificación determinada.

Cuerpo de la petición
CampoTipoEstadoDescripción
session_idstringRequeridoID de sesión recibido en la llamada a /v1/verify/send.
codestringRequeridoEl código recibido e introducido por el usuario.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/verify/check
curl -X POST "https://api.envoisms.ma/v1/verify/check" \
  -H "Authorization: Bearer smr_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"
}
DocsVerify/verify/:id
GEThttps://api.envoisms.ma/v1/verify/:id
Bearer Auth

Estado de la sesión OTP

Consulta el estado (validado o expirado) de una sesión de verificación específica.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/verify/:id
curl -X GET "https://api.envoisms.ma/v1/verify/:id" \
  -H "Authorization: Bearer smr_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"
}
DocsVerify/verify/lookup
POSThttps://api.envoisms.ma/v1/verify/lookup
Bearer Auth

Validación de número

Valida el formato, el operador (carrier), el tipo de línea y la ubicación geográfica de un número de teléfono.

Cuerpo de la petición
CampoTipoEstadoDescripción
numberstringRequeridoEl número de teléfono a validar (formato local o internacional).
country_codestringOpcionalCódigo de país ISO de 2 letras (ej: MA, FR). Recomendado si el número está en formato local.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/verify/lookup
curl -X POST "https://api.envoisms.ma/v1/verify/lookup" \
  -H "Authorization: Bearer smr_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"
}
DocsConversations/conversations
GEThttps://api.envoisms.ma/v1/conversations
Bearer Auth

Listar conversaciones

Recupera el listado de conversaciones de WhatsApp con seguimiento en tiempo real de la ventana de servicio de 24 horas y estado del bot.

Parámetros Query
ParámetroTipoEstadoDescripción
limitintegerOpcionalNúmero máximo de conversaciones a devolver (por defecto 30, máx. 100).
bot_statusstringOpcionalFiltrar por estado del bot ("active" o "muted").
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/conversations
curl -X GET "https://api.envoisms.ma/v1/conversations?limit=50&offset=0" \
  -H "Authorization: Bearer smr_xxx"
{
  "conversations": [
    {
      "phone": "+212612345678",
      "contact_name": "Yassine Alami",
      "last_message": "Bonjour, je souhaite visiter l'appartement témoin",
      "last_message_at": "2026-08-30T11:42:00Z",
      "unread_count": 1,
      "bot_muted": true,
      "can_reply_free": true,
      "window_expires_at": "2026-08-31T11:42:00Z"
    }
  ],
  "total": 1
}
DocsConversations/conversations/:phone
GEThttps://api.envoisms.ma/v1/conversations/:phone
Bearer Auth

Historial de conversación

Recupera el hilo completo de mensajes intercambiados con un contacto de WhatsApp.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/conversations/:phone
curl -X GET "https://api.envoisms.ma/v1/conversations/:phone" \
  -H "Authorization: Bearer smr_xxx"
{
  "phone": "+212612345678",
  "contact_name": "Yassine Alami",
  "bot_muted": true,
  "messages": [
    {
      "id": "msg_01J...",
      "direction": "inbound",
      "body": "Je souhaite des informations sur le projet Casablanca Marina",
      "type": "text",
      "timestamp": "2026-08-30T11:40:00Z"
    },
    {
      "id": "msg_02J...",
      "direction": "outbound",
      "body": "Bonjour Yassine ! Quel type de bien recherchez-vous ?",
      "type": "interactive",
      "timestamp": "2026-08-30T11:40:05Z"
    }
  ]
}
DocsConversations/conversations/:phone/messages
POSThttps://api.envoisms.ma/v1/conversations/:phone/messages
Bearer Auth

Responder en chat en vivo

Envía una respuesta de agente y silencia el bot en esa conversación (reactivación con POST /v1/conversations/:phone/toggle-bot). Un mensaje libre de WhatsApp exige que el contacto haya escrito en las últimas 24 horas (si no, 400 OUT_OF_24H_WINDOW); una plantilla aprobada puede enviarse en cualquier momento.

Cuerpo de la petición
CampoTipoEstadoDescripción
messagestringOpcionalTexto de la respuesta (o pie del medio adjunto). Obligatorio sin plantilla ni medio.
channelstringOpcional"whatsapp" (por defecto) o "sms".
template_namestringOpcionalPlantilla de WhatsApp aprobada que se envía en lugar de texto libre (con template_language y variables).
media_urlstringOpcionalURL https (o data URI) de una imagen o PDF que adjuntar; media_type "image" o "document".
phone_number_idstringOpcionalNúmero de WhatsApp conectado que responde.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/conversations/:phone/messages
curl -X POST "https://api.envoisms.ma/v1/conversations/:phone/messages" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "ok": true,
  "message": {
    "id": "msg_03J...",
    "phone": "212612345678",
    "role": "agent",
    "message": "Bonjour Yassine, votre visite est confirmée.",
    "status": "sent",
    "channel": "whatsapp",
    "created_at": "2026-08-30T11:45:00Z"
  }
}
DocsLeads/qualified-leads
GEThttps://api.envoisms.ma/v1/qualified-leads
Bearer Auth

Listar leads calificados

Recupera los clientes potenciales calificados automáticamente por AtlasAI™ con su puntuación BANT y estado CRM.

Parámetros Query
ParámetroTipoEstadoDescripción
stagestringOpcionalFiltrar por etapa ("new", "contacted", "meeting_scheduled", "closed_won", "closed_lost").
min_scoreintegerOpcionalPuntuación BANT mínima (0 a 100).
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • Los leads son calificados por AtlasAI™ Conversational Engine, AtlasAI™ Voice y AtlasAI™ Vision directamente a través de mensajes de WhatsApp. Estos motores de IA están integrados de forma nativa en WABA y no se ofrecen como API independientes.
GEThttps://api.envoisms.ma/v1/qualified-leads
curl -X GET "https://api.envoisms.ma/v1/qualified-leads?limit=50&offset=0" \
  -H "Authorization: Bearer smr_xxx"
{
  "leads": [
    {
      "id": "lead_01J...",
      "phone": "+212612345678",
      "name": "Dr. Benjelloun",
      "preset": "medical_equipment",
      "bant_score": 85,
      "is_hot": true,
      "breakdown": {
        "budget": 25,
        "authority": 25,
        "need": 20,
        "timeline": 15
      },
      "intent": "Échographe Doppler pour nouveau cabinet",
      "stage": "meeting_scheduled",
      "created_at": "2026-08-30T09:15:00Z"
    }
  ],
  "total": 1
}
DocsLeads/qualified-leads/:id/status
POSThttps://api.envoisms.ma/v1/qualified-leads/:id/status
Bearer Auth

Actualizar estado del lead

Actualiza la etapa en el pipeline comercial de un lead calificado.

Cuerpo de la petición
CampoTipoEstadoDescripción
statusstringRequerido"new" | "contacted" | "meeting_scheduled" | "closed_won" | "closed_lost"
notesstringOpcionalNotas internas de seguimiento comercial.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/qualified-leads/:id/status
curl -X POST "https://api.envoisms.ma/v1/qualified-leads/:id/status" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "success": true,
  "lead_id": "lead_01J...",
  "stage": "meeting_scheduled"
}
DocsContacts/contacts
GEThttps://api.envoisms.ma/v1/contacts
Bearer Auth

Listar contactos

Recupera todos los contactos de su cuenta, con filtrado por palabra clave o por lista.

Parámetros Query
ParámetroTipoEstadoDescripción
limitintegerOpcionalResultados por página (1-500, por defecto: 100).
offsetintegerOpcionalDesplazamiento de paginación (por defecto: 0).
qstringOpcionalBúsqueda por nombre, teléfono o email.
list_idstringOpcionalFiltrar únicamente los miembros de una lista de contactos específica.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/contacts
curl -X GET "https://api.envoisms.ma/v1/contacts?limit=50&offset=0" \
  -H "Authorization: Bearer smr_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
}
DocsContacts/contacts
POSThttps://api.envoisms.ma/v1/contacts
Bearer Auth

Crear / Modificar un contacto

Añade un contacto o actualiza la información de un contacto existente (detección por número).

Cuerpo de la petición
CampoTipoEstadoDescripción
phonestringRequeridoNúmero de teléfono en formato E.164.
namestringOpcionalNombre completo del contacto.
emailstringOpcionalDirección de email.
list_idstringOpcionalAsociar inmediatamente el contacto a una lista existente.
custom_fieldsobjectOpcionalObjeto que contiene hasta 3 campos personalizados ("custom1", "custom2", "custom3").
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/contacts
curl -X POST "https://api.envoisms.ma/v1/contacts" \
  -H "Authorization: Bearer smr_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"
}
DocsContacts/contacts/import
POSThttps://api.envoisms.ma/v1/contacts/import
Bearer Auth

Importar contactos

Importa masivamente hasta 5 000 contactos en una sola llamada.

Cuerpo de la petición
CampoTipoEstadoDescripción
contactsarrayRequeridoArray de objetos que contienen "phone", "name" (opcional) y "email" (opcional).
list_idstringOpcionalID de la lista en la que importar el grupo.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/contacts/import
curl -X POST "https://api.envoisms.ma/v1/contacts/import" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      {
        "phone": "+212611111111",
        "name": "Karim"
      },
      {
        "phone": "+212622222222",
        "name": "Youssef"
      }
    ],
    "list_id": "lst_f84b..."
  }'
{
  "imported": 150,
  "skipped": 3
}
DocsContacts/contacts/:id
DELETEhttps://api.envoisms.ma/v1/contacts/:id
Bearer Auth

Eliminar un contacto

Elimina definitivamente un contacto a partir de su identificador único.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
DELETEhttps://api.envoisms.ma/v1/contacts/:id
curl -X DELETE "https://api.envoisms.ma/v1/contacts/:id" \
  -H "Authorization: Bearer smr_xxx"
{
  "deleted": true,
  "id": "ctc_a2b3..."
}
DocsContacts/contacts/lists
GEThttps://api.envoisms.ma/v1/contacts/lists
Bearer Auth

Listar las listas

Recupera todas las listas de contactos creadas para las campañas de difusión.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/contacts/lists
curl -X GET "https://api.envoisms.ma/v1/contacts/lists" \
  -H "Authorization: Bearer smr_xxx"
{
  "data": [
    {
      "id": "lst_f84b...",
      "name": "Newsletter Clients",
      "description": "Clients inscrits à notre lettre d'information",
      "count": 1420,
      "created_at": "2026-04-15T09:00:00Z"
    }
  ]
}
DocsContacts/contacts/lists
POSThttps://api.envoisms.ma/v1/contacts/lists
Bearer Auth

Crear una lista

Crea un nuevo grupo (lista de contactos) vacío destinado a las campañas.

Cuerpo de la petición
CampoTipoEstadoDescripción
namestringRequeridoNombre de la lista.
descriptionstringOpcionalDescripción de la lista.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/contacts/lists
curl -X POST "https://api.envoisms.ma/v1/contacts/lists" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Newsletter Clients",
    "description": "Clients inscrits"
  }'
{
  "id": "lst_f84b...",
  "name": "Newsletter Clients",
  "description": "Clients inscrits",
  "count": 0
}
DocsContacts/optouts
GEThttps://api.envoisms.ma/v1/optouts
Bearer Auth

Listar las bajas

Recupera la lista de números que se han dado de baja (STOP) de sus comunicaciones.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/optouts
curl -X GET "https://api.envoisms.ma/v1/optouts" \
  -H "Authorization: Bearer smr_xxx"
{
  "data": [
    {
      "phone": "+212611111111",
      "opted_out_at": "2026-06-01T12:00:00Z"
    }
  ],
  "total": 1
}
DocsContacts/optouts
POSThttps://api.envoisms.ma/v1/optouts
Bearer Auth

Añadir una baja

Añade manualmente un número a su lista de bajas (blacklist global).

Cuerpo de la petición
CampoTipoEstadoDescripción
phonestringRequeridoNúmero de teléfono en formato E.164.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/optouts
curl -X POST "https://api.envoisms.ma/v1/optouts" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "success": true,
  "phone": "+212611111111",
  "opted_out_at": "2026-06-01T12:00:00Z"
}
DocsContacts/optouts/:phone
DELETEhttps://api.envoisms.ma/v1/optouts/:phone
Bearer Auth

Retirar una baja

Retira un número de la lista de bajas.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
DELETEhttps://api.envoisms.ma/v1/optouts/:phone
curl -X DELETE "https://api.envoisms.ma/v1/optouts/:phone" \
  -H "Authorization: Bearer smr_xxx"
{
  "deleted": true,
  "phone": "+212611111111"
}
DocsContacts/consents
GEThttps://api.envoisms.ma/v1/consents
Bearer Auth

Listar consentimientos

Registro de consentimientos de solo adición (ley 09-08, art. 10): cada consentimiento y cada retirada es un evento fechado con su fuente y su prueba. La plataforma escribe por sí misma las palabras clave STOP/START recibidas en WhatsApp y SMS y la primera conversación abierta por el cliente. Añada format=csv para exportar todo el conjunto filtrado.

Parámetros Query
ParámetroTipoEstadoDescripción
phonestringOpcionalNúmero E.164 a filtrar.
purposestringOpcionalmarketing, transactional, otp o service.
statusstringOpcionalgranted o withdrawn.
fromstringOpcionalEventos registrados a partir de esta fecha ISO 8601.
formatstringOpcionalcsv para descargar el conjunto completo como archivo.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/consents
curl -X GET "https://api.envoisms.ma/v1/consents?limit=50&offset=0" \
  -H "Authorization: Bearer smr_xxx"
{
  "data": [
    {
      "id": "cns_9f2a...",
      "phone": "+212612345678",
      "channel": "whatsapp",
      "purpose": "marketing",
      "status": "withdrawn",
      "source": "whatsapp_keyword",
      "evidence": { "keyword": "stop", "lang": "fr" },
      "recorded_at": "2026-09-05T09:00:00.000Z",
      "created_at": "2026-09-05T09:00:00.000Z"
    }
  ],
  "total": 1,
  "limit": 100,
  "offset": 0
}
DocsContacts/consents
POSThttps://api.envoisms.ma/v1/consents
Bearer Auth

Registrar un consentimiento

Consigna que una persona dio o retiró su consentimiento, con la prueba que usted posee (texto mostrado, URL, IP, referencia). recorded_at puede antedatarse para un consentimiento importado, nunca en el futuro. Una retirada de marketing pasa de inmediato a la lista de exclusión.

Cuerpo de la petición
CampoTipoEstadoDescripción
phonestringRequeridoNúmero en formato E.164.
purposestringRequeridomarketing, transactional, otp o service.
statusstringOpcionalgranted (por defecto) o withdrawn.
channelstringOpcionalwhatsapp, sms o any (por defecto).
sourcestringOpcionalapi (por defecto), form, import o dashboard. Las fuentes por palabra clave están reservadas a la plataforma.
evidenceobjectOpcionalObjeto JSON libre (< 4 KB): texto mostrado, url, ip, referencia.
recorded_atstringOpcionalFecha ISO 8601 del acto de la persona (por defecto: ahora).
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/consents
curl -X POST "https://api.envoisms.ma/v1/consents" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "id": "cns_9f2a...",
  "phone": "+212612345678",
  "channel": "any",
  "purpose": "marketing",
  "status": "granted",
  "source": "form",
  "evidence": { "text": "J'accepte de recevoir les offres par WhatsApp", "url": "https://example.ma/inscription" },
  "recorded_at": "2026-09-01T10:00:00.000Z",
  "created_at": "2026-09-09T12:00:00.000Z"
}
DocsContacts/consents/:phone
GEThttps://api.envoisms.ma/v1/consents/:phone
Bearer Auth

Estado e historial de un número

La respuesta a «muéstreme el consentimiento de esta persona»: estado actual por finalidad (derivado del evento más reciente, unknown sin historial, nunca presumido), presencia en la lista de exclusión e historial completo.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/consents/:phone
curl -X GET "https://api.envoisms.ma/v1/consents/:phone" \
  -H "Authorization: Bearer smr_xxx"
{
  "phone": "+212612345678",
  "opted_out": true,
  "opted_out_at": "2026-09-05T09:00:00Z",
  "state": {
    "marketing": { "status": "withdrawn", "channel": "whatsapp", "source": "whatsapp_keyword", "recorded_at": "2026-09-05T09:00:00.000Z", "record_id": "cns_3" },
    "transactional": { "status": "unknown" },
    "otp": { "status": "unknown" },
    "service": { "status": "granted", "channel": "whatsapp", "source": "whatsapp_inbound", "recorded_at": "2026-07-01T09:00:00.000Z", "record_id": "cns_1" }
  },
  "history": []
}
DocsCampaigns/campaigns
GEThttps://api.envoisms.ma/v1/campaigns
Bearer Auth

Listar campañas

Recupera todas sus campañas de envío programado o de difusión en curso.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/campaigns
curl -X GET "https://api.envoisms.ma/v1/campaigns" \
  -H "Authorization: Bearer smr_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"
    }
  ]
}
DocsCampaigns/campaigns
POSThttps://api.envoisms.ma/v1/campaigns
Bearer Auth

Crear una campaña

Registra una nueva campaña como borrador o la programa para una fecha concreta.

Cuerpo de la petición
CampoTipoEstadoDescripción
namestringRequeridoNombre de la campaña.
bodystringRequeridoCuerpo del mensaje. Puede usar la variable {{name}}. (Se requiere uno de los dos: body o template_id.)
template_idstringRequeridoAlternativamente, ID de una plantilla aprobada. (Se requiere uno de los dos: body o template_id.)
channelstringOpcional"sms" o "whatsapp". Por defecto "sms".
list_idstringOpcionalID de la lista de contactos destinataria.
sender_idstringOpcionalNombre de remitente.
scheduled_atstringOpcionalFecha de programación (ISO 8601). Cambia el estado a "scheduled".
buttonsarrayOpcionalArray de botones interactivos de WhatsApp (máx. 3, tipo "copy" | "url" | "call").
metadataobjectOpcionalMetadatos personalizados (ej: opciones de throttling / cadencia de envío: {"throttling": "50_min"}).
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/campaigns
curl -X POST "https://api.envoisms.ma/v1/campaigns" \
  -H "Authorization: Bearer smr_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"
}
DocsCampaigns/campaigns/:id
GEThttps://api.envoisms.ma/v1/campaigns/:id
Bearer Auth

Detalles de una campaña

Recupera los detalles, la programación y el estado de ejecución de una campaña.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/campaigns/:id
curl -X GET "https://api.envoisms.ma/v1/campaigns/:id" \
  -H "Authorization: Bearer smr_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"
}
DocsCampaigns/campaigns/:id/send
POSThttps://api.envoisms.ma/v1/campaigns/:id/send
Bearer Auth

Lanzar una campaña

Inicia inmediatamente la difusión de una campaña en borrador a todos los contactos asociados.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/campaigns/:id/send
curl -X POST "https://api.envoisms.ma/v1/campaigns/:id/send" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "id": "cmp_8d2a...",
  "queued": 1420,
  "total": 1420
}
DocsWebhooks/webhooks
GEThttps://api.envoisms.ma/v1/webhooks
Bearer Auth

Listar webhooks

Recupera la lista de todos sus endpoints de webhooks registrados.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/webhooks
curl -X GET "https://api.envoisms.ma/v1/webhooks" \
  -H "Authorization: Bearer smr_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"
    }
  ]
}
DocsWebhooks/webhooks
POSThttps://api.envoisms.ma/v1/webhooks
Bearer Auth

Crear un Webhook

Registra una URL HTTPS de callback para recibir las notificaciones de eventos.

Cuerpo de la petición
CampoTipoEstadoDescripción
urlstringRequeridoURL de destino segura que comience por "https://".
eventsarrayOpcionalArray de eventos (ej: ["message.delivered", "message.failed"]). Se aceptan los comodines "message.*" y "*". Por defecto: ["message.delivered", "message.failed"].
secretstringOpcionalClave de firma secreta. Si no se proporciona, se generará automáticamente.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/webhooks
curl -X POST "https://api.envoisms.ma/v1/webhooks" \
  -H "Authorization: Bearer smr_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
}
DocsWebhooks/webhooks/:id
PATCHhttps://api.envoisms.ma/v1/webhooks/:id
Bearer Auth

Modificar un Webhook

Actualiza la configuración de un webhook (URL, eventos suscritos o estado activo).

Cuerpo de la petición
CampoTipoEstadoDescripción
urlstringOpcionalNueva URL HTTPS.
eventsarrayOpcionalNueva lista de eventos suscritos.
activebooleanOpcionalActivar (true) o desactivar (false) el webhook.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
PATCHhttps://api.envoisms.ma/v1/webhooks/:id
curl -X PATCH "https://api.envoisms.ma/v1/webhooks/:id" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://mon-serveur.ma/api/envoisms-receiver-updated",
    "active": false
  }'
{
  "updated": true,
  "id": "whk_5f2b..."
}
DocsWebhooks/webhooks/:id
DELETEhttps://api.envoisms.ma/v1/webhooks/:id
Bearer Auth

Eliminar un Webhook

Desactiva y elimina lógicamente un endpoint de webhook.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
DELETEhttps://api.envoisms.ma/v1/webhooks/:id
curl -X DELETE "https://api.envoisms.ma/v1/webhooks/:id" \
  -H "Authorization: Bearer smr_xxx"
{
  "deleted": true,
  "id": "whk_5f2b..."
}
DocsWebhooks/webhooks/:id/test
POSThttps://api.envoisms.ma/v1/webhooks/:id/test
Bearer Auth

Probar un Webhook

Dispara un evento de prueba ("message.test") hacia la URL configurada del webhook.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/webhooks/:id/test
curl -X POST "https://api.envoisms.ma/v1/webhooks/:id/test" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "queued": true,
  "id": "whk_5f2b..."
}
DocsWebhooks/inbound-webhooks
GEThttps://api.envoisms.ma/v1/inbound-webhooks
Bearer Auth

Listar Inbound Webhooks

Recupera todos los endpoints de captura de leads publicitarios configurados en su cuenta.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/inbound-webhooks
curl -X GET "https://api.envoisms.ma/v1/inbound-webhooks" \
  -H "Authorization: Bearer smr_xxx"
{
  "webhooks": [
    {
      "id": "inw_9a8b...",
      "name": "Campagne TikTok Ads Casablanca",
      "source": "tiktok_ads",
      "catch_url": "https://api.envoisms.ma/v1/inbound-webhooks/catch/inw_9a8b...",
      "auto_start_funnel": true,
      "total_received": 142,
      "created_at": "2026-08-20T14:00:00Z"
    }
  ]
}
DocsWebhooks/inbound-webhooks
POSThttps://api.envoisms.ma/v1/inbound-webhooks
Bearer Auth

Crear un Inbound Webhook

Genera una URL de captura para recibir prospectos de TikTok Lead Ads, Meta Lead Ads, Zapier o Make al instante.

Cuerpo de la petición
CampoTipoEstadoDescripción
namestringRequeridoNombre descriptivo de la fuente (ej: "Facebook Lead Gen Promo Verano").
sourcestringOpcionalIdentificador de fuente ("tiktok_ads", "meta_leads", "google_forms", "custom"). Por defecto: "custom".
auto_start_funnelbooleanOpcionalSi es true, activa inmediatamente el flujo de calificación de WhatsApp AtlasAI™ al recibir el lead.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/inbound-webhooks
curl -X POST "https://api.envoisms.ma/v1/inbound-webhooks" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "id": "inw_9a8b...",
  "name": "Campagne TikTok Ads Casablanca",
  "catch_url": "https://api.envoisms.ma/v1/inbound-webhooks/catch/inw_9a8b...",
  "auto_start_funnel": true
}
DocsBilling/billing/balance
GEThttps://api.envoisms.ma/v1/billing/balance
Bearer Auth

Consultar el saldo

Consulta el saldo disponible en dírhams marroquíes (MAD) junto con la divisa y el plan activo.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/billing/balance
curl -X GET "https://api.envoisms.ma/v1/billing/balance" \
  -H "Authorization: Bearer smr_xxx"
{
  "balance_mad": 1492.5,
  "currency": "MAD",
  "plan": "croissance"
}
DocsMachine Payments/machine-payments/status
GEThttps://api.envoisms.ma/v1/machine-payments/status
Bearer Auth

Estado de pagos máquina

Indica si los pagos máquina (MPP / HTTP 402) están activos en esta instancia. Un agente puede consultar este endpoint antes de intentar una llamada de pago.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • Cuando "enabled" es false, cualquier llamada de pago devuelve 503 en lugar de 402.
GEThttps://api.envoisms.ma/v1/machine-payments/status
curl -X GET "https://api.envoisms.ma/v1/machine-payments/status" \
  -H "Authorization: Bearer smr_xxx"
{
  "enabled": true,
  "deposit_usd": 5.00,
  "credit_mad": 49.65,
  "networks": ["base", "tempo"],
  "permissions": ["send", "status", "balance", "verify"]
}
DocsMachine Payments/messages
POSThttps://api.envoisms.ma/v1/messages
Bearer Auth

Desafío de pago (HTTP 402)

Cualquier endpoint de pago llamado sin clave API devuelve un 402 con una cabecera WWW-Authenticate: Payment que contiene un desafío firmado y una dirección de depósito USDC. El agente deposita exactamente deposit_usd USDC en una de las direcciones y reintenta la llamada con una credencial Payment.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • El campo "request" es JSON canónico (RFC 8785) codificado en base64url sin relleno. Contiene: amount, currency, networks[], recipients{}, paymentIntent, resource, credit{}.
  • Deduplicación por IP: si ya existe un desafío activo para la misma IP, se devuelve el mismo desafío en lugar de una nueva dirección de depósito.
  • Límite: 5 desafíos por minuto por IP. A partir de ahí, se devuelve el 402 sin dirección de depósito.
POSThttps://api.envoisms.ma/v1/messages
curl -X POST "https://api.envoisms.ma/v1/messages" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+212612345678",
    "message": "Votre code de validation est 849204",
    "from": "MaBoutique",
    "channel": "whatsapp"
  }'
HTTP/1.1 402 Payment Required
WWW-Authenticate: Payment id="chal_01jxyz", realm="envoisms",
  method="stripe", intent="session",
  request="<base64url-JCS-encoded JSON>",
  expires="2026-09-25T21:45:00.000Z",
  description="EnvoiSMS pay-per-use API access."

{
  "type": "https://paymentauth.org/problems/payment-required",
  "title": "Payment Required",
  "status": 402,
  "detail": "Payment is required.",
  "challengeId": "chal_01jxyz"
}
DocsMachine Payments/messages (+ /v1/verify, /v1/waba)
POSThttps://api.envoisms.ma/v1/messages (+ /v1/verify, /v1/waba)
Bearer Auth

Canjear una credencial de pago

Tras depositar los fondos USDC, el agente reintenta el endpoint de pago original (ej: POST /v1/messages) sustituyendo Authorization: Bearer por Authorization: Payment <credential>. El worker valida el depósito en Stripe en el lado del servidor, acredita una cuenta máquina y devuelve la clave API con alcance limitado en la cabecera X-Machine-Session-Key.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
Notes d'implémentation
  • La credencial es JSON canónico base64url: {"challenge":{"id":"chal_01jxyz","method":"stripe","intent":"session"},"source":"<wallet-address>","payload":{}}.
  • La clave devuelta se muestra una sola vez. Idempotente: un agente que pierde su clave puede volver a llamar — el mismo depósito devuelve una nueva clave para la misma cuenta.
  • Devuelve 402 si el depósito en Stripe aún no ha alcanzado el estado "succeeded". El agente debe esperar la confirmación on-chain (normalmente 1–2 minutos) antes de reintentar.
POSThttps://api.envoisms.ma/v1/messages (+ /v1/verify, /v1/waba)
curl -X POST "https://api.envoisms.ma/v1/messages  (+ /v1/verify, /v1/waba)" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "key": "smr_live_xxxxxxxxxxxxxxxxxxxx",
  "permissions": ["send", "status", "balance", "verify"],
  "credit_mad": 49.65,
  "receipt": "<base64url-encoded receipt>",
  "account": {
    "id": "acct_01jxyz",
    "plan": "starter",
    "balance_mad": 49.65
  }
}
DocsAnalytics/analytics
GEThttps://api.envoisms.ma/v1/analytics
Bearer Auth

Estadísticas de uso

Recupera métricas clave sobre sus envíos (volúmenes totales, tasa de entregabilidad y costes facturados).

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/analytics
curl -X GET "https://api.envoisms.ma/v1/analytics" \
  -H "Authorization: Bearer smr_xxx"
{
  "summary": {
    "total": 12840,
    "delivered": 12570,
    "delivery_rate": 97.9,
    "cost_mad": 2663.1
  }
}
DocsAPI Keys/api-keys
GEThttps://api.envoisms.ma/v1/api-keys
Bearer Auth

Listar claves API

Recupera la lista de todas sus claves de API activas o revocadas.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
GEThttps://api.envoisms.ma/v1/api-keys
curl -X GET "https://api.envoisms.ma/v1/api-keys" \
  -H "Authorization: Bearer smr_xxx"
{
  "data": [
    {
      "id": "key_e84c...",
      "name": "Production Server",
      "key_prefix": "smr_a8f7d6c5",
      "sandbox": false,
      "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"
    }
  ]
}
DocsAPI Keys/api-keys
POSThttps://api.envoisms.ma/v1/api-keys
Bearer Auth

Crear una clave API

Genera un nuevo token de API seguro con permisos y restricciones específicos.

Cuerpo de la petición
CampoTipoEstadoDescripción
namestringOpcionalEtiqueta para identificar la clave (por defecto: "API key").
permissionsarrayOpcionalDerechos concedidos (send, verify, status, balance, contacts, campaigns, webhooks, billing, analytics, api_keys, optouts, sender_id).
ip_whitelistarrayOpcionalLista de direcciones IP autorizadas a ejecutar peticiones con esta clave.
rate_limitintegerOpcionalLímite máximo de peticiones/min (de 10 a 2000). Por defecto según el plan: Starter 60, Business 180, Pro 500, Enterprise 1 200.
sandboxbooleanOpcionaltrue genera una clave de prueba con el prefijo env_test_. Las peticiones se validan y registran, pero ningún mensaje se envía realmente y nada se factura. El modo de una clave es definitivo: para cambiarlo, cree una nueva clave.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
POSThttps://api.envoisms.ma/v1/api-keys
curl -X POST "https://api.envoisms.ma/v1/api-keys" \
  -H "Authorization: Bearer smr_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": "smr_a8f7d6c5",
  "api_key": "smr_a8f7d6c5b4a3...",
  "sandbox": false,
  "permissions": [
    "send",
    "verify",
    "status"
  ],
  "rate_limit": 100,
  "warning": "The full API key is shown once. Store it securely."
}
DocsAPI Keys/api-keys/:id
PATCHhttps://api.envoisms.ma/v1/api-keys/:id
Bearer Auth

Modificar una clave API

Actualiza los permisos, restricciones de IP o el estado de activación de una clave API.

Cuerpo de la petición
CampoTipoEstadoDescripción
namestringOpcionalNuevo nombre.
permissionsarrayOpcionalNueva lista de permisos.
ip_whitelistarrayOpcionalNueva lista de direcciones IP autorizadas.
rate_limitintegerOpcionalNuevo límite de peticiones por minuto.
activebooleanOpcionalActivar o suspender la clave.
Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
PATCHhttps://api.envoisms.ma/v1/api-keys/:id
curl -X PATCH "https://api.envoisms.ma/v1/api-keys/:id" \
  -H "Authorization: Bearer smr_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Backup Server",
    "active": true
  }'
{
  "updated": true,
  "id": "key_e84c..."
}
DocsAPI Keys/api-keys/:id
DELETEhttps://api.envoisms.ma/v1/api-keys/:id
Bearer Auth

Revocar una clave API

Revoca definitivamente una clave API para impedir que autentique peticiones.

Cabeceras HTTP
Authorization: Bearer env_test_d...
Content-Type: application/json
Accept: application/json
DELETEhttps://api.envoisms.ma/v1/api-keys/:id
curl -X DELETE "https://api.envoisms.ma/v1/api-keys/:id" \
  -H "Authorization: Bearer smr_xxx"
{
  "revoked": true,
  "id": "key_e84c..."
}

Guía de Webhooks

Callbacks de entrega firmados y seguros.

EnvoiSMS.ma envía eventos JSON a la URL HTTPS de su servidor con un encabezado X-EnvoiSMS.ma-Signature para autenticar al remitente.

message.sent

El mensaje fue aceptado por la red del operador.

message.delivered

El mensaje fue entregado con éxito al destinatario (SMS o WhatsApp).

message.read

El mensaje de WhatsApp fue abierto y leído por el destinatario (doble check azul).

message.failed

Fallo de entrega en la ruta o en la presentación (rechazo, error de encaminamiento).

message.undeliverable

La red confirmó que el mensaje no puede entregarse (número inexistente, expirado en la cola del operador).

message.fallback

Cascada (cascade: true): el mensaje pasa al siguiente canal (p. ej. WhatsApp → SMS) porque el primero rechazó o informó del fallo del mensaje, o no envió acuse de entrega dentro de cascade_timeout. channel es el nuevo canal, previous_channel el anterior, error_code y error_message el motivo.

message.inbound

Un destinatario respondió a uno de sus mensajes SMS o WhatsApp (entrante).

message.flow_response

Un usuario completó y envió un formulario nativo de WhatsApp Flow.

message.location

Un usuario compartió su ubicación geográfica GPS en WhatsApp.

lead.qualified

AtlasAI™ completó la calificación BANT de un cliente potencial en WhatsApp.

contact.optout

Un destinatario se dio de baja (palabra clave STOP o similar).

Validación de firma
import crypto from 'node:crypto';

// La signature arrive dans le header X-EnvoiSMS-Signature
// (format "sha256=<hex>"), l'événement dans X-EnvoiSMS-Event.
// Corps livré : { "event": "...", "data": { ... }, "timestamp": "..." }
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

Errores

Estructura de las respuestas de error de la API.

Todos los errores de la API devuelven un código HTTP adecuado (4xx o 5xx) junto con una estructura JSON predecible que contiene el código de error y la descripción.

{
  "error": {
    "code": "INVALID_PHONE",
    "message": "to must be E.164 format, for example +212612345678",
    "docs": "https://envoisms.ma/docs#errors"
  }
}
UNAUTHORIZED

Clave API ausente o no válida.

INSUFFICIENT_BALANCE

Saldo insuficiente para realizar el envío.

INVALID_PHONE

El número de teléfono no está en formato E.164.

WHATSAPP_NOT_CONNECTED

Ningún número de WhatsApp Business conectado: conecte el suyo en el panel para enviar por WhatsApp. Para un texto ordinario, omita channel (SMS por defecto) — no se ha cobrado nada.

OUT_OF_24H_WINDOW

Mensaje libre de WhatsApp a un contacto que no le ha escrito en las últimas 24 horas. Envíe una plantilla aprobada. No se ha cobrado nada.

WHATSAPP_ONLY_FIELD

Se envió un campo exclusivo de WhatsApp (reaction, contacts, location, sticker, context) en otro canal.

CONFLICTING_MESSAGE_TYPES

Un mensaje lleva un solo tipo de contenido: reaction, contacts, location o sticker no se combinan con nada más.

CASCADE_NOT_SUPPORTED

cascade no es posible con una reacción, contactos, una ubicación o un sticker: no hay equivalente SMS.

INVALID_REACTION

reaction necesita el message_id (wamid) de destino y un solo emoji (o una cadena vacía para retirar la reacción).

INVALID_CONTEXT

context necesita el message_id (wamid) del mensaje citado y no se combina con reaction.

INVALID_CONTACTS

contacts debe ser un array de 1 a 20 fichas, cada una con name.formatted_name; el mensaje indica la ficha errónea.

INVALID_LOCATION

location exige latitude (-90 a 90) y longitude (-180 a 180) numéricas; name y address son opcionales.

INVALID_MEDIA

Un medio de WhatsApp lleva "id" o "link" (URL https), nunca ambos; sin pie en audio y sticker.

META_WINDOW_EXPIRED

Fallo de WhatsApp (131047): la ventana de servicio de 24 horas estaba cerrada. Envíe una plantilla aprobada o un SMS.

META_UNDELIVERABLE

Fallo de WhatsApp (131026): el número no es localizable en WhatsApp. Sin reintento automático.

META_MARKETING_LIMIT

Fallo de WhatsApp (131049): límite de mensajes de marketing por destinatario. No reenvíe de inmediato.

META_RATE_LIMITED

Fallo de WhatsApp (130429 caudal del número, o 131056 como META_PAIR_RATE_LIMITED: demasiados mensajes a este contacto) tras 3 intentos automáticos.

META_POLICY_BLOCKED

Fallo de WhatsApp (368; también META_ACCOUNT_LOCKED 131031, META_PAYMENT_ISSUE 131042, META_PHONE_NOT_REGISTERED 133010): número o cuenta emisora restringida. Revise WhatsApp Manager.

META_TEMPLATE_NOT_FOUND

Fallo de WhatsApp (132001; también META_TEMPLATE_PARAM_MISMATCH 132000, META_TEMPLATE_PARAM_FORMAT 132012): plantilla inexistente en ese idioma o variables incorrectas.

RATE_LIMITED

Límite de peticiones por minuto superado. Respete la cabecera Retry-After.

INVALID_IDEMPOTENCY_KEY

La cabecera Idempotency-Key supera los 255 caracteres.

IDEMPOTENCY_IN_FLIGHT

La petición original con esta Idempotency-Key aún está en curso. Reintente en un momento.

IDEMPOTENCY_KEY_REUSED

Esta Idempotency-Key ya se usó con un cuerpo de petición diferente. Use una clave nueva.

INVALID_CHANNEL

El canal solicitado no existe. Canales válidos: sms, whatsapp, telegram, voice, rcs.

CHANNEL_NOT_CONFIGURED

El canal solicitado no está disponible actualmente en la plataforma.

CHANNEL_DISABLED

El canal solicitado está desactivado en la plataforma.

FORBIDDEN

La clave API no tiene el permiso necesario para esta acción, o la cuenta está suspendida.

SENDER_ID_TOO_LONG

El Sender ID supera el límite de 11 caracteres.

SENDER_ID_INVALID

El Sender ID contiene caracteres no permitidos.

SENDER_ID_NOT_APPROVED

El Sender ID aún no ha sido aprobado por los operadores.

SENDER_ID_PENDING

El Sender ID está en proceso de aprobación.

SENDER_ID_REJECTED

El Sender ID fue rechazado por los operadores.

SENDER_ID_GENERIC

El Sender ID es un encabezado genérico (INFO, ALERTA, SERVICIO…), no una marca. Use su nombre de marca u omita sender_id.

SENDER_ID_PROTECTED_BRAND

El Sender ID designa o imita a una institución protegida (banco, operador, administración). Reservado a cuentas cuyo registro para ese nombre fue aprobado.

SENDER_ID_NOT_REGISTERED

El Sender ID nunca fue registrado en esta cuenta y la cuenta aún no tiene una recarga: el envío se limita a su propio número verificado.

TRIAL_RESTRICTED_DESTINATION

Cuenta en modo de prueba gratuita: los envíos de prueba están limitados a su propio número verificado. Realice una primera recarga para enviar a terceros.

MISSING_FIELD

Falta un campo obligatorio en la petición.

CASCADE_TIMEOUT

El primer canal expiró; se cambia al canal secundario (cascada).

UPSTREAM_ERROR

Error de entrega a nivel del operador o de la pasarela.

OPTED_OUT

El número rechazó sus comunicaciones (STOP). Envío prohibido.

SPAM_OR_PHISHING_DETECTED

El mensaje contiene un enlace identificado como phishing, o habla en nombre de un banco, operador o administración. Envío rechazado y cuenta suspendida pendiente de revisión.

CONTENT_BLOCKED

El contenido del mensaje fue bloqueado por el control anti-abuso y la cuenta está suspendida pendiente de revisión. Contacte con soporte.

INVALID_CODE

El código OTP enviado es incorrecto. El mensaje de error indica cuántos intentos quedan.

EXPIRED_CODE

El código OTP ha caducado. Solicite uno nuevo mediante /v1/verify/send.

MAX_ATTEMPTS

Se superó el número máximo de intentos de verificación. La sesión está cerrada.

STRIPE_ERROR

No se pudo crear la página de pago de nuestro lado. No se realizó ningún cargo — reintente en un momento.

INTERNAL_ERROR

Error interno de nuestro lado. Reintente; contacte con soporte si el problema persiste.

INVALID_PURPOSE

purpose debe ser marketing, transactional, otp o service.

INVALID_STATUS

status debe ser granted o withdrawn.

INVALID_CHANNEL

channel debe ser whatsapp, sms o any.

INVALID_SOURCE

source debe ser api, form, import o dashboard.

INVALID_EVIDENCE

evidence debe ser un objeto JSON de menos de 4 KB.

INVALID_DATE

Una fecha no está en formato ISO 8601, o recorded_at está en el futuro.

Límites

Restricciones y cuotas en el entorno de producción.

OpenAPI YAML
Peticiones API

60 a 1 200 peticiones / minuto por clave según el plan (Starter 60, Business 180, Pro 500, Enterprise 1 200), ampliable bajo demanda.

Tamaño del mensaje

1600 caracteres máximo por mensaje.

Lote masivo

Hasta 10 000 mensajes por llamada API.

Retención de logs

90 días para los informes detallados.