Skip to content
Claim your free business email

SMS API: what it is, what to look for, and how to send your first text

Published Updated 13 min readBy the Rasket team

Written for developers and startup founders

SMS API for developers: a phone sending a message bubble to a server and a check mark coming back.

The short answer

An SMS API is a web endpoint that sends a text message when your code asks it to, and tells you afterwards what happened to it. You send a phone number and the words; the provider holds the number the text comes from, hands the message to the phone networks, and posts a webhook when it is delivered, fails, or the person replies.

Sending one text is the easy part. What separates one SMS API from another is everything around it: whether a retry can text someone twice, whether STOP is handled for you, which kinds of number you can text from, how consent is recorded, and what a message costs once it is longer than 160 characters. This guide covers those first, then sends a real text with curl and Node.

What is an SMS API?

A text message API is the programmable side of the phone networks. Your application makes an HTTPS request with a destination number and a body. The provider checks the request, picks the number to send from, and submits the message to a carrier network, which delivers it to the handset. Status reports and replies flow back the other way and reach you as webhooks.

The traffic it carries has a name in the industry: application-to-person, or A2P. That matters because carriers treat it differently from texts between two people. Since A2P traffic is where spam comes from, the networks want to know who is sending, from which number, and why, before they deliver it. Much of what an SMS API does for you is that paperwork: registering your number, keeping the opt-out list, and refusing a text that would get your number filtered.

An SMS API for developers also has to fit the code you already have. The useful ones work like a modern email API: a JSON body, a bearer API key, idempotency keys, signed webhooks, and an object per message that you can read back later. If you have sent email through an API, sending a text should feel the same, which is the idea behind sending both from one account.

What to look for in an SMS API

Delivery webhooks you can act on

A text is not done when the API answers. It is accepted, then sent, then delivered, or it fails, and only the carrier knows which. You want a webhook for each step, signed so you can trust it, with a reason when a text fails: a landline, a number that no longer works, a message the carrier filtered. Rasket sends six SMS events, from sms.queued to sms.delivered and sms.failed, plus sms.received for replies and contact.sms_unsubscribed for opt-outs, signed the same way as its email webhooks (the SMS webhooks page has the payloads).

Idempotency, because a duplicate text is worse than a duplicate email

Networks drop responses. If your code times out and sends again, a careless API texts the person twice, and a second one-time code or a second “your order shipped” is confusing at best. Look for an Idempotency-Key header: the same key within a window returns the first answer instead of sending again. On POST /sms it holds for 24 hours, a replay carries Idempotent-Replayed: true, and the same key with a different body is refused with 409 invalid_idempotent_request, so a bug cannot reuse a key for a new text. The idempotent sends post shows the retry loop; it is the same for texts.

The provider should be careful on its side too. When a hand-off to the carrier times out, Rasket does not resubmit it, because a second submission could reach the phone twice. It waits for the carrier's late report instead, and marks the text failed, and unbilled, if none arrives within the hour.

Consent and opt-out handled below the API

US law treats a text like a call. Under the FCC's rules a marketing text sent with automated equipment needs the person's prior express written consent. A person may revoke consent by any reasonable means, a reply of STOP, QUIT, END, REVOKE, OPT OUT, CANCEL or UNSUBSCRIBE counts as one on its own, and the sender has at most ten business days to honour it. Canada's anti-spam law requires consent for commercial messages as well. An SMS API should keep that record for you and stop texts the moment someone opts out.

In Rasket, SMS consent is its own fact on the contact, recorded with where and how the person agreed and the words they saw, and kept as proof for five years. STOP and its synonyms stop every text from your project to that phone, transactional ones included; only the person can undo it, by texting START. HELP is answered for you with your business name and how to stop. Consent and STOP has the details.

The kinds of number you can text from

The number a text comes from decides who it can reach and how long you wait before you can send. In the US and Canada there are three kinds:

SMS number kinds
KindReachesPrice in RasketBefore you can send
Toll-freeUS and CanadaFirst one included on paid plans, then $2 a month eachVerification of the number
Local (10DLC)US$2 a month, plus $15 a month for your business's registrationYour business and one campaign registered
Short codeUS and CanadaOn Enterprise, by contractSet up with us

Start with toll-free: it reaches both countries, and it is the only way to text people in Canada from an application. Registration usually takes 1 to 5 business days. While yours is in review you are not stuck: Rasket lets you text your own verified phones from its shared test number straight away, with [Test] in front, so you can build and test the whole flow before the approval comes back.

Throughput

Carriers set how fast each registered number may send, and a local number's registration also carries a daily cap. An SMS API should queue your texts and pace them to the number's rate rather than fail the ones above it. Rasket queues every text per number and sends at that number's rate; a campaign that reaches a daily cap carries the rest to the next day instead of failing them. For a burst of transactional texts, POST /sms/batch takes up to 100 in one request.

