Skip to content

Developers

An SMS API that gets out of your way.

Send messages and verification codes with one HTTPS request. JSON in, JSON out, clear errors and signed webhooks.

Send your first SMS

Create an API key in your dashboard, then make one request. The response comes back right away with an ID you can track.

https://app.traitzsms.com/api/v1

Response · 201

{
  "id": "5b0f6d9e-8a3c-4c2a-9f6e-1d2c3b4a5e6f",
  "to": "+237699000001",
  "status": "queued",
  "segments": 1,
  "cost_credits": 1,
  "client_reference": "order-4821",
  "created_at": "2026-10-29T14:00:00Z"
}
curl https://app.traitzsms.com/api/v1/messages \
  -H "Authorization: Bearer tsms_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-4821-1" \
  -d '{"to":"+237699000001","from":"MYSHOP","message":"Your order #4821 is on its way.","client_reference":"order-4821"}'

Endpoints

POST/messages
POST/messages/bulk
GET/messages
GET/messages/{id}
GET/sender-ids
GET/balance

Built for production

Idempotency keys

Retry safely. The same key never sends twice.

Priority for codes

OTP messages use their own queue, ahead of bulk campaigns.

Client references

Attach your own order or user ID and find any message by it.

OpenAPI file

Generate a client in your language from our OpenAPI 3.1 file.

Webhooks you can trust

We call your URL when a message is submitted, delivered or fails. Each call is signed with your endpoint secret and carries a timestamp, so you can reject fakes and replays. Failed calls are retried for 24 hours.

  • message.submitted
  • message.delivered
  • message.failed
  • campaign.completed

Verify a webhook signature

import crypto from 'node:crypto'

// rawBody: the exact bytes we sent, before JSON parsing.
function isFromTraitzSms(rawBody, headers, secret) {
  const timestamp = Number(headers['x-traitzsms-timestamp'])
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false // replay

  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
  const received = headers['x-traitzsms-signature'] || ''
  return expected.length === received.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))
}

Errors you can act on

HTTPerror
400validation_failedA field is missing or invalid
401unauthorizedThe API key is missing, invalid or revoked
402insufficient_creditsNot enough credits for this request
403sender_not_allowedThis sender ID is not approved for you
409duplicate_requestSame idempotency key, different body
422invalid_recipientNot a valid Cameroon mobile number
429rate_limitedLimit reached, see the Retry-After header
503service_unavailableTemporary problem, safe to retry
Read the full docs

Ready when you are

Your first message can go out today.

Create your account, top up with mobile money and send in minutes.

  • MTN, Orange, Nexttel, Camtel
  • Pay with MoMo or Orange Money
  • Live delivery reports