Developers

Public API

Send SMS, email and WhatsApp, run campaigns, verify OTPs and read your balance over a simple HTTP API. Every error is machine-readable with a stable code — the full reference is below.

Getting started

All endpoints are served under:

https://api-s1.textdigo.com/api/v0

Requests and responses are JSON (except multipart file uploads). Send the header x-locale: fr or en to localize error messages.

Authentication

Authenticate every request with HTTP Basic using your apiLogin as the username and your apiKey as the password (found in Settings → Organization → API).

curl -u "apiLogin:apiKey" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumber":"+237670000000","message":"Hello"}' \
  https://api-s1.textdigo.com/api/v0/sms/message

Responses & errors

Errors share one shape. statusCode is the HTTP status, errorCode is a stable machine-readable string (see the reference), message is human-readable, and details[] lists per-field problems for validation errors.

{
  "statusCode": 422,
  "errorCode": "PUBLIC_API_INVALID_PHONE_NUMBER",
  "message": "The phone number 0670 is not a valid international number",
  "details": [],
  "timestamp": "2026-06-10T10:00:00.000Z",
  "path": "/api/v0/sms/message"
}

Send messages

POST/sms/messagetest send

Send an SMS to one number.

FieldTypeInDescription
phoneNumber*string (E.164)bodyRecipient number in international format, e.g. +237670000000.
message*string (≤2000)bodyMessage body.
senderNamestring (≤50)bodyApproved sender ID.
smsTypeenum TRANSACTIONAL|MARKETINGbodyBilling tier (default TRANSACTIONAL).
externalIdstringbodyYour reference, echoed in webhooks.

Possible errors: PUBLIC_API_INVALID_PHONE_NUMBER (422), PUBLIC_API_UNSUPPORTED_PHONE_NUMBER (422)

POST/email/messagebillable

Send an email.

FieldTypeInDescription
email*string (email)bodyRecipient email address.
subject*string (≤998)bodyEmail subject.
htmlMessagestringbodyHTML body.
textMessagestringbodyPlain-text body.

Possible errors: PUBLIC_API_INVALID_EMAIL (422)

POST/email/template/messagebillable

Send a templated email.

FieldTypeInDescription
email*string (email)bodyRecipient email address.
subject*stringbodyEmail subject.
templateId*stringbodyTemplate identifier.
parametersobject<string,string>bodyTemplate variable values.

Possible errors: PUBLIC_API_INVALID_EMAIL (422), PUBLIC_API_TEMPLATE_NOT_FOUND (404)

POST/whatsapp-business/messagebillable

Send a WhatsApp Business message.

FieldTypeInDescription
whatsappBusinessPhoneNumberId*stringbodyYour WhatsApp sender id.
phoneNumber*string (E.164)bodyRecipient number in international format, e.g. +237670000000.
messagestring (≤4096)bodyText body (within the 24h window).
mediaUrlstring (url)bodyPublic URL of an attachment.

Possible errors: PUBLIC_API_INVALID_PHONE_NUMBER (422), PUBLIC_API_WAB_ACCOUNT_NOT_FOUND (404)

POST/whatsapp-business/otp/messagebillable

Send a WhatsApp OTP message.

FieldTypeInDescription
whatsappBusinessPhoneNumberId*stringbodyYour WhatsApp sender id.
phoneNumber*string (E.164)bodyRecipient number in international format, e.g. +237670000000.

Possible errors: PUBLIC_API_INVALID_PHONE_NUMBER (422), PUBLIC_API_WAB_ACCOUNT_NOT_FOUND (404)

POST/whatsapp-business/template/messagebillable

Send a WhatsApp template message.

FieldTypeInDescription
whatsappBusinessPhoneNumberId*stringbodyYour WhatsApp sender id.
phoneNumber*string (E.164)bodyRecipient number in international format, e.g. +237670000000.
templateId*stringbodyApproved template id.
bodyParametersobject<string,string>bodyBody variable values.

Possible errors: PUBLIC_API_INVALID_PHONE_NUMBER (422), PUBLIC_API_TEMPLATE_NOT_FOUND (404), PUBLIC_API_WAB_ACCOUNT_NOT_FOUND (404)

POST/api-campaign/send-smsbillable

Send one SMS to many contacts (bulk).

FieldTypeInDescription
message*stringbodyMessage body.
contacts*string[] (≤1000)bodyRecipient numbers; invalid ones are skipped and reported.
senderNamestringbodyApproved sender ID.

Possible errors: PUBLIC_API_INVALID_RECIPIENTS (422)

