Developers
API Documentation
Everything you need to send messages and verify OTPs — based on the Tasdeeqly Client API & Integration Guide, V1.1.
YOUR_CLIENT_ID
and YOUR_CLIENT_SECRET
with the credentials from your onboarding — never share your client secret publicly.
Authentication
Every request is authenticated with two headers:
X-Client-Id
and X-Client-Secret,
issued during onboarding. Keep your secret key confidential — server-to-server
integration is recommended.
curl --location 'https://api.tasdeeqly.com/api/v1/messages' \
--header 'Content-Type: application/json' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'X-Client-Secret: YOUR_CLIENT_SECRET' \
--data '{
"mobileNo": "+923001234567",
"channel": "SMS",
"smsType": "TRANSACTIONAL",
"text": "Your order #12345 has been confirmed.",
"reference": "ORDER-12345",
"network": "UFONE"
}' Send a Message
Available
Sends an SMS or WhatsApp message to a single mobile number.
channel is
optional — if missing or null, Tasdeeqly treats the request as SMS. WhatsApp is
supported where enabled for your account.
POST /api/v1/messages
{
"mobileNo": "+923001234567",
"channel": "SMS",
"smsType": "TRANSACTIONAL",
"text": "Your order #12345 has been confirmed.",
"reference": "ORDER-12345",
"network": "UFONE"
} POST /api/v1/messages
{
"mobileNo": "+923001234567",
"channel": "WHATSAPP",
"smsType": "TRANSACTIONAL",
"text": "Your order #12345 has been confirmed.",
"reference": "ORDER-12345"
} HTTP/1.1 201 Created
{
"reference": "ORDER-12345",
"messageId": "MSG-3f9a1c2e-...",
"statusCode": 2001,
"statusMessage": "Message submitted successfully."
} | Field | Required | Description |
|---|---|---|
| mobileNo | Yes | Recipient mobile number |
| channel | No | SMS or WHATSAPP; default is SMS |
| smsType | Yes for normal messages | TRANSACTIONAL or PROMOTIONAL |
| text | Yes for normal messages | Message content |
| reference | Yes | Your business/reference value |
| network | No | Optional network/operator information |
reference
is returned unchanged. messageId
is generated by Tasdeeqly and can be used for tracking and reconciliation.
statusCode
is a numeric code (see Error Handling for the full list) — 2001 corresponds to
SUBMITTED.
A successful request always returns HTTP 201 Created; the numeric
statusCode
in the body confirms the specific outcome.
Message Types
Your account can be configured to allow transactional messages, promotional messages, or both.
| Type | Typical use |
|---|---|
| TRANSACTIONAL | Order confirmation, payment notification, delivery update, account notification |
| PROMOTIONAL | Offers, campaigns, marketing and promotional communication |
Character & Unit Rules — V1
V1 supports English/GSM-7 characters only. Unicode, Urdu, Arabic, and other character sets are not supported in V1.
| Message length | SMS units |
|---|---|
| 1–160 characters | 1 unit |
| 161–306 characters | 2 units |
| 307–459 characters | 3 units |
| 460–612 characters | 4 units |
| 613+ characters | Rejected |
Tasdeeqly does not automatically split messages in V1. A message above 612 characters
is rejected before sending (MESSAGE_TOO_LONG).
Length is measured in GSM-7 septets, not raw character count. Extended-set characters
(such as ^ { } [ ] ~ | €)
cost 2 septets each, so a message using these characters can reach a unit boundary
sooner than its visible character count suggests. Any character outside the
supported GSM-7 set is rejected with
UNSUPPORTED_CHARACTERS
rather than being auto-converted.
The calculated number of units is deducted from the client's SMS balance and is
fixed at submission time. WhatsApp messages are not subject to the
SMS unit table above — every accepted WhatsApp message consumes a flat 1 WhatsApp
unit, up to a maximum of 4,096 characters (rejected with
MESSAGE_TOO_LONG
beyond that).
Bundles & Units
Clients purchase communication bundles. A bundle may contain SMS units, WhatsApp units, or both. SMS and WhatsApp balances are managed separately. When a new bundle is purchased, its units are added to the client's existing balance.
Request OTP
AvailableGenerates and delivers a one-time code to a mobile number, for use cases such as verifying a customer's mobile number during order or account creation.
POST /api/v1/otp/request
{
"mobileNo": "+923001234567",
"reference": "ORDER-12345",
"network": "UFONE"
} HTTP/1.1 201 Created
{
"reference": "ORDER-12345",
"messageId": "OTP-7c1e2a9b-...",
"statusCode": 2002,
"statusMessage": "OTP sent successfully.",
"coolPeriod": 60,
"maxAttempts": 3,
"remainingAttempts": 2
}
The response returns the cooldown period
(coolPeriod,
in seconds), the configured resend limit
(maxAttempts)
and how many resend requests remain
(remainingAttempts)
so your UI can show the appropriate information.
Verify OTP
AvailableValidate the code entered by the user against the mobile number and reference from the request step.
POST /api/v1/otp/verify
{
"mobileNo": "+923001234567",
"reference": "ORDER-12345",
"otpCode": "482913"
} HTTP/1.1 201 Created
{
"reference": "ORDER-12345",
"statusCode": 2003,
"statusMessage": "OTP verified successfully.",
"verifyMaxAttempts": 5,
"remainingVerificationAttempts": 5
} verifyMaxAttempts
is the configured verification-attempt limit. On a successful verify,
remainingVerificationAttempts
reflects the full limit again; on a failed attempt
(INVALID_OTP),
the same field reports how many verification attempts remain before the reference is locked.
When the configured verification-attempt threshold is reached, further verify calls
against that reference return
OTP_VERIFICATION_LIMIT.
Separately, if a mobile number is locked, the initial waiting period is 15 minutes;
repeated exhaustion progressively increases the waiting period — 15, 30, 45, 60
minutes and onward — and any request made inside that window returns
OTP_LOCKED.
Reset Mobile / OTP Lock
AvailableIf a mobile number becomes locked because the configured OTP attempt threshold has been exceeded, the client can request a reset for that mobile number.
POST /api/v1/otp/reset-mobile
{
"mobileNo": "+923001234567"
} HTTP/1.1 201 Created
{
"statusCode": 2000,
"statusMessage": "OTP state reset for this mobile number."
}
This response has no reference
or messageId
field — the reset is scoped to the client + mobile number, not a specific OTP
request. Authentication identifies the client, so the reset applies only to that
client's mobile number. It clears the active OTP lock/cooldown state so the client
can request OTP again according to its configured policy, and does not affect other
clients, previous OTP records, message history, or communication balances.
Idempotency
AvailableTasdeeqly protects against accidental duplicate submissions after a message has been successfully submitted — automatically, with no special header required. The logical identity of a message is based on Client + Reference + Message.
If the same successfully submitted message is sent again, Tasdeeqly returns the existing result instead of submitting another message. If the original submission failed before succeeding, retrying is allowed.
Automatic Fallback & Reliability
AvailableIf a network/operator communication route experiences a temporary failure, Tasdeeqly can automatically use an alternative available route where configured, without requiring any change to your integration. Fallback is handled transparently — you continue using the same API and don't need to know which communication route was used.
Delivery Status
Tasdeeqly tracks standardized delivery status based on delivery information received from the communication network.
| Status | Meaning |
|---|---|
| SUBMITTED | Message accepted for processing |
| DELIVERED | Message delivery confirmed |
| FAILED | Message delivery failed |
Network Parameter
The network
field is optional and can be sent with messages and OTP requests. It may be useful
for operator-specific requirements, routing information, or future communication
requirements. If your integration doesn't need it, you can omit the field.
{ "network": "UFONE" } White-Label Shortcode / Masking
PlannedTasdeeqly can provide white-label sender options for clients that require their own brand identity when messages are delivered. Depending on the supported channel, country, operator, and applicable commercial/regulatory requirements, this may include shortcode, sender masking, or other approved sender-ID arrangements — configured with Tasdeeqly during onboarding. Availability, sender format, approval requirements, and applicable charges vary by network and local regulations. White-label configuration does not change your API integration.
Service Availability and Maintenance
Tasdeeqly may temporarily suspend or degrade SMS or WhatsApp service globally, or
for an individual client, for maintenance, operational issues, or service
degradation. Your integration does not need to change — the API returns a
standardized response (SERVICE_UNAVAILABLE)
indicating the service is temporarily unavailable or degraded.
Error Handling
Every response body includes a numeric statusCode
and a human-readable statusMessage.
The numeric code is always consistent with the HTTP status of the response. On
error, the response follows the same envelope shape:
{
"statusCode": 4010,
"statusMessage": "Invalid client credentials.",
"code": "AUTHENTICATION_FAILED"
} | Code | Numeric | HTTP | Meaning |
|---|---|---|---|
| VALIDATION_ERROR | 4000 | 400 | Request body failed validation (missing/malformed field) |
| INVALID_OTP | 4001 | 400 | OTP code is incorrect |
| OTP_EXPIRED | 4002 | 410 | OTP has expired |
| OTP_REFERENCE_NOT_FOUND | 4003 | 404 | No active OTP found for this client + reference + mobile number |
| OTP_ALREADY_VERIFIED | 4004 | 201 | Reference was already verified; treated as an idempotent no-op |
| UNSUPPORTED_CHARACTERS | 4005 | 400 | Message contains characters outside the supported GSM-7 set in V1 |
| MESSAGE_TOO_LONG | 4006 | 400 | SMS exceeds 612 characters, or WhatsApp exceeds 4,096 characters |
| AUTHENTICATION_FAILED | 4010 | 401 | Invalid Client ID or Secret Key |
| INSUFFICIENT_UNITS | 4020 | 402 | Not enough SMS/WhatsApp units |
| CLIENT_SUSPENDED | 4030 | 403 | Client service is disabled |
| CHANNEL_DISABLED | 4031 | 403 | Requested channel is not enabled |
| MESSAGE_TYPE_DISABLED | 4032 | 403 | Requested message type — or OTP — is not enabled for this client |
| NOT_FOUND | 4040 | 404 | Requested resource/route not found |
| DUPLICATE_REQUEST | 4090 | 409 | Conflicting duplicate request |
| RATE_LIMIT_EXCEEDED | 4290 | 429 | Configured request rate limit reached |
| OTP_COOLDOWN | 4291 | 429 | OTP request is currently in cooldown |
| OTP_ATTEMPT_LIMIT | 4292 | 429 | OTP resend limit reached |
| OTP_VERIFICATION_LIMIT | 4293 | 429 | OTP verification limit reached |
| OTP_LOCKED | 4294 | 429 | Mobile number is inside an escalating lock window after repeated limit exhaustion |
| INTERNAL_ERROR | 5000 | 500 | Unexpected server error |
| PROVIDER_COMMUNICATION_FAILED | 5020 | 502 | Message could not be completed through the available communication routes |
| SERVICE_UNAVAILABLE | 5030 | 503 | Tasdeeqly service temporarily unavailable |
OTP_ALREADY_VERIFIED
also returns HTTP 201 (not a 4xx) because re-verifying an already-verified reference
is treated as an idempotent no-op — the body's numeric statusCode (4004) still lets
your integration distinguish it from a fresh verification.
Message-lifecycle and success statuses that may also appear in
statusCode:
OK (2000), SUBMITTED (2001), OTP_SENT (2002), OTP_VERIFIED (2003), PENDING (2005),
DELIVERED (2006). Provider-specific outcomes (for example a route-level rejection or
timeout) may also surface as additional numeric codes configured per provider during
onboarding.
Recommended Integration Flow
Normal message:
1. Customer action / business event
2. Your backend calls Tasdeeqly
3. Tasdeeqly authenticates your client
4. Request and service permissions are validated
5. SMS length/units are calculated
6. Available balance is checked
7. Tasdeeqly processes the message
8. Tasdeeqly returns reference/requestId/messageId
9. Delivery information is processed
10. Final status becomes DELIVERED or FAILED Ready to integrate?
Get API access and start sending your first verification today.