AdaSMS.ma API documentation

Send SMS to Moroccan numbers from your application: a JSON REST API, one key per application, examples ready to copy.

Create an account Go to my account https://api.adasms.ma/v1
Contents

Introduction

The AdaSMS.ma API sends single or bulk SMS to Moroccan numbers, lets you track every message, share documents through secure links (AdaLink) and check your balance. Your systems can also be notified in real time by webhook.

Base URL

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

Every request uses HTTPS. Request and response bodies are JSON (except AdaLink file uploads, which use multipart/form-data).

Response format

Every response contains success (true or false). On error, message explains the problem and, for errors your code should handle, code gives a stable value (see Error codes).

iError messages (message) are written in French. In your code, rely on the HTTP status and the code field, never on the message text.

Authentication

Every request carries your API key in the X-API-Key header. Create your keys in your customer area, API Keys menu: one key per application, which you can disable at any time.

http
X-API-Key: adasms_YOUR_KEY

A key is made of adasms_ followed by 48 hexadecimal characters.

!The key is shown only once, when it is created. Keep it on your server (environment variable, secrets vault) and never embed it in a mobile app or a web page. If you lose it, create a new key and disable the old one.

Authentication errors

HTTP statusCodeCause
401—Missing X-API-Key header
401—Unknown, disabled or malformed key
403—Account suspended
403SENDER_EXPIREDKey linked to an expired or inactive Sender ID
429RATE_LIMITEDMore than 20 malformed keys from the same IP address within 10 minutes

Phone numbers

AdaSMS.ma only sends to Moroccan numbers. Three formats are accepted everywhere (single send, bulk send, AdaLink); spaces, dashes, dots and brackets are ignored. Numbers are stored and returned in the +212XXXXXXXXX format.

FormatExampleStored as
+212XXXXXXXXX+212600000001+212600000001
212XXXXXXXXX212600000001+212600000001
0XXXXXXXXX06 00 00 00 01+212600000001

An unreadable number returns a 400 error. A foreign number (for example +33…) returns a 400 error with the code NON_MOROCCAN_NUMBER, and nothing is debited; in a bulk send, the whole request is then rejected.

Segments and encoding

An SMS is billed per segment. The number of segments depends on the text length and its encoding, which is detected automatically:

Encoding1 segmentSeveral segments
GSM-7 (standard alphabet)160 characters153 characters per segment
Unicode / UCS-2 (Arabic, emojis, some accents)70 characters67 characters per segment

A text is limited to 10 segments (1,530 GSM-7 characters or 670 in Unicode); beyond that, the API returns 400 TEXT_TOO_LONG. In GSM-7, the characters ^ { } \ [ ] ~ | € count twice.

iA single character outside the GSM-7 alphabet switches the whole text to Unicode. Common pitfalls: ê â î ô û ë ï ç. With gsm_replace: true, these characters are replaced with their GSM-7 equivalent before sending.

Rate limits

POST /messages, POST /bulk and GET /account are limited per 60-second window:

ScopeLimit per 60 s window
Per API key600 requests
Per IP address1,200 requests

Beyond that, the API returns 429 with the code RATE_LIMITED and the Retry-After header (delay in seconds). To send many messages, prefer POST /bulk (up to 1,000 recipients per request). Need a higher limit? Write to support@adasms.ma.

API reference

Send an SMS

POST/v1/messages

