SMS Gateway API Dashboard

API reference

Send SMS with a single HTTP request. Messages are accepted immediately, queued, and delivered as soon as capacity allows โ€” your request never blocks waiting for a carrier.

Base URL

https://smsgateway.swiftcoder.in/api/v1

All paths below are relative to this. Requests and responses are JSON; send Content-Type: application/json on anything with a body.

Authentication

Every request carries an API key. Pass it as a bearer token:

Authorization: Bearer sk_a1b2c3d4_your_key_here

Or, if a bearer header is inconvenient, as a dedicated header:

X-API-Key: sk_a1b2c3d4_your_key_here
Keys are shown once. Only a hash is stored, so a lost key cannot be recovered โ€” issue a new one and revoke the old. Keys carry scopes: messages:send to send, messages:read to read back. A key without the right scope gets 403.

A key is a bearer credential: anyone holding it can send messages at your expense. Keep it server-side โ€” never in a browser, mobile binary, or public repository.

Send a message

POST /messages

Parameters

FieldTypeDescription
tostring, required Recipient number. Use E.164 (+919140327455) โ€” spaces, dashes and brackets are accepted and stripped.
bodystring, required Message text. Longer messages are split and billed by the carrier as multiple parts.
clientRefstring, optional Your own reference for this message. Makes the request safe to retry โ€” see Idempotency.

Request

curl -X POST https://smsgateway.swiftcoder.in/api/v1/messages \
  -H "Authorization: Bearer $SMS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+919140327455",
    "body": "Your verification code is 123456",
    "clientRef": "signup-8842"
  }'
const res = await fetch("https://smsgateway.swiftcoder.in/api/v1/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SMS_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    to: "+919140327455",
    body: "Your verification code is 123456",
    clientRef: "signup-8842",
  }),
});

if (!res.ok) throw new Error(`send failed: ${res.status}`);
const message = await res.json();
console.log(message.id, message.status);
import os, requests

res = requests.post(
    "https://smsgateway.swiftcoder.in/api/v1/messages",
    headers={"Authorization": f"Bearer {os.environ['SMS_API_KEY']}"},
    json={
        "to": "+919140327455",
        "body": "Your verification code is 123456",
        "clientRef": "signup-8842",
    },
    timeout=10,
)
res.raise_for_status()
message = res.json()
print(message["id"], message["status"])
$ch = curl_init("https://smsgateway.swiftcoder.in/api/v1/messages");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("SMS_API_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "to" => "+919140327455",
        "body" => "Your verification code is 123456",
        "clientRef" => "signup-8842",
    ]),
]);
$message = json_decode(curl_exec($ch), true);
echo $message["id"], " ", $message["status"];

Response 202 Accepted

{
  "id": "6a9720e14e2f3b1b37d311d6",
  "to": "+919140327455",
  "body": "Your verification code is 123456",
  "channel": "sms",
  "status": "queued",
  "clientRef": "signup-8842",
  "attempts": 0,
  "lastError": null,
  "createdAt": "2026-09-01T19:01:02.627Z",
  "sentAt": null,
  "deliveredAt": null,
  "failedAt": null
}

202 means accepted for delivery, not delivered. Keep the id and poll it if you need the outcome.

Send in bulk

POST /messages/bulk

Up to 500 messages per request. Each entry takes the same fields as a single send and is validated on its own, so one bad number does not reject the batch.

curl -X POST https://smsgateway.swiftcoder.in/api/v1/messages/bulk \
  -H "Authorization: Bearer $SMS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      { "to": "+919140327455", "body": "Your order shipped" },
      { "to": "not-a-number",  "body": "This one is rejected" }
    ]
  }'

Response 207 Multi-Status

{
  "results": [
    { "index": 0, "status": "accepted", "message": { "id": "6a97โ€ฆ", "status": "queued" } },
    { "index": 1, "status": "rejected", "error": "invalid_recipient",
      "message": "`to` must be a phone number, ideally in E.164 form (+15551234567)." }
  ]
}

Always 207, even if every entry succeeded. Read each result by its index, which matches the order you sent.

Check a message

GET /messages/:id

Returns the message with its current state and timestamps.

curl https://smsgateway.swiftcoder.in/api/v1/messages/6a9720e14e2f3b1b37d311d6 \
  -H "Authorization: Bearer $SMS_API_KEY"
{
  "id": "6a9720e14e2f3b1b37d311d6",
  "to": "+919140327455",
  "status": "delivered",
  "attempts": 1,
  "lastError": null,
  "sentAt": "2026-09-01T19:01:02.627Z",
  "deliveredAt": "2026-09-01T19:01:04.133Z",
  "failedAt": null
}

A message you did not send with this key returns 404.

List messages

GET /messages

Your key's messages, newest first.

QueryDescription
statusFilter by state, e.g. failed
limit1โ€“200, default 50
beforePass the previous response's nextBefore to page back
curl "https://smsgateway.swiftcoder.in/api/v1/messages?status=failed&limit=20" \
  -H "Authorization: Bearer $SMS_API_KEY"
{
  "data": [ { "id": "6a97โ€ฆ", "to": "+919140327455", "status": "failed" } ],
  "nextBefore": "6a97โ€ฆ"
}

nextBefore is null on the last page. Paging is by cursor, so new messages arriving mid-scan will not shift your results.

Delivery states

A message moves forward through these states and never backwards.

StateMeaning
queued Accepted and waiting for capacity.
dispatched Being sent right now.
sent Handed to the mobile network.
delivered The network confirmed it reached the handset.
failed Terminal, after 3 attempts. lastError says why.
Treat sent as success. Delivery receipts are optional for carriers and many never send one, so a delivered message can sit at sent forever. Waiting for delivered before you act will strand a large share of perfectly good traffic.

Failures are retried automatically up to 3 times before a message is marked failed; a send that goes unconfirmed for 120 seconds is returned to the queue and tried again. You do not need to implement retries yourself.

Idempotency

Network timeouts leave you unsure whether a message was accepted. Resending blindly risks a duplicate. Send a clientRef โ€” any string unique to that message in your own system โ€” and a repeat of the same request returns the original message instead of sending a second one.

{ "to": "+919140327455", "body": "Your code is 123456", "clientRef": "signup-8842" }

Scoped to your API key, so your references cannot collide with anyone else's. The response is the first message โ€” including its original body โ€” so a changed body under a reused reference is not sent.

Errors

Failures return the matching HTTP status and a JSON body with a stable error code and a human-readable message. Branch on the code, not the text.

{ "error": "invalid_recipient", "message": "`to` must be a phone number, ideally in E.164 form (+15551234567)." }
StatusCodeMeaning
400invalid_recipientMissing or unparseable to
400invalid_bodyMissing or empty body
400invalid_channelUnknown channel requested
400too_many_messagesMore than 500 in one bulk request
401missing_api_keyNo key on the request
401invalid_api_keyUnknown or revoked key
403insufficient_scopeKey lacks the required scope
404not_foundNo such message under this key

A 4xx will not succeed on retry โ€” fix the request. A 5xx is safe to retry, and safest with a clientRef.

Health

GET /health

Unauthenticated liveness check, suitable for a monitor.

curl https://smsgateway.swiftcoder.in/api/v1/health
{ "ok": true, "uptime": 1284.51 }