Traitz Sms API v1

Traitz Sms API

Send SMS to Cameroon numbers from your own software, follow every message to delivery and keep your contacts in sync. All requests and responses are JSON. Every response carries a request_id to quote when you contact support.

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

Authentication

Create a key in the dashboard under Developers. It starts with tsms_ and is shown once, so store it in a secret manager. Send it as a Bearer token. A revoked key stops working immediately.

Authorization: Bearer tsms_ab12cd34_...

Errors

Errors always have the same body. Refused messages are never charged.

{"error": "insufficient_credits", "message": "Not enough credits for this message.", "request_id": "01J..."}
HTTPerrorMeaning
400validation_failedMissing or invalid field, with a field list
401unauthorizedMissing, invalid or revoked key
402insufficient_creditsNot enough credits for this request
403sender_not_allowedSender ID not approved for this account
404not_foundNo resource with this ID in your account
409duplicate_requestSame idempotency key with a different body
422invalid_recipientNot a valid Cameroon mobile number. The same status carries recipient_opted_out and content_blocked (words or links not allowed)
429rate_limitedKey limit reached, with a Retry-After header
503service_unavailableProvider down, message not accepted

Webhooks

We POST message.submitted, message.delivered, message.failed and campaign.completed to your endpoints. Answer with any 2xx within 10 seconds. Failed deliveries are retried with growing delays for 24 hours, and you can resend any delivery from the dashboard.

Each request has X-TraitzSms-Signature, the HMAC SHA-256 hex of the raw body with your endpoint secret, and X-TraitzSms-Timestamp, also inside the signed body. Refuse requests older than 5 minutes to block replays.

$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $body, $secret);
$valid = hash_equals($expected, $_SERVER['HTTP_X_TRAITZSMS_SIGNATURE'] ?? '');
$fresh = abs(time() - (int) $_SERVER['HTTP_X_TRAITZSMS_TIMESTAMP']) < 300;

Limits

  • 120 requests per minute per key, 600 per account. Over the limit you get 429 with a Retry-After header.
  • Bulk sends take up to 1000 recipients per call.
  • Your account daily sending limit applies to the API as well as the dashboard.
  • Use an Idempotency-Key header on sends so a retried request never sends twice.

Messages

Send one SMS

POST /api/v1/messages

Queues one SMS to a Cameroon mobile number. Without "from", your own approved sender ID is used, or the shared sender while yours is in review.

Body

to
Required. Cameroon mobile number in any common format, for example 699000001 or +237699000001.
message
Required. Up to 1530 characters. GSM text fits 160 characters per SMS part, Unicode 70.
from
Optional. An approved sender ID of your account.
client_reference
Optional. Your own reference, up to 100 characters, returned in every status and webhook.
callback_url
Optional. HTTPS URL that receives this message's status webhooks.

Headers

Idempotency-Key
Optional. Repeating a key with the same body returns the first message instead of sending twice.
curl -X POST https://app.traitzsms.com/api/v1/messages \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"699000001","message":"Your order 1042 is ready for pickup.","client_reference":"order-1042"}'

Response 201

{
    "id": "5b0f6d9e-8a3c-4c2a-9f6e-1d2c3b4a5e6f",
    "to": "+237699000001",
    "from": "MYBRAND",
    "status": "queued",
    "segments": 1,
    "encoding": "gsm",
    "cost_credits": 1,
    "error_code": null,
    "client_reference": "order-1042",
    "created_at": "2026-10-29T14:00:00Z",
    "submitted_at": null,
    "delivered_at": null,
    "failed_at": null
}

Send to many numbers

POST /api/v1/messages/bulk

Up to 1000 recipients per call, with one text for all or one text each. Every recipient is accepted or refused on its own; running out of credits stops the batch.

Body

messages
Required. List of recipients: to, optional message, optional client_reference.
message
Text used for recipients without their own message.
from
Optional. An approved sender ID of your account.
curl -X POST https://app.traitzsms.com/api/v1/messages/bulk \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"Weekend promotion: 20% off everything.","messages":[{"to":"699000001"},{"to":"677000002","client_reference":"c-2"}]}'

Response 201

{
    "accepted": 1,
    "rejected": 1,
    "results": [
        {
            "index": 0,
            "id": "5b0f6d9e-8a3c-4c2a-9f6e-1d2c3b4a5e6f",
            "to": "+237699000001",
            "from": "MYBRAND",
            "status": "queued",
            "segments": 1,
            "encoding": "gsm",
            "cost_credits": 1,
            "error_code": null,
            "client_reference": "order-1042",
            "created_at": "2026-10-29T14:00:00Z",
            "submitted_at": null,
            "delivered_at": null,
            "failed_at": null
        },
        {
            "index": 1,
            "error": "invalid_recipient",
            "message": "Not a valid Cameroon mobile number."
        }
    ]
}

List messages

GET /api/v1/messages