Sends an SMS to a Moroccan number. The cost is debited when the message is sent (your plan's unit price × number of segments). If the operator rejects the message, the amount is credited back to your balance.

Subject to rate limiting. See ›

Request body

JSON body.

FieldTypeRequiredDescription
tostringYesMoroccan number: +212XXXXXXXXX, 212XXXXXXXXX or 0XXXXXXXXX (spaces, dashes, dots and brackets ignored). Converted to the +212XXXXXXXXX format.
textstringYesSMS text, at most 10 segments (1,530 GSM-7 characters or 670 in Unicode). See “Segments and encoding”.
fromstring—Your approved Sender ID (sender name). Required as soon as you have at least one approved Sender ID. Without an approved Sender ID, leave it empty: the shared sender is used for a limited number of trial messages. If your API key is linked to a Sender ID, that one is always used.
typestring—Free label (e.g. otp, alert, promo), kept on the message and in webhooks. Default: transactional
referencestring—Your own reference (printable ASCII, 64 characters maximum), to find your messages with GET /messages?reference=….
gsm_replaceboolean—Replaces common Unicode characters with their GSM-7 equivalent before sending (ê→e, ç→c, «→", —→-, …→...). The stored text is the replaced text. Default: false

Request

bash
curl -X POST "https://api.adasms.ma/v1/messages" \
  -H "X-API-Key: adasms_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "+212600000001",
  "text": "Your verification code: 847291",
  "from": "MyService",
  "type": "otp",
  "reference": "ORDER-2026-001"
}'

Response 202

Message accepted.

json
{
  "success": true,
  "messageId": "3f6c2a91-5b7e-4d0a-9c1e-2b8f4e6d7a10",
  "status": "sent",
  "providerMessageId": "9a8b7c6d-0000-4e1f-8a2b-3c4d5e6f7a8b",
  "cost": "0.4900",
  "channel": "sms",
  "downgraded": false,
  "segments": 1,
  "encoding": "GSM7",
  "reference": "CMD-2026-001"
}
Response fields
FieldTypeDescription
messageIdstring
statusstringsent = handed to the operator; queued = waiting to be handed over. Values: queued, sent
providerMessageIdstringIdentifier assigned by the operator.
coststringAmount debited in MAD excl. VAT (price per segment × segments), 4 decimals.
providerstringDeprecated Technical field kept for compatibility; its value may change without notice. Do not use it.
channelstringValues: sms
downgradedbooleantrue if the message was sent by SMS although a rule on your account planned another channel.
segmentsinteger
encodingstringValues: GSM7, UCS2
referencestring | null

Errors

HTTP statusCodeCause
400—to or text missing
400—Unreadable number (accepted formats, see “Phone numbers”)
400NON_MOROCCAN_NUMBERNumber outside Morocco
400—Invalid reference (printable ASCII, 64 characters maximum)
400TEXT_TOO_LONGText longer than 10 segments
400DEFAULT_SENDER_FORBIDDENfrom missing although you have an approved Sender ID
400DEFAULT_SENDER_QUOTA_EXCEEDEDTrial messages with the shared sender used up
401, 403—Missing or invalid API key, suspended account, key's Sender ID expired: see Authentication.
402INSUFFICIENT_CREDITInsufficient balance
403EMAIL_NOT_VERIFIEDAccount email address not confirmed
429RATE_LIMITEDRate limit reached
502—Sending failed

Search by reference

GET/v1/messages

Returns your messages whose reference field exactly matches the given value: at most 100, newest first.

Query parameters

FieldTypeRequiredDescription
referencestringYesReference given when sending.

Request

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

Response 200

Matching messages (possibly empty list).

json
{
  "success": true,
  "messages": [
    {
      "id": "3f6c2a91-5b7e-4d0a-9c1e-2b8f4e6d7a10",
      "to": "+212600000001",
      "from": "MyService",
      "type": "otp",
      "channel": "sms",
      "status": "sent",
      "text": "Your verification code: 847291",
      "cost": "0.49",
      "billingOutcome": "charged",
      "segments": 1,
      "encoding": "GSM7",
      "reference": "CMD-2026-001",
      "providerMessageId": "9a8b7c6d-0000-4e1f-8a2b-3c4d5e6f7a8b",
      "errorMessage": null,
      "createdAt": "2026-11-10T09:00:00.000Z",
      "updatedAt": "2026-11-10T09:00:01.200Z"
    }
  ]
}
Response fields
FieldTypeDescription
messagesarray<object>
messages[].idstring
messages[].tostringNumber in +212XXXXXXXXX format.
messages[].fromstring | null
messages[].typestring
messages[].channelstringValues: sms
messages[].statusstringqueued = waiting; sent = handed to the operator; delivered = delivered to the phone (operator-dependent, not available yet); failed = failed. Values: queued, sent, delivered, failed
messages[].textstring
messages[].coststringAmount debited in MAD excl. VAT ("0" if sending failed).
messages[].providerstring | nullDeprecated Technical field kept for compatibility; do not use it.
messages[].billingOutcomestringcharged = billed; refunded = credited back after an incident; not_charged = rejected before sending, not billed. Values: charged, refunded, not_charged
messages[].segmentsinteger
messages[].encodingstringValues: GSM7, UCS2
messages[].referencestring | null
messages[].providerMessageIdstring | null
messages[].errorMessagestring | nullFailure reason, free text.
messages[].createdAtstring
messages[].updatedAtstring

Errors

HTTP statusCodeCause
400—Missing reference parameter
401, 403—Missing or invalid API key, suspended account, key's Sender ID expired: see Authentication.

Retrieve a message

GET/v1/messages/{messageId}

Returns one of your messages.

Path parameters

FieldTypeRequiredDescription
messageIdstringYesIdentifier returned when sending (messageId).

Request

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

Response 200

The message.

json
{
  "success": true,
  "message": {
    "id": "3f6c2a91-5b7e-4d0a-9c1e-2b8f4e6d7a10",
    "to": "+212600000001",
    "from": "MyService",
    "type": "otp",
    "channel": "sms",
    "status": "sent",
    "text": "Your verification code: 847291",
    "cost": "0.49",
    "billingOutcome": "charged",
    "segments": 1,
    "encoding": "GSM7",
    "reference": "CMD-2026-001",
    "providerMessageId": "9a8b7c6d-0000-4e1f-8a2b-3c4d5e6f7a8b",
    "errorMessage": null,
    "createdAt": "2026-11-10T09:00:00.000Z",
    "updatedAt": "2026-11-10T09:00:01.200Z"
  }
}
Response fields
FieldTypeDescription
messageobject
message.idstring
message.tostringNumber in +212XXXXXXXXX format.
message.fromstring | null
message.typestring
message.channelstringValues: sms
message.statusstringqueued = waiting; sent = handed to the operator; delivered = delivered to the phone (operator-dependent, not available yet); failed = failed. Values: queued, sent, delivered, failed
message.textstring
message.coststringAmount debited in MAD excl. VAT ("0" if sending failed).
message.providerstring | nullDeprecated Technical field kept for compatibility; do not use it.
message.billingOutcomestringcharged = billed; refunded = credited back after an incident; not_charged = rejected before sending, not billed. Values: charged, refunded, not_charged
message.segmentsinteger
message.encodingstringValues: GSM7, UCS2
message.referencestring | null
message.providerMessageIdstring | null
message.errorMessagestring | nullFailure reason, free text.
message.createdAtstring
message.updatedAtstring

Errors

HTTP statusCodeCause
401, 403—Missing or invalid API key, suspended account, key's Sender ID expired: see Authentication.
404—Message not found

Send bulk SMS

POST/v1/bulk

Sends up to 1,000 SMS in one request, with a common text or one text per recipient. Numbers accept the same formats as single sends. Duplicates (once converted to +212 format) are sent only once. The total cost is checked and debited before sending; each message rejected by the operator is credited back. If a single number is invalid or outside Morocco, the whole request is rejected and nothing is debited.

Subject to rate limiting. See ›

Request body

JSON body.

FieldTypeRequiredDescription
recipientsarray<string | object>YesNumbers, or {to, text, reference} objects. 1,000 at most.
recipients[].tostringYesMoroccan number: +212XXXXXXXXX, 212XXXXXXXXX or 0XXXXXXXXX (spaces, dashes, dots and brackets ignored). Converted to the +212XXXXXXXXX format.
recipients[].textstring—Text for this recipient (otherwise the common text).
recipients[].referencestring—Your own reference (printable ASCII, 64 characters maximum), to find your messages with GET /messages?reference=….
textstring—Common text, required if a recipient has no text of its own.
fromstring—Your approved Sender ID (same rules as POST /messages).
typestring—Free label. Default: bulk
gsm_replaceboolean—GSM-7 replacement applied to every text (see POST /messages). Default: false

Request

Common text

bash
curl -X POST "https://api.adasms.ma/v1/bulk" \
  -H "X-API-Key: adasms_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "recipients": [
    "+212600000001",
    "0600000002",
    "212600000003"
  ],
  "text": "Your order #4521 has shipped.",
  "from": "MyShop"
}'