US and Canada rules

  • Destinations. +1 is not only the US and Canada: the Caribbean shares it. Rasket accepts US and Canadian mobile numbers and answers anything else, including toll-free and premium numbers, with 422 unsupported_destination.
  • Who you are. Every text starts with your brand, “Acme: ”, added when the text does not already start with it. Canada's law asks every commercial message to identify the sender, and US carriers expect it.
  • Marketing texts go out only between 8 am and 9 pm where the person is, or the shorter hours some states set, at most once in any 16 hours, and always end with “Reply STOP to opt out”. A text due outside those hours waits for the morning.
  • Links. Carriers filter public link shorteners, so Rasket refuses them. Use your own short-link domain.

A price per message you can read before you send

A message is up to 160 characters (70 if it has an emoji or another special character). A longer text is sent and billed as several messages. That is the unit every SMS price is in, so the question to ask is what one message costs and how the API tells you the count. On Rasket's Pro plans a message past the ones included costs $0.015, falling to $0.0125 on the largest Scale plans; Pro 50k includes 200 texts a month, and a picture message is billed as 3 messages ($0.045 on Pro). Free has 50 test texts a month to your own phones. Every text the API returns says how many messages it was and what it cost, a failed text is never charged, and POST /sms/estimate counts one before you send it. The plans themselves are on the pricing page, and SMS pricing answers the questions about texts.

Send a text with the Rasket SMS API

These are the steps from nothing to a delivered text on your own phone, before any number of yours is approved. They follow the SMS quickstart.

  1. Give a key SMS access — In the dashboard, give an API key SMS access: Send to send, and Send and manage on a full-access key to add test phones. A key limited to one domain cannot text.
  2. Add your phone as a test phone — Call POST /sms/verified-phones with your mobile number in E.164 form; Rasket texts it a 6-digit code from its shared test number.
  3. Confirm the code — Call POST /sms/verified-phones/{id}/verify with the code. Until a number of yours is approved, texts can only go to verified phones like this one.
  4. Send the text — Call POST /sms with to, text and an Idempotency-Key header, so a retry within 24 hours returns the first answer instead of texting twice.
  5. Read it back or take the webhook — Read GET /sms/{id} until status is delivered or failed, or subscribe a webhook endpoint to sms.delivered and sms.failed.

1. Give a key SMS access

Every API key starts with no SMS access, so an admin gives one access under API keys in the dashboard. Sending needs Send, on a sending_access or full_access key. Adding a test phone, the next step, needs a full_access key with Send and manage. A key limited to one sending domain cannot send texts.

2. Add your phone and confirm the code

Rasket texts the phone a 6-digit code from the shared test number. Confirm it with the id the first call returned.

curl -X POST "https://api.rasket.com/sms/verified-phones" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "phone": "+14155550123"
}'
curl -X POST "https://api.rasket.com/sms/verified-phones/{verified_phone_id}/verify" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "481922"
}'

3. Send the text

The only required field is to, in E.164 form, plus text for anything that is not a picture message. category is transactional unless you say marketing; a marketing text needs the contact's SMS consent and keeps to the daytime hours above. from is optional: leave it out and the text comes from your default number for the destination's country, or from the shared test number until you have one.

curl -X POST "https://api.rasket.com/sms" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042-shipped" \
  -d '{
  "to": "+14155550123",
  "text": "Your order #1042 has shipped.",
  "category": "transactional",
  "tags": {
    "order": "1042"
  }
}'

The same request from Node, with the built-in fetch:

const response = await fetch("https://api.rasket.com/sms", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
    "User-Agent": "acme-billing/1.0",
    "Content-Type": "application/json",
    "Idempotency-Key": "order-1042-shipped",
  },
  body: JSON.stringify({
    to: "+14155550123",
    text: "Your order #1042 has shipped.",
    category: "transactional",
    tags: {
      order: "1042"
    }
  }),
});

const { id } = await response.json();

The answer is the text itself. text is the whole text as sent, brand prefix included; segments is how many messages it was billed as; price_each and cost are in dollars; and included is true when it came out of your plan's monthly texts.

{
  "object": "sms",
  "id": "01928c3e-5b7a-7c1e-9a2f-3d4e5f60718a",
  "status": "queued",
  "from": "+18335550199",
  "to": "+14155550123",
  "text": "Acme: Your order #1042 has shipped.",
  "category": "transactional",
  "encoding": "gsm7",
  "segments": 1,
  "price_each": "0.015",
  "cost": "0.015",
  "currency": "usd",
  "included": true,
  "scheduled_at": null,
  "created_at": "2026-10-19T20:41:00.000Z",
  "tags": {
    "order": "1042"
  }
}

4. Read it back, or wait for the webhook

status moves from queued to sent to delivered, or to failed with a reason. Poll the text while you build; in production, subscribe a webhook endpoint to the SMS events instead.

curl -X GET "https://api.rasket.com/sms/{sms_id}" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

One more error worth handling

A 429 sms_quota_exceeded means the month's texts are used up: Free's test texts, your plan's allowance with pay-as-you-go off, or your SMS spend cap. Retrying it will not help, so surface it rather than looping.

After the send: delivery, failures and replies