GET/api-campaign/send-smsbillable

Bulk SMS (query-param variant).

FieldTypeInDescription
message*stringqueryMessage body.
contacts*string (comma-separated)queryComma-separated numbers.

Possible errors: PUBLIC_API_INVALID_RECIPIENTS (422)

Delivery status

GET/message/{channel}/status/{msgId}read-only

Get a message delivery status.

FieldTypeInDescription
channel*enum sms|email|whatsapppathChannel of the message.
msgId*stringpathThe msgId returned at send time.

Possible errors: PUBLIC_API_MESSAGE_NOT_FOUND (404)

GET/message/sms/{msgId}read-only

Get full SMS details.

FieldTypeInDescription
msgId*stringpathThe msgId returned at send time.

Possible errors: PUBLIC_API_MESSAGE_NOT_FOUND (404)

Account & usage

GET/integration/usageread-only

Usage & quota snapshot.

GET/integration/walletread-only

Wallet balance & recent transactions.

GET/integration/canalsread-only

List your channels.

FieldTypeInDescription
typeenum CanalTypequeryFilter by channel type.
limitnumberqueryPage size (default 50).

Resources

POST/integration/campaignsbillable

Create and launch a campaign.

FieldTypeInDescription
campaignSpecId*uuidbodyMessage template id.
profileIds*uuid[]bodyContact list ids.
frequency*enum CampaignFrequencybodySend cadence.
POST/integration/campaign-specsbillable

Create a message template.

FieldTypeInDescription
name*string (≤200)bodyTemplate name.
type*enum CampaignSpecTypebodyChannel type (SMS, EMAIL…).
configobjectbodyChannel-specific config.
POST/integration/campaign-profilesbillable

Create a contact list.

FieldTypeInDescription
name*string (≤200)bodyList name.
type*enum CampaignProfileTypebodyList source type.
campaignSpecType*enum CampaignSpecTypebodyChannel the list targets.
POST/integration/campaign-profiles/{id}/contacts/importbillable

Import contacts into a list.

FieldTypeInDescription
id*uuidpathContact list id.
contacts*object[] (≤10000)bodyArray of { phoneNumber?, email?, parameters? }.
POST/integration/ticketsbillable

Create a ticket.

FieldTypeInDescription
canalType*enum TicketCanalTypebodyChannel of the ticket.
descriptionstring (≤2000)bodyTicket description.
POST/integration/customersbillable

Create a contact.

FieldTypeInDescription
namestringbodyContact name.
phoneNumbersstring[]bodyPhone numbers.
emailsstring[] (email)bodyEmail addresses.
POST/integration/groupsbillable

Create a contact group.

FieldTypeInDescription
name*stringbodyGroup name.

One-time passwords

POST/otp/smsbillable

Send an SMS OTP.

FieldTypeInDescription
phoneNumber*string (E.164)bodyRecipient number in international format, e.g. +237670000000.
numberOfDigitsint 4–8bodyCode length (default service value).

Possible errors: PUBLIC_API_INVALID_PHONE_NUMBER (422)

POST/otp/sms/verifyread-only

Verify an SMS OTP.

FieldTypeInDescription
phoneNumber*string (E.164)bodyRecipient number in international format, e.g. +237670000000.
otpCode*string (3–10)bodyThe code the user received.

Possible errors: PUBLIC_API_OTP_CONTACT_NOT_FOUND (404)

POST/otp/whatsappbillable

Send a WhatsApp OTP.

FieldTypeInDescription
phoneNumber*string (E.164)bodyRecipient number in international format, e.g. +237670000000.

Possible errors: PUBLIC_API_INVALID_PHONE_NUMBER (422)

POST/otp/whatsapp/verifyread-only

Verify a WhatsApp OTP.

FieldTypeInDescription
phoneNumber*string (E.164)bodyRecipient number in international format, e.g. +237670000000.
otpCode*string (3–10)bodyThe code the user received.

Possible errors: PUBLIC_API_OTP_CONTACT_NOT_FOUND (404)

POST/otp/emailbillable

Send an email OTP.

FieldTypeInDescription
email*string (email)bodyRecipient email address.

Possible errors: PUBLIC_API_INVALID_EMAIL (422)

POST/otp/email/verifyread-only

Verify an email OTP.

FieldTypeInDescription
email*string (email)bodyRecipient email address.
otpCode*string (3–10)bodyThe code the user received.

Possible errors: PUBLIC_API_OTP_CONTACT_NOT_FOUND (404)

Files & tickets