One text per recipient

bash
curl -X POST "https://api.adasms.ma/v1/bulk" \
  -H "X-API-Key: adasms_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "from": "MyShop",
  "recipients": [
    {
      "to": "+212600000001",
      "text": "Hello Karim, your balance is 250 MAD.",
      "reference": "CUS-001"
    },
    {
      "to": "0600000002",
      "text": "Hello Salma, your balance is 80 MAD.",
      "reference": "CUS-002"
    }
  ]
}'

Response 202

Batch processed. Each message's details are available with GET /bulk/{batchId}.

json
{
  "success": true,
  "batchId": "7c1d9e20-4a3b-4f6e-8d2c-1a0b9c8d7e6f",
  "total": 3,
  "status": "completed",
  "estimatedCost": "1.4700"
}
Response fields
FieldTypeDescription
batchIdstring
totalintegerNumber of recipients once duplicates are removed.
statusstringfailed if every message failed. Values: completed, failed
estimatedCoststringAmount debited before sending, in MAD excl. VAT; failed messages are credited back.

Errors

HTTP statusCodeCause
400—recipients missing or empty
400—More than 1,000 recipients
400—Unreadable number or missing text (details per recipient in errors)
400NON_MOROCCAN_NUMBERNumber outside Morocco (details per recipient in errors)
400—Invalid reference (printable ASCII, 64 characters maximum)
400TEXT_TOO_LONGText longer than 10 segments
400DEFAULT_SENDER_FORBIDDENfrom missing although you have an approved Sender ID
400DEFAULT_SENDER_QUOTA_EXCEEDEDTrial messages with the shared sender used up
401, 403—Missing or invalid API key, suspended account, key's Sender ID expired: see Authentication.
402INSUFFICIENT_CREDITInsufficient balance
403EMAIL_NOT_VERIFIEDAccount email address not confirmed
429RATE_LIMITEDRate limit reached
502—Sending failed

