SMS & WhatsApp Messaging

Send a message

Send one SMS, or one WhatsApp message from your own connected WhatsApp Business number (channel whatsapp: templates, text, media by id or link, interactive list/button/flow/cta_url/location_request_message, reactions, contact cards, locations, stickers, and a reply context on any of them). WhatsApp rule: a message that is not a template may only be sent to a contact who wrote to your number in the last 24 hours; otherwise it is refused with 400 OUT_OF_24H_WINDOW before anything is charged. Reactions are not billed. To show a typing indicator while you prepare a reply, see POST /messages/typing. Without a connected number, WhatsApp OTPs are available via /verify/send with channel whatsapp. Sending one-time codes? /verify/send manages the full OTP lifecycle (generation, delivery, validation, expiry) and is the recommended path; if you generate codes yourself and send them here, tag the request with metadata purpose: "otp" to enable the automatic one-shot re-send over an alternate SMS route on delivery failure (see the sms_otp example).

post/messages

Request

  • Base URL: https://api.envoisms.ma/v1
  • URL: https://api.envoisms.ma/v1/messages
  • Auth: HTTP bearer

Headers

Idempotency-Keystring

Unique string (max 255 chars, e.g. a UUID) making this send safe to retry: the same key replays the original response instead of sending and billing again. See the Idempotency section above.

Request body

tostring required

Destination phone in E.164 format

messagestring

Message content (max 1600 chars). See the object description for when it may be omitted on WhatsApp.

fromstring

Sender ID (alphanumeric, max 11 chars)

channel'sms' | 'whatsapp' | 'voice' | 'rcs'

Channel for message delivery: sms (default) for Moroccan operator routes; whatsapp to send from your own connected WhatsApp Business number (403 WHATSAPP_NOT_CONNECTED otherwise). To send an ordinary text to a customer who happens to use WhatsApp, sms is enough: no connection, no template, no 24-hour window. On whatsapp, a message that is not a template may only be sent to a contact who wrote to your number in the last 24 hours — otherwise it is refused with 400 OUT_OF_24H_WINDOW before any charge (with a cascade, WhatsApp is skipped and the next channel is used instead).

cascadeboolean

When true, tries WhatsApp, then falls back to SMS: at once if WhatsApp refuses the message or reports it failed (not on WhatsApp, 24-hour window closed, ...), or when no delivery report arrives within cascade_timeout (120 s by default). Only a send that actually went out is billed: a refused or failed WhatsApp message is not, and you pay for the SMS alone. A WhatsApp message still waiting for its delivery report did go out (it can still be delivered when the phone reconnects), so it is billed along with its SMS fallback, and refunded if WhatsApp later reports it failed. Tip: give your WhatsApp template a time-to-live (TTL) no longer than cascade_timeout, so a phone that comes back online does not receive both.

cascade_timeoutinteger

With cascade: seconds to wait for a delivery report before the next channel. Shorter falls back faster but bills more double sends; longer means fewer duplicates. Out of range: 400 INVALID_FIELD.

metadataobject

Custom key-value pairs, stored with the message and returned in DLR webhooks. One key carries platform semantics: set purpose: "otp" when the message carries a one-time code you generated yourself — if the network reports a hard delivery failure on a Moroccan number while the code is still fresh (within 10 minutes), the platform automatically re-sends it once over an alternate SMS route, under the same message id and at no extra charge. Prefer /verify/send when you want the whole code lifecycle (generation, delivery cascade, validation, expiry) managed for you. Set no_failover: true to opt out of this automatic re-send entirely — the first delivery attempt's outcome is then final.

phone_number_idstring

WhatsApp only. Which of your connected numbers sends; defaults to your default number.

Example request

{
  "to": "+212612345678",
  "message": "Bonjour! Votre commande #1234 est confirmée.",
  "from": "MonApp",
  "metadata": {
    "order_id": "ORD-12345",
    "customer_ref": "C-789"
  },
  "buttons": [
    {
      "type": "copy",
      "text": "Copier le code",
      "copy_code": "123456",
      "url": "https://example.com",
      "phone_number": "+212612345678"
    }
  ],
  "template": {
    "name": "order_update",
    "language": "fr"
  },
  "image": {
    "link": "https://example.com/brochure.pdf"
  },
  "video": {
    "link": "https://example.com/brochure.pdf"
  },
  "audio": {
    "link": "https://example.com/brochure.pdf"
  },
  "document": {
    "link": "https://example.com/brochure.pdf"
  },
  "sticker": {
    "link": "https://example.com/brochure.pdf"
  },
  "reaction": {
    "message_id": "wamid.HBgLMjEyNjEyMzQ1Njc4FQIAEhgg",
    "emoji": "👍"
  },
  "contacts": [
    {
      "name": {
        "formatted_name": "Service client"
      },
      "phones": [
        {
          "phone": "+212522000000",
          "type": "WORK"
        }
      ]
    }
  ],
  "location": {
    "latitude": 33.5731,
    "longitude": -7.5898,
    "name": "Agence Casablanca",
    "address": "Bd Zerktouni, Casablanca"
  },
  "context": {
    "message_id": "wamid.HBgLMjEyNjEyMzQ1Njc4FQIAEhgg"
  }
}

Response

Message queued

idstring
tostring
channel'sms' | 'whatsapp' | 'voice' | 'rcs'

sms is generally available with multi-operator routing. whatsapp sends from your own connected WhatsApp Business number (templates, text, media, interactive messages, reactions, contacts, locations) via the official WhatsApp Cloud API. voice and rcs are available on request.

cascadeboolean
statusstring
segmentsinteger
created_atstring date-time
sandboxboolean

Present and true only when the request used an env_test_ key. Nothing was delivered and nothing was charged.

Example response

{
  "id": "msg_8f2da1b2c3d4e5f6a7b8c9d0",
  "to": "+212612345678",
  "status": "queued",
  "cost": {
    "eur": 0.072,
    "mad": 0.79
  },
  "segments": 1,
  "simulated_cost": {
    "eur": 0.072,
    "mad": 0.79
  },
  "warnings": [
    {
      "code": "OUT_OF_24H_WINDOW"
    }
  ]
}

Changes

No recorded changes to this operation across all 1 revision of this API.