Most of an SMS integration is the webhook handler. Three events deserve code of their own:

  • sms.failed carries failed.type and failed.reason. A landline or a number that cannot take texts fails, is never charged, and is put on your SMS suppression list so you do not pay to try it again. A text Rasket skipped by rule, such as one to a phone that opted out, arrives here too, with failed.type set to skipped.
  • sms.received is a reply that is not a keyword. Route it to a person or a support queue; replies are free.
  • contact.sms_unsubscribed fires on any opt-out, by keyword, by the carrier or from the dashboard. Mirror it in your own database so no other system of yours texts that phone.

A text from a campaign or an automation carries its broadcast_id or automation_run_id, so one handler can serve every source. The way to verify the signature is the one email webhooks use.

SMS or email: which one to send

A text is read within minutes and is short by nature. An email can carry a receipt, a table, an attachment and a link to everything else, and it costs a fraction of a text. Most products need both, and the useful question is which one each message belongs in.

When to send a text and when to send an email
MessageBetter asWhy
Sign-in or verification codeSMSNeeded now, on the phone in their hand
Order shipped, out for deliverySMS, plus emailTime-sensitive; the email keeps the details
Appointment reminderSMSA day before or an hour before, when an email may go unread
Receipt or invoiceEmailA record with line items and an address
Password reset linkEmail, or SMS with a codeA link is safer in the inbox the account is tied to
Newsletter, product newsEmailLong, and texts are for what cannot wait
Flash sale, back in stockEither, with consentA marketing text needs SMS consent and daytime hours

A rule that holds up: text when a minute matters or the person is away from a screen, and email when they will want to read it again. When one event earns both, send the email for the record and a one-line text that points to it. The transactional SMS guide has templates for the texts, with their message counts.

SMS in Rasket

Rasket sends texts from the same API key, contacts and webhooks you use for email. A contact can have a phone and no address. A campaign can be an email or a text. An automation can text a contact as one of its steps, beside its emails. Consent, STOP, quiet hours and the 16-hour rule are enforced below the API, so a campaign, an automation and a direct call all follow the same rules.

Texts reach phones in the United States and Canada. The SMS page shows what is included, and the SMS reference lists every field and error.

Frequently asked questions

What is the difference between an SMS API and an MMS API?

SMS carries text only; MMS adds an image. In Rasket they are one endpoint: add media_urls with up to 10 JPEG, PNG or GIF images, 1 MB in all, and the text becomes a picture message billed as 3 messages. Picture messages reach US numbers only for now.

How much does it cost to send a text through an SMS API?

Providers price per message, and a message is one segment of up to 160 characters, or 70 with an emoji. On Rasket's Pro plans a message past the included ones costs $0.015, falling to $0.0125 on the largest Scale plans. A failed text is never charged.

Can I send texts to Canada with an SMS API?

Yes, from a toll-free number. Canadian carriers filter application traffic on local numbers, so toll-free is the way to reach Canadian phones from an application, and one toll-free number can be your default for both the US and Canada. Local numbers are for the US only.

Can I test an SMS API before my number is approved?

With Rasket, yes. Registration usually takes 1 to 5 business days, and meanwhile you can text your own verified phones from Rasket's shared test number. Those texts start with [Test], so you can build the whole flow, webhooks included, while you wait for the approval.

What happens when someone replies STOP to a text?

Rasket stops every text from your project to that phone, transactional ones included, and sends a contact.sms_unsubscribed webhook. UNSUBSCRIBE, CANCEL, END and QUIT work the same way, and only the person can undo it, by texting START. A later send to that phone is accepted and skipped, and never charged.

Should I text from a toll-free number or a local 10DLC number?

Start with toll-free. It reaches the US and Canada, and the first one is included on paid plans. A local number reaches the US only, costs $2 a month and needs your business registered for $15 a month. Pick local when your customers expect a number in their own area code.

Sources

  1. 47 CFR § 64.1200: Delivery restrictions — Legal Information Institute, Cornell Law School, read 2026-10-25
  2. Messaging Principles and Best Practices (May 2023) — CTIA, read 2026-10-25
  3. An Act to promote the efficiency and adaptability of the Canadian economy (S.C. 2010, c. 23), section 6 — Justice Laws Website, Government of Canada, read 2026-10-25
  4. Rasket docs: SMS quickstart — Rasket, read 2026-10-25
  • SMS — Text US and Canadian phones from the API you send email with: one key, the same contacts and webhooks, consent and STOP handled, a price per message in dollars.
  • SMS — Transactional and marketing texts on the API, contacts and automations you use for email. Consent, STOP and HELP handled, priced per message in dollars.
  • SMS quickstart — Send your first text to a US or Canadian phone.
  • Get a number — Toll-free or local numbers, and the registration carriers require.
  • Consent and STOP — Who you may text, the proof you keep, and replies like STOP.
  • SMS pricing — Texts included in each plan, the price per message, and number fees.
  • Transactional SMS: rules, examples and templates — What makes a text transactional rather than marketing, the consent each needs, templates with their character and message counts, and how to send one.
  • Idempotent email sends: retry without sending twice — How to make email sends idempotent and stop duplicate emails: choosing an Idempotency-Key, a tested retry loop, keys for agents, and what each repeat returns.

Start sending this morning

Sign up, verify a domain and send your first email in minutes.