Retrieve a batch

GET/v1/bulk/{batchId}

Returns one of your batches and the status of each of its messages.

Path parameters

FieldTypeRequiredDescription
batchIdstringYesIdentifier returned when sending (batchId).

Request

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

Response 200

The batch, its messages and their count.

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

Errors

HTTP statusCodeCause
401, 403—Missing or invalid API key, suspended account, key's Sender ID expired: see Authentication.
404—Batch not found

Account balance

GET/v1/account

Returns your account's balance, plan, billing mode and the price of one SMS segment.

Subject to rate limiting. See ›

Request

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

Response 200

Account information.

json
{
  "success": true,
  "account": {
    "name": "My Company",
    "plan": "starter",
    "billingMode": "prepaid",
    "balance": "549.8100",
    "currency": "MAD",
    "smsUnitPrice": "0.4900",
    "estimatedSmsRemaining": 1122
  }
}
Response fields
FieldTypeDescription
accountobject
account.namestring
account.planstringPlan code (starter, business, enterprise).
account.billingModestringValues: prepaid, postpaid
account.balancestringBalance in MAD excl. VAT, 4 decimals, same as the dashboard.
account.currencystringValues: MAD
account.smsUnitPricestringPrice of one SMS segment on your plan, in MAD excl. VAT.
account.estimatedSmsRemaininginteger | nullNumber of one-segment GSM-7 SMS the balance covers (integer part of balance ÷ smsUnitPrice); 0 if the balance is zero or negative; null for postpaid accounts.

Errors

HTTP statusCodeCause
401, 403—Missing or invalid API key, suspended account, key's Sender ID expired: see Authentication.
429RATE_LIMITEDRate limit reached

Webhooks

A webhook notifies your server of an event (SMS sent, SMS failed, bulk send or campaign finished) with a JSON POST request. Create it in your customer area, Webhooks menu: an HTTPS receiving URL and the events you want. The signing secret is shown only once, when the webhook is created (or when you generate a new one).

Headers sent

HeaderValue
Content-Typeapplication/json
X-AdaSMS-EventEvent name, for example message.sent
X-AdaSMS-TimestampTime the request was sent (ISO 8601)
X-AdaSMS-Signaturesha256= followed by the HMAC-SHA256 signature of the raw body, computed with your secret

Verify the signature (Node.js)

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

function isValidSignature(rawBody, secret, header) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return header.length === expected.length
    && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

// Read the raw body: the signature covers the bytes received.
app.post('/webhooks/adasms', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('X-AdaSMS-Signature') || '';
  if (!isValidSignature(req.body, process.env.ADASMS_WEBHOOK_SECRET, header)) {
    return res.sendStatus(401);
  }
  const event = JSON.parse(req.body.toString('utf8'));
  console.log(event.event, event.data);
  res.sendStatus(200);
});