POST/issuebillable

Create a support ticket (multipart).

FieldTypeInDescription
email*string (email)multipartRecipient email address.
issueCanalType*enum SMS|WHATSAPP|EMAILmultipartReply channel.
issueMessagestringmultipartThe issue text.
filebinarymultipartOptional attachment.

Possible errors: PUBLIC_API_INVALID_EMAIL (422), PUBLIC_API_FILE_TOO_LARGE (413)

Webhooks

Configure per-channel callback URLs in Settings → Organization → API. Every call is a POST signed with X-TextDigo-Signature: sha256=HMAC_SHA256(webhookSecret, rawBody) — verify it against your webhookSecret.

Delivery reports

{ "msgId": "...", "from": "...", "status": "DELIVERED",
  "partCount": 1, "amount": 0.02, "operator": "...",
  "externalId": "...", "currency": "XAF", "subject": "dlr", "type": "sms" }

status ∈ DELIVERED | UNDELIVERED | SENT | FAILED

Inbound messages

{ "event": "inbound-message", "type": "sms", "lineId": "...",
  "phoneNumber": "...", "chatId": "...", "message": "...", "medias": [] }

Error codes

Branch on errorCode, not on the human message (which is localized). Codes migrating from the legacy Meteor API show their old numeric code.

Authentication

CodeHTTPMeaningHow to fix
API_KEY_MISSING_CREDENTIALS401Missing API credentials.No Authorization header (or token) was supplied.Send Authorization: Basic base64(apiLogin:apiKey).
API_KEY_INVALID_CREDENTIALS401Invalid API credentials.The apiLogin/apiKey pair does not match any account.Copy the keys from Settings → Organization → API.
API_KEY_ORG_NOT_ACTIVE403Organization is not active.The account is suspended or cancelled.Reactivate the account or contact support.

Validation

CodeHTTPMeaningHow to fix
VALIDATION_FAILED422One or more fields are invalid.A field is missing, the wrong type, too long, or unknown.Read the per-field details[] array in the response.
PUBLIC_API_INVALID_PHONE_NUMBERwas #3001422The phone number is not a valid international number.The number is not parseable in E.164.Use the full international form, e.g. +237670000000.
PUBLIC_API_UNSUPPORTED_PHONE_NUMBERwas #3002422No active operator serves this number.The destination country/operator is not enabled on your account.Check your enabled coverage or contact support.
PUBLIC_API_INVALID_EMAILwas #3003422The email address is not valid.The address failed format validation.Provide a syntactically valid address.
PUBLIC_API_INVALID_RECIPIENTS422None of the supplied recipients are valid.Every number in a bulk request failed validation.Send at least one valid E.164 number.
PUBLIC_API_FILE_REQUIREDwas #101422A file is required.The multipart request carried no file part.Attach the file under the "file" field.
PUBLIC_API_FILE_TOO_LARGE413The file exceeds the maximum size.The upload is over the per-file limit.Compress or split the file under the limit.

Resources

CodeHTTPMeaningHow to fix
PUBLIC_API_MESSAGE_NOT_FOUND404Message not found.The msgId does not belong to your account.Use the msgId returned by the send call.
PUBLIC_API_OTP_CONTACT_NOT_FOUND404No pending OTP for this contact.No OTP was sent, or it expired.Send a new OTP before verifying.
PUBLIC_API_WAB_ACCOUNT_NOT_FOUND404No WhatsApp Business sender matches the id.whatsappBusinessPhoneNumberId is wrong or not connected.Use an id from your connected WhatsApp channels.
PUBLIC_API_TEMPLATE_NOT_FOUND404Template not found.The templateId is unknown in your account.List your templates and use a valid id.
PUBLIC_API_CANAL_NOT_ACTIVEwas #501422The target channel is not active.The channel exists but is disabled.Activate the channel in the dashboard.

Rate limiting

CodeHTTPMeaningHow to fix
RATE_LIMITED429Too many requests.You exceeded the per-key request budget.Back off and retry after a short delay.

Server

CodeHTTPMeaningHow to fix
INTERNAL_ERRORwas #100500Unexpected server error.Something failed on our side.Retry later; contact support if it persists.

Limits & quotas

  • Rate limiting: requests are throttled per API key — back off on 429 (RATE_LIMITED).
  • Bulk SMS: up to 1000 contacts per /api-campaign/send-sms call.
  • Contact import: up to 10 000 contacts per import call.
  • File uploads are capped by the per-file size limit (PUBLIC_API_FILE_TOO_LARGE otherwise).