API documentation

Error codes

HTTP status tells you what kind of problem it is; the message tells you what to fix.

StatusMeaningTypical messageWhat to do
400Bad requestMissing required fields: to, message
Insufficient balance
Invalid phone number
Fix the payload; top up if balance is low.
401UnauthenticatedMissing API key · Invalid API key
Missing required headers: X-Timestamp, X-Signature
Request timestamp expired or invalid · Invalid signature
Check the key, and for OTP endpoints re-sign with a fresh millisecond timestamp and the exact body string.
403ForbiddenAPI key does not have the required scope
IP address not allowed
Daily spend limit reached
Ask support to adjust scopes, whitelist or limits.
404Not foundMessage not found · Contact not found · Unknown endpointCheck the id / path.
405Method not allowedUse the method listed in the reference.
429Rate limitedToo many requests, please try again laterBack off until RateLimit-Reset; batch with /sms/bulk.
500Server errorFailed to …Retry with the same Idempotency-Key; contact support if it persists.
502 / 503Service unavailableMessaging service temporarily unavailableRetry with back-off (we are usually back within seconds).

Handling pattern

retry.js
async function send(payload, attempt = 1) {
  const res = await fetch('https://tiansms.com/api/v1/sms/send', {
    method: 'POST',
    headers: { 'x-api-key': KEY, 'Content-Type': 'application/json', 'Idempotency-Key': payload.idempotencyKey },
    body: JSON.stringify(payload.body)
  });
  const json = await res.json();
  if (res.ok && json.success) return json.data;
  if ((res.status === 429 || res.status >= 500) && attempt < 4) {
    await new Promise(r => setTimeout(r, 500 * 2 ** attempt));
    return send(payload, attempt + 1);
  }
  throw new Error(json.message || ('HTTP ' + res.status));
}

Message-level failures

An accepted message can still fail later (handset off for days, number ported, DND). You will see status: "failed" with error_message on /sms/status/{id} or an sms.failed webhook. Failed messages are refunded automatically.