Newest first, with cursor pagination. Pass next_cursor as cursor to get the next page.

Query

status
queued, submitted, sent, delivered or failed
from
ISO 8601 date
to
ISO 8601 date
sender
Sender ID name
client_reference
Exact reference
limit
1 to 100, default 50
cursor
From the previous page
curl -X GET https://app.traitzsms.com/api/v1/messages \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY"

Response 200

{
    "data": [
        {
            "id": "5b0f6d9e-8a3c-4c2a-9f6e-1d2c3b4a5e6f",
            "to": "+237699000001",
            "from": "MYBRAND",
            "status": "queued",
            "segments": 1,
            "encoding": "gsm",
            "cost_credits": 1,
            "error_code": null,
            "client_reference": "order-1042",
            "created_at": "2026-10-29T14:00:00Z",
            "submitted_at": null,
            "delivered_at": null,
            "failed_at": null
        }
    ],
    "next_cursor": "eyJpZCI6MTAyfQ"
}

Get one message

GET /api/v1/messages/{id}

Status, parts, cost, error code and timestamps of one message.

curl -X GET https://app.traitzsms.com/api/v1/messages/5b0f6d9e-8a3c-4c2a-9f6e-1d2c3b4a5e6f \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY"

Response 200

{
    "status": "delivered",
    "delivered_at": "2026-10-29T14:00:04Z",
    "id": "5b0f6d9e-8a3c-4c2a-9f6e-1d2c3b4a5e6f",
    "to": "+237699000001",
    "from": "MYBRAND",
    "segments": 1,
    "encoding": "gsm",
    "cost_credits": 1,
    "error_code": null,
    "client_reference": "order-1042",
    "created_at": "2026-10-29T14:00:00Z",
    "submitted_at": null,
    "failed_at": null
}

Account

List sender IDs

GET /api/v1/sender-ids

Your sender IDs and their approval status, plus the shared sender.

curl -X GET https://app.traitzsms.com/api/v1/sender-ids \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY"

Response 200

{
    "data": [
        {
            "name": "MYBRAND",
            "usage": "transactional",
            "status": "approved",
            "shared": false
        }
    ]
}

Get the balance

GET /api/v1/balance

Credits left. One credit sends one SMS part.

curl -X GET https://app.traitzsms.com/api/v1/balance \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY"

Response 200

{
    "credits": 12450,
    "approximate_sms": 12450,
    "daily_limit": 5000
}

Contacts

List contacts

GET /api/v1/contacts

Search by name or number, filter by group name, with cursor pagination.

Query

q
Name or number
group
Group name
limit
1 to 100, default 50
cursor
From the previous page
curl -X GET https://app.traitzsms.com/api/v1/contacts \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY"

Response 200

{
    "data": [
        {
            "id": "01a1...",
            "phone": "+237699000001",
            "first_name": "Awa",
            "last_name": "Ndongo",
            "opted_out": false,
            "groups": [
                "VIP"
            ]
        }
    ],
    "next_cursor": null
}

Create or update a contact

POST /api/v1/contacts

Creates the contact, or updates the names when the number is already saved. Groups are matched by name and created when missing.

Body

phone
Required. Cameroon mobile number.
first_name
Optional.
last_name
Optional.
groups
Optional. List of group names.
curl -X POST https://app.traitzsms.com/api/v1/contacts \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone":"699000001","first_name":"Awa","groups":["VIP"]}'

Response 201

{
    "id": "01a1...",
    "phone": "+237699000001",
    "first_name": "Awa",
    "last_name": null,
    "opted_out": false,
    "groups": [
        "VIP"
    ]
}

Webhooks

List webhook endpoints

GET /api/v1/webhooks

Endpoints that receive your events. Secrets are never listed.

curl -X GET https://app.traitzsms.com/api/v1/webhooks \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY"

Response 200

{
    "data": [
        {
            "id": "01a2...",
            "url": "https://example.cm/sms-events",
            "events": [
                "message.delivered",
                "message.failed"
            ],
            "active": true,
            "created_at": "2026-10-29T14:00:00Z"
        }
    ]
}

Add a webhook endpoint

POST /api/v1/webhooks

The signing secret is returned once, in this response. Store it to check the X-TraitzSms-Signature header.

Body

url
Required. HTTPS URL.
events
Required. Any of message.submitted, message.delivered, message.failed, campaign.completed.
curl -X POST https://app.traitzsms.com/api/v1/webhooks \
  -H "Authorization: Bearer $TRAITZ_SMS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.cm/sms-events","events":["message.delivered","message.failed"]}'

Response 201

{
    "id": "01a2...",
    "url": "https://example.cm/sms-events",
    "events": [
        "message.delivered",
        "message.failed"
    ],
    "active": true,
    "created_at": "2026-10-29T14:00:00Z",
    "secret": "whsec_..."
}

Traitz Sms, by Traitz Tech. Made in Cameroon.