SMSGateway
Sign in Read the docs

SMS API

Send a message.
Know it landed.

One HTTP call puts a message on the wire. We queue it, retry it up to 3 times, and hand back a delivery state you can act on — no polling a black box, no guessing whether it went out.

Idempotent sends · Automatic retries · Delivery receipts

POST /api/v1/messages 202
{
  "to": "+919140327455",
  "body": "Your code is 481920",
  "clientRef": "signup-8842"
}
  1. 19:01:02.418 queued accepted, waiting for capacity
  2. 19:01:02.627 sent handed to the mobile network
  3. 19:01:04.133 delivered receipt confirmed · 1.7s

Retries you don't write

A message that fails goes back in the queue and is tried again. Your code sends once.

Safe to retry

Send your own reference and a repeated request returns the original message, never a duplicate.

Receipts, not hope

Every message carries a state and a timestamp, from accepted through to confirmed on the handset.

How it works

Three steps to your first message

  1. 01

    Create a key

    Issue a key from the dashboard and scope it to send, read, or both. Keys are shown once and revocable at any time.

  2. 02

    Post a message

    A recipient and a body is the whole payload. You get a 202 and an id back immediately — no waiting on a carrier.

  3. 03

    Follow it home

    Fetch the id to see where it got to, or watch the whole stream in the dashboard with failure reasons attached.

The whole integration
// Send an OTP and keep the id.
  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 code is ${code}`,
      clientRef: `signup-${user.id}`,
    }),
  });

  const { id, status } = await res.json();

Prefer Python, PHP or plain cURL? Every endpoint is written up in the API reference.

What you get

Built for the parts you'd rather not build

A queue that holds the line

Traffic spikes and quiet capacity are our problem. Messages wait in order and go out as soon as there is room.

Idempotency by reference

Attach your own clientRef. A timed-out request can be replayed without sending a second message.

Honest delivery states

Queued, sent, delivered, failed — with the error text attached when something goes wrong, so you can act on it.

Bulk in one call

Up to 500 messages per request, each validated on its own. One bad number never rejects the batch.

Keys with scopes

Separate keys per service, each limited to sending or reading, revocable the moment one leaks.

A dashboard that explains

Daily volume, success rate, and the failure reasons ranked — plus one-click retry on anything that didn't make it.

Where it's used

Messages people are waiting for

One-time codes

Sign-in and verification, where a late message is a lost customer.

Order and delivery updates

Dispatched, out for delivery, arriving now — sent as they happen.

Reminders and alerts

Appointments, payment due dates, and anything your system needs acknowledged.

Pricing

Pay for what you send

No seat licences and no monthly minimum. Start free, and the rate falls as volume rises.

Starter

₹0 to begin

For a side project or a proof of concept.

  • 1,000 messages included
  • Full API access
  • Delivery receipts
  • Email support
Get a key

Scale

Talk to us

For high volume and custom terms.

  • Negotiated per-message rate
  • Dedicated capacity
  • Custom retention
  • Direct line to an engineer
Start a conversation

Questions

Before you integrate

What does a successful send actually mean?

A 202 means we've accepted the message, not that it has arrived. Watch the state: sent means it reached the mobile network, and that is the point most integrations should treat as success. Delivery receipts are optional for carriers, so waiting for delivered will leave a share of perfectly good messages unconfirmed.

Do I need to write retry logic?

No. A failed send is requeued and tried again up to 3 times before it is marked failed, with the reason attached. Send once and read the state.

What if my request times out?

Send a clientRef and replay it. The same reference returns the original message rather than sending a second one, so a retry can never double-charge your customer's phone.

How do I know what went wrong?

Errors return a stable code and a plain-language message, and a failed message keeps its lastError. The dashboard ranks failure reasons so you can see a pattern rather than one-off noise.

Your first message is a curl away.