Moorsyl Docs

SMS API

Send text messages to any Mauritanian phone number with a single API call.

The SMS API lets you send messages to any Mauritanian number. Messages are queued immediately and delivered through Mauritania-optimized carrier routing.

Requires a secret key (sk_…). See API Keys.

Send a message

POST /api/sms

Request headers

HeaderValue
x-api-keyYour secret API key
Content-Typeapplication/json

Request body

FieldTypeRequiredDescription
tostringyesRecipient phone number — must be a valid Mauritanian number in +222XXXXXXXXX format
fromstringnoSender ID, 1–11 characters. Defaults to MOORSYL. See Alpha Sender ID
bodystringyesMessage text, 1–1600 characters
idempotencyKeystringno8–128 character string to prevent duplicate sends

Response

FieldTypeDescription
acceptedbooleantrue when the message has been queued for delivery
messageIdstringUnique message ID you can use with POST /api/sms/get
idempotencyKeystringThe idempotency key used (provided or generated)
organizationIdstringThe organization the message was charged to
fromstringThe sender ID the message is sent with
noticeobjectOnly present when your from sender ID is still awaiting approval. The message was sent from MOORSYL instead. Contains code (SENDER_PENDING_APPROVAL), requestedFrom and a readable message

Example

Send an SMS
curl -X POST https://api.moorsyl.com/api/sms \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_..." \
  -d '{
    "to": "+22236551999",
    "from": "MyBrand",
    "body": "Your order #1042 has been shipped."
  }'
Response
{
  "accepted": true,
  "messageId": "2a8df28b-9b7e-4f8a-aafd-21f8ef34f4e1",
  "idempotencyKey": "a3b4c5d6-...",
  "organizationId": "org_...",
  "from": "MyBrand"
}

If MyBrand is still awaiting approval, the message is still sent, from MOORSYL, and the response tells you:

Response (sender ID awaiting approval)
{
  "accepted": true,
  "messageId": "2a8df28b-9b7e-4f8a-aafd-21f8ef34f4e1",
  "idempotencyKey": "a3b4c5d6-...",
  "organizationId": "org_...",
  "from": "MOORSYL",
  "notice": {
    "code": "SENDER_PENDING_APPROVAL",
    "requestedFrom": "MyBrand",
    "message": "Sent from the default sender MOORSYL because your sender ID \"MyBrand\" isn't approved yet. Messages will switch to \"MyBrand\" automatically once it's ready."
  }
}

Keep sending with from: "MyBrand": once it's approved, messages switch to it automatically.

Phone number format

Only Mauritanian numbers are accepted. The number must start with +222, followed by a digit 2, 3, or 4, then 7 more digits:

+222[2-4]XXXXXXX
ExampleValid
+22221234567✓ Mauritel
+22231234567✓ Mattel
+22241234567✓ Chinguitel
+22251234567✗ Invalid prefix
22221234567✗ Missing +
+2221234567✗ Too short

Idempotency

Supply an idempotencyKey to ensure a message is only sent once even if you retry the request. If a request with the same key has already been accepted, the API returns the original response without queuing a new message.

If you omit idempotencyKey, one is generated and returned in the response.

curl -X POST https://api.moorsyl.com/api/sms \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_..." \
  -d '{
    "to": "+22236551999",
    "from": "MyBrand",
    "body": "Your code is 847291",
    "idempotencyKey": "otp-user42-20240101T120000"
  }'

Good idempotency keys include the user ID and a timestamp or attempt counter so they are unique per intent but stable across retries.

Poll message status

Use the messageId returned by POST /api/sms to fetch the latest delivery state.

curl -X POST https://api.moorsyl.com/api/sms/get \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_..." \
  -d '{
    "messageId": "2a8df28b-9b7e-4f8a-aafd-21f8ef34f4e1"
  }'

Delivery events

When a message is sent or fails, Moorsyl fires a webhook event. Set up a Webhook endpoint to receive sms.sent and sms.failed events and trigger downstream actions in your system.

Errors

StatusCodeReason
400BAD_REQUESTInvalid input (bad phone number, empty body, body too long), or SENDER_NOT_APPROVED when from was rejected or isn't on your account
401UNAUTHORIZEDMissing or invalid API key
402PAYMENT_REQUIREDInsufficient organization balance
403FORBIDDENAPI key is not linked to an active organization
429TOO_MANY_REQUESTSRate limit exceeded

On this page