Verify the signature (PHP)

php
<?php
$body     = file_get_contents('php://input');
$header   = $_SERVER['HTTP_X_ADASMS_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $body, getenv('ADASMS_WEBHOOK_SECRET'));

if (!hash_equals($expected, $header)) {
    http_response_code(401);
    exit;
}
$event = json_decode($body, true);
http_response_code(200);

Verify the signature (Python)

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

app = Flask(__name__)

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

Response and retries

Reply with a 2xx status within 10 seconds. Otherwise (error, timeout), AdaSMS.ma sends the same event again 1 minute and then 5 minutes later: 3 attempts in total. Process events idempotently (for example with messageId), as the same event may arrive twice.

Events

EventSent when
message.sentAn SMS sent with POST /messages has been handed to the operator.
message.failedAn SMS sent with POST /messages was rejected; its amount has been credited back (cost is "0.0000").
batch.completedA bulk send started from the dashboard (or a campaign) has finished. Batches sent with POST /bulk are processed during the request: they do not trigger this webhook, as the response already contains their result.
campaign.completedA campaign has finished (status completed) or was stopped while sending (status stopped).
campaign.failedA scheduled campaign could not start at its scheduled time (for example insufficient balance); nothing was debited.

message.sent — SMS handed to the operator

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

message.failed — SMS failed

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

batch.completed — Bulk send finished

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

campaign.completed — Campaign finished

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

campaign.failed — Scheduled campaign not started

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

Error codes

Stable values of the code field, to use in your code. Other errors have no code: rely on the HTTP status.

CodeHTTP statusDescription
NON_MOROCCAN_NUMBER400The number is not a Moroccan number (+212 followed by 9 digits). Nothing is debited.
TEXT_TOO_LONG400The text is longer than 10 segments (1,530 GSM-7 characters or 670 in Unicode).
DEFAULT_SENDER_FORBIDDEN400You have an approved Sender ID, so the shared sender is no longer available; set from.
DEFAULT_SENDER_QUOTA_EXCEEDED400Your trial messages with the shared sender are used up; request your Sender ID.
INSUFFICIENT_CREDIT402Insufficient balance. Nothing is debited; top up your account.
EMAIL_NOT_VERIFIED403The account's email address is not confirmed; sending is blocked until it is.
SENDER_EXPIRED403The API key is linked to an expired or inactive Sender ID; renew it or change the key.
RATE_LIMITED429Too many requests; wait for the delay given in the Retry-After header.

Pricing

Prepaid credit, with no commitment or subscription. The price of an SMS depends on your plan and is counted per segment (see Segments and encoding). The amount is debited when sending and credited back if the operator rejects the message.

PlanPrice per segmentVolume
Starter0.49 MAD excl. VATfewer than 10,000 SMS/month
Business0.35 MAD excl. VAT10,000 to 99,999 SMS/month
Enterprise0.30 MAD excl. VAT100,000+ SMS/month

Price per link, based on how long it stays valid: each day is billed at its band's rate. The SMS carrying the link is charged on top, at your plan's price.

ValidityPrice per day excl. VATExample
1 to 7 days1.40 MAD1 d = 1.40 · 7 d = 9.80 MAD
8 to 14 days0.70 MAD14 d = 14.70 MAD
15 to 30 days0.30 MAD30 d = 19.50 MAD
More than 30 daysOn quotation—

GET /account returns the price of one segment on your plan (smsUnitPrice) and your balance.

Quick start

  1. Create your account on app.adasms.ma and confirm your email address: sending is blocked until it is confirmed.
  2. Create an API key in the API Keys menu and copy it (it will not be shown again).
  3. Send your first SMS:
bash
curl -X POST https://api.adasms.ma/v1/messages \
  -H "X-API-Key: adasms_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": "0600000001", "text": "Hello from AdaSMS.ma"}'

A 202 response with "success": true confirms the send. Without an approved Sender ID, leave from empty: the shared sender is used for your trial messages. To send under your own name, request a Sender ID from your customer area.

In your customer area only

Your API keys, webhook secrets, message history, invoices and Sender IDs are managed in your customer area, app.adasms.ma. A question? support@adasms.ma.

🍪 This site uses cookies to improve your experience and analyse traffic.