# SMS webhook on your own number: do you need Twilio?

> Receive the SMS your own SIM gets as a signed JSON webhook, via a free Android app. No rented number: Twilio charges $1.15/month plus $0.0083 per SMS.

Source: https://unlimitedmessaging.app/articles/sms-webhook-incoming-sms

SMS webhook

# Get the SMS your phone receives  
_as a webhook, on your own number._

Inbound SMS APIs usually start with renting a new number. Install a free Android app instead: each text your SIM receives reaches your URL as signed JSON, and you answer from that same number.

[Create a free account](https://app.unlimitedmessaging.app)[See paid plans](https://unlimitedmessaging.app/pricing)

The short answer

## Can you receive SMS on your own number by webhook?

Yes, with an Android phone. The free Unlimited Messaging app links your phone's SIM to your account, and every SMS it receives after sign-in is posted to your URL as a signed JSON event, message.received. People keep texting the number they know, and you pay no fee per incoming SMS. Unlike [Twilio](https://www.twilio.com/en-us/sms/pricing/us), there is no number to rent. Webhooks are on the paid Medium and Max plans.

The classic way to receive SMS by API is an A2P provider. With Twilio you lease a number ($1.15 a month for a US local number), point its webhook at your server, and pay $0.0083 per inbound segment plus a carrier fee, $0.0035 from AT&T or $0.0025 from T-Mobile. The number is new, so your customers have to learn it, and Twilio posts form-encoded parameters signed with HMAC-SHA1.

An Android gateway skips the rental. Unlimited Messaging for Android is free and open source (MIT): you install the APK, sign in, and each SIM becomes an SMS account (dual SIM, two accounts). The phone keeps a connection to the API, uploads each SMS it receives, and the API announces it to your webhook in the same JSON envelope it uses for WhatsApp and email. A retried upload is recognized and never announced twice.

The catch is physical: the phone must stay on, online and allowed to run in the background. It handles the texts of one business at a human pace, not the inbound traffic of a national short code.

Compare first: [the four Android SMS gateway apps](https://unlimitedmessaging.app/articles/android-sms-gateway-comparison), and [what a free SMS API really costs](https://unlimitedmessaging.app/articles/free-sms-api).

![Illustration: a phone with text-message bubbles and an SMS tag, with the headline “Incoming SMS, straight to your code”.](https://unlimitedmessaging.app/_next/image?url=%2Fassets%2Farticles%2Fcovers%2Fsms-webhook-incoming-sms-en.png&w=3840&q=75)

Definition
SMS webhook

An HTTP POST sent to your server each time a phone number receives a text message, with the sender, the text and the time, so your code can react without polling.

Also searched as incoming SMS webhook, receive SMS API, inbound SMS API or SMS to webhook.

[Source: Twilio, incoming message webhook↗](https://www.twilio.com/docs/messaging/guides/webhook-request)

The events

## Which SMS events does the webhook send?

SMS uses the same event types as the other channels. An endpoint only receives the types in its eventTypes list.

1. 01  
### message.received  
A text arrived on one of your SIMs. data.channel.type is SMS, content holds the text, sender the number in +E.164\. A sender the carrier only names (a bank, a delivery service) comes with sender null and that name in senderId.
2. 02  
### message.sent  
An SMS you sent through the API left the phone. Carries the text and the recipient, fired once, so your inbox can show both sides.
3. 03  
### message.status  
An SMS you sent moved to SENT, DELIVERED (when the carrier sends delivery reports), FAILED or UNDELIVERABLE, with error saying why. SMS has no read receipts, so never READ.
4. 04  
### account.status\_changed  
A SIM account changed status, for instance disconnected when the app was signed out. Subscribe to it to know when the phone stops relaying.

POST https://example.com/webhooks/umJSON

```
{
  "type": "message.received",
  "eventId": "whd_2b9e7c41-0d3a-4f6e-8c52-91a7d4e0b6f3",
  "occurredAt": "2026-11-09T08:42:06.000Z",
  "data": {
    "message": {
      "id": "msg_7d2c9a10-5e4b-4b8f-a1c3-0f6e2d9b8a47",
      "externalId": "c1f4a9e27b3d4e6f9a0b",
      "direction": "IN",
      "fromMe": false,
      "content": "Running 10 min late for my 9:00, sorry!",
      "sentAt": "2026-11-09T08:42:03.000Z",
      "receivedAt": "2026-11-09T08:42:06.000Z",
      "sender": "+447700900456",
      "senderId": "+447700900456",
      "senderName": null,
      "participant": null,
      "replyTo": null,
      "transcript": null
    },
    "channel": {
      "type": "SMS",
      "account": { "id": "acc_5e8d1f2a-3c4b-4d6e-9f70-1a2b3c4d5e6f", "name": "Front desk SIM" },
      "conversation": { "id": null, "isGroup": false, "address": "+447700900456" }
    }
  }
}
```

A real message.received body for an SMS, built from the published schema. conversation.id is null for SMS: key the thread on sender. Only SMS received after the app was signed in are uploaded; texts already on the phone are never read.

Set it up

## How do you receive incoming SMS in Node.js?

Install the app, register an endpoint, verify each POST. The same handler works for WhatsApp and email later.

1. 01  
### Install the Android app  
Download the APK from GitHub (Android 8.0 or newer), sign in, grant SMS access and unrestricted battery. Each SIM appears as an SMS account.
2. 02  
### Register the endpoint  
POST /webhooks with your URL and eventTypes, or add it on the Webhooks page of the dashboard. The secret (whsec\_...) is shown once.
3. 03  
### Verify, acknowledge, act  
Check the webhook-signature header, return 2xx within 10 seconds, deduplicate on eventId, then reply or store.

POST /webhookscurl

```
curl https://api.unlimitedmessaging.app/webhooks \
  -H "Authorization: Bearer $UM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/um",
    "eventTypes": ["message.received", "message.status"],
    "description": "Incoming SMS"
  }'

# The response carries "secret": "whsec_..." once. Store it as UM_WEBHOOK_SECRET.
```

Add accountIds to limit the endpoint to one SIM; without it, every account you have is covered, including SIMs added later.

webhook handlerNode.js / Express

```
import crypto from 'node:crypto';
import express from 'express';
import { UnlimitedMessagingApiClient } from '@unlimited-messaging/sdk';

const um = new UnlimitedMessagingApiClient({ token: process.env.UM_API_KEY! });
const key = Buffer.from(process.env.UM_WEBHOOK_SECRET!.replace(/^whsec_/, ''), 'base64');
const seen = new Set<string>(); // use your database in production

// Standard Webhooks: HMAC-SHA256 of "id.timestamp.rawBody", base64.
function verify(raw: string, id: string, ts: string, header: string) {
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = crypto.createHmac('sha256', key).update(`${id}.${ts}.${raw}`).digest('base64');
  return header.split(' ').some((entry) => {
    const sig = entry.startsWith('v1,') ? entry.slice(3) : '';
    return sig.length === expected.length &&
      crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
  });
}

const app = express();
app.post('/webhooks/um', express.raw({ type: 'application/json' }), async (req, res) => {
  const raw = req.body.toString('utf8');
  const ok = verify(raw, req.get('webhook-id') ?? '', req.get('webhook-timestamp') ?? '',
    req.get('webhook-signature') ?? '');
  if (!ok) return res.sendStatus(401);
  res.sendStatus(200); // answer within 10 s, work afterwards

  const event = JSON.parse(raw);
  if (seen.has(event.eventId)) return; // at-least-once delivery
  seen.add(event.eventId);

  if (event.type === 'message.received' && event.data.channel.type === 'SMS') {
    const { sender, content } = event.data.message;
    if (content?.trim().toUpperCase() === 'C') {
      // Texts back from the same SIM that received the SMS.
      await um.messages.messageSend({
        to: { phone: sender },
        channels: [{ channel: 'SMS', accountId: event.data.channel.account.id }],
        text: 'Thanks, your appointment is confirmed.',
      });
    }
  }
});
app.listen(3000);
```

The signature check follows the documented Standard Webhooks scheme (HMAC-SHA256 over id.timestamp.rawBody). The reply names the SIM that received the text, so it leaves from the same number.

Vibe coding

## Building with Cursor, Claude Code, Lovable or Bolt? Paste this

Your AI editor gets the route, the signature scheme and the SMS event shape in one go.

Prompt to copy

Add an Unlimited Messaging webhook to this app so it receives the SMS my own Android phone receives.

1. Create a POST route at /webhooks/um that reads the RAW request body.
2. Verify the Standard Webhooks signature: key = base64-decode(UM_WEBHOOK_SECRET without "whsec_"); expected = base64(HMAC-SHA256(key, `${webhook-id}.${webhook-timestamp}.${rawBody}`)); accept if any space-separated entry of the webhook-signature header equals `v1,${expected}` (constant-time compare); reject timestamps more than 5 minutes off; return 401 otherwise.
3. Return 200 at once, then process. Deduplicate on body.eventId.
4. On type "message.received" with data.channel.type "SMS", save data.message.sender (+E164, or null with the name in senderId), data.message.content and data.message.sentAt. conversation.id is null for SMS: group by sender.
5. To reply by SMS, install @unlimited-messaging/sdk, read UM_API_KEY from env, and call `client.messages.messageSend({ to: { phone: sender }, channels: [{ channel: 'SMS', accountId: data.channel.account.id }], text })`.
6. Put UM_API_KEY and UM_WEBHOOK_SECRET in .env and .env.example, never in code.

Docs: https://docs.unlimitedmessaging.app (Webhooks). Register the URL with POST https://api.unlimitedmessaging.app/webhooks and eventTypes ["message.received", "message.status"].

What people build

## What can you do with incoming SMS on your own number?

Whatever starts with a customer texting the number on your van, your flyer or your invoice.

### Reply-to-confirm reminders

Send a reminder by SMS, read the C or the R that comes back, update the booking and confirm, all from your usual number.

### SMS into your CRM

Attach each incoming text to the contact by sender, next to their WhatsApp and email, since all three arrive in the same envelope.

1. 01  
### STOP handling  
Catch STOP or UNSUBSCRIBE in content and flag the contact before your next send.
2. 02  
### AI first answer  
Hand the text to an LLM for a draft, send it back by SMS or route it to a human.
3. 03  
### Alerts from machines and services  
Forward texts from an alarm, a sensor SIM or a supplier to Slack or email.
4. 04  
### No-code flows  
Point the webhook at n8n, Make or Zapier and branch on content without a server.

The table

## Receiving SMS by webhook: Twilio vs Android gateways vs Unlimited Messaging

A rented number from a provider, or the SIM already in your phone.

__Receiving SMS by webhook: Twilio vs Android gateways vs Unlimited Messaging__
| [Twilio](https://www.twilio.com/en-us/sms/pricing/us)Rented number (US) | [SMSGate / httpSMS](https://github.com/capcom6/android-sms-gateway)Open source Android gateways | Unlimited MessagingAndroid app, paid plans            |                                                            |
| ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------- |
| Number that receives                                                    | A number you lease from Twilio                                                                  | Your phone's SIM                                      | Your phone's SIM                                           |
| Monthly number cost                                                     | $1.15 local, $2.15 toll-free                                                                    | None beyond your carrier plan                         | None beyond your carrier plan; webhooks need Medium or Max |
| Cost per incoming SMS                                                   | $0.0083 per segment plus a carrier fee                                                          | None                                                  | None from Unlimited Messaging                              |
| Payload                                                                 | Form-encoded, X-Twilio-Signature (HMAC-SHA1)                                                    | Webhook or callback URL (SMSGate: sms:received event) | JSON, Standard Webhooks signature (HMAC-SHA256)            |
| Hardware                                                                | None                                                                                            | An Android phone kept on                              | An Android 8.0+ phone kept on                              |
| WhatsApp and email in the same webhook                                  | WhatsApp via a registered sender; email via SendGrid, separately                                | SMS only                                              | Yes, same envelope, same signature                         |
| Volume                                                                  | Built for high volume                                                                           | One phone's pace                                      | One phone's pace                                           |

Checked on 9 November 2026 on Twilio's US SMS pricing, its incoming message and webhook security docs, and the SMSGate and httpSMS repositories (links in the sources). Carrier fees vary by sending carrier.

The catch

## What are the limits of an SMS webhook from your phone?

No rented number and no per-SMS fee, but a phone is a phone.

1. 01  
### Webhooks are a paid feature  
On the Free plan, incoming SMS show up in the web app inbox. Pushing them to your server needs Medium (€19 a month, or €17 a month billed yearly) or Max.
2. 02  
### The phone must stay on and online  
If it is off, out of signal or killed by battery saving, nothing is relayed until it is back. Keep the app's battery unrestricted, and allow auto-start on Samsung, Xiaomi, Huawei, Oppo and Vivo.
3. 03  
### Android only, outside Google Play  
Google Play grants SMS permissions only to the default SMS app, so the app ships as a signed APK from GitHub. There is no iPhone version.
4. 04  
### Text only, from sign-in onward  
SMS is text only (no MMS). Only messages received after the app was signed in are uploaded: the texts already on the phone are never read.
5. 05  
### A personal line, a personal pace  
Consumer plans are sold for person-to-person use, and replies count against your plan. For thousands of inbound texts an hour or a short code, use an A2P provider.

How to choose

### Rented number or your own SIM?

You need a new dedicated number, high volume, a short code or no hardware at all: rent a number from Twilio or another provider and pay per segment. Your customers already text your mobile number and you want those texts in your code, with replies from the same number: install the Android app and subscribe to message.received.

FAQ

## Questions about SMS webhooks

Use an Android gateway app on a phone with your SIM. With Unlimited Messaging, each SMS the phone receives after sign-in is sent to your webhook as message.received, in signed JSON. There is no number to rent and no fee per incoming SMS; webhooks need the Medium or Max plan.

The envelope type, eventId and occurredAt, then data.message with id, externalId, direction IN, content (the text), sentAt, receivedAt, sender (+E.164), senderId, and data.channel with type SMS, the SIM account and conversation.address. conversation.id is null for SMS.

Yes, like every Unlimited Messaging webhook, per Standard Webhooks: webhook-id, webhook-timestamp and webhook-signature headers, with an HMAC-SHA256 of id.timestamp.rawBody keyed by your whsec\_ secret.

In the US, $0.0083 per inbound segment on a long code or toll-free number, plus a carrier fee per message (for example $0.0035 from AT&T, $0.0025 from T-Mobile), on top of the number itself at $1.15 a month for a local number.

Yes. Each SIM becomes its own SMS account, so data.channel.account.id tells you which line received the text, and you can scope an endpoint to one SIM with accountIds.

No. Only SMS received after the app was signed in are uploaded. The texts already stored on the phone are never read.

No. The gateway app exists for Android only, version 8.0 or newer. An old Android phone with your SIM in it is enough.

Call POST /message with to.phone set to the sender and a channels entry for SMS with the accountId of the SIM that received it. The reply leaves from the same number and counts against your carrier plan.

Sources

## Sources & references

To check the information in this article for yourself:

1. [01SMS pricing in the United States (inbound, numbers, carrier fees)↗Twilio](https://www.twilio.com/en-us/sms/pricing/us)
2. [02Incoming message webhook request (form-encoded parameters)↗Twilio Docs](https://www.twilio.com/docs/messaging/guides/webhook-request)
3. [03Webhooks security (X-Twilio-Signature, HMAC-SHA1)↗Twilio Docs](https://www.twilio.com/docs/usage/webhooks/webhooks-security)
4. [04SMS Gateway for Android (sms:received webhook, Apache-2.0)↗GitHub - capcom6](https://github.com/capcom6/android-sms-gateway)
5. [05httpSMS (forwards received SMS to your server, AGPL-3.0)↗GitHub - NdoleStudio](https://github.com/NdoleStudio/httpsms)
6. [06Unlimited Messaging for Android (MIT)↗GitHub - UnlimitedMessaging](https://github.com/UnlimitedMessaging/unlimited-messaging-android)
7. [07Standard Webhooks specification↗standardwebhooks.com](https://www.standardwebhooks.com)
8. [08Unlimited Messaging API reference - Webhooks↗Unlimited Messaging](https://docs.unlimitedmessaging.app)

![Ilian, senior software engineer](https://ilianazz.com/images/iliazz.png)

Written by

[Ilian](https://unlimitedmessaging.app/authors/ilian) · Senior Software Engineer

A senior software engineer, he founds and runs several tech companies. He builds products around messaging APIs, automation and AI integration, and shares here what he learns while building.

[View LinkedIn profile↗](https://www.linkedin.com/in/ilianAzz/)Updated November 9, 2026

![](https://unlimitedmessaging.app/assets/logos/whatsapp.svg)![](https://unlimitedmessaging.app/assets/logos/email.svg)![](https://unlimitedmessaging.app/assets/logos/sms.svg)

## Your own number, wired to your code.

Create an account, install the free Android app, and turn on webhooks with Medium or Max. Sending SMS stays free on every plan.

[Create a free account→](https://app.unlimitedmessaging.app)

Similar articles
* [![](https://unlimitedmessaging.app/_next/image?url=%2Fassets%2Farticles%2Fcovers%2Fone-webhook-whatsapp-email-sms-en.png&w=3840&q=75)One webhook for WhatsApp, email and SMS: how far does it go?Every reply on your number, mailbox and phone in one signed JSON envelope: build a support inbox, an AI responder or a CRM sync.](https://unlimitedmessaging.app/articles/one-webhook-whatsapp-email-sms)
* [![](https://unlimitedmessaging.app/_next/image?url=%2Fassets%2Farticles%2Fcovers%2Fandroid-sms-gateway-comparison-en.png&w=3840&q=75)What is the best Android SMS gateway? 2026 comparisonAndroidSMSGate, httpSMS, textbee and Unlimited Messaging: self-hosting, MMS, dual SIM, encryption, MCP.](https://unlimitedmessaging.app/articles/android-sms-gateway-comparison)
* [![](https://unlimitedmessaging.app/_next/image?url=%2Fassets%2Farticles%2Fcovers%2Ffree-sms-api-en.png&w=3840&q=75)Free SMS API: what is really free, and what is a trial?FreeTwilio's trial, Textbelt's free key, and Android gateways that send on your own plan: the honest comparison.](https://unlimitedmessaging.app/articles/free-sms-api)
