AI app builder
Add SMS to a Bolt app: server functions, secrets and replies from your own phone
Published and updated
A Bolt app sends SMS through your own Android phone from a Bolt server function. Save the textbee API key under Secrets in the Bolt database panel, ask Bolt to write a function that posts to the textbee send endpoint, and call it from your app. Replies arrive at a second server function that you register as a textbee webhook. Bolt deploys both functions for you.
- Send
- HTTP POST
- to the textbee send endpoint
- Receive
- Webhook
- MESSAGE_RECEIVED, flat JSON
- Pace
- 10 to 15 / min
- per Android phone
- textbee code
- None
- uses what the tool ships today
What you need
- A Bolt project with Bolt Cloud enabled, so the database panel shows Secrets and Server Functions. The project owner or a team admin manages secrets.
- A textbee account with the Android app installed on the phone that holds the SIM, and an API key from the dashboard.
- A second phone, or a friend, to text the textbee phone when you test replies.
- The textbee app on the phone. Download the app, then create an API key in the dashboard.
Send SMS from Bolt
Bolt server functions run on Deno on the Supabase backend that Bolt Database uses. They read secrets from the environment, which keeps the textbee key out of the browser.
Add the secret
Click the database icon at the top center, open Secrets, enter the name and value, and click Save. Bolt also links to this tab when code it wrote needs a key.
Field Value Name TEXTBEE_API_KEY Value Your key from the textbee dashboard Prompt for the function
Paste the prompt from this page and change What I want. Bolt writes a server function like the one below and deploys it.
supabase/functions/send-sms/index.tsDeno.serve(async (req) => { const { to, message } = await req.json() const res = await fetch('https://api.textbee.dev/api/v1/gateway/send-sms', { method: 'POST', headers: { 'x-api-key': Deno.env.get('TEXTBEE_API_KEY') ?? '', 'Content-Type': 'application/json', }, body: JSON.stringify({ recipients: [to], message }), }) return new Response(await res.text(), { status: res.status, headers: { 'Content-Type': 'application/json' }, }) })Protect the function
A public send function lets anyone text from your phone. Ask Bolt to accept calls only from signed-in users, or to build the message on the server from a booking id instead of taking any text from the browser.
Test and read the logs
Trigger the function from the preview with your own number. In the database panel, Server Functions and View Logs show the textbee response: data.success true and an smsBatchId.
Receive SMS in Bolt
A second server function receives replies. It must accept requests without a Supabase login token, because textbee signs its requests with X-Signature instead.
Prompt for the webhook function
Ask Bolt for a function that reads the raw body, checks X-Signature with TEXTBEE_WEBHOOK_SECRET, skips repeated idempotencyKey values and stores the reply. Tell it the function must not require a Supabase JWT.
supabase/functions/textbee-webhook/index.tsasync function signatureMatches(raw: string, signature: string | null): Promise<boolean> { const secret = Deno.env.get('TEXTBEE_WEBHOOK_SECRET') ?? '' const key = await crypto.subtle.importKey( 'raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'], ) const mac = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(raw)) const expected = Array.from(new Uint8Array(mac), (b) => b.toString(16).padStart(2, '0')).join('') if (!signature || signature.length !== expected.length) return false let diff = 0 for (let i = 0; i < expected.length; i++) diff |= expected.charCodeAt(i) ^ signature.charCodeAt(i) return diff === 0 } Deno.serve(async (req) => { const raw = await req.text() if (!(await signatureMatches(raw, req.headers.get('x-signature')))) { return new Response('invalid signature', { status: 401 }) } const event = JSON.parse(raw) if (event.webhookEvent === 'MESSAGE_RECEIVED') { // save event.sender, event.message, event.receivedAt } return new Response('ok') })Get the function URL
Bolt does not print a URL format in its docs, so ask in the chat: "What is the public URL of the textbee-webhook function?" Supabase-backed functions usually answer at https://<ref>.supabase.co/functions/v1/textbee-webhook.
Register the webhook
In the textbee dashboard open Webhooks, add the URL, pick MESSAGE_RECEIVED and use the same signing secret you saved in Bolt Secrets. Text the phone and watch View Logs.
Paste this prompt into Bolt
The prompt below carries the endpoints, the payloads, where the key may live and the Bolt details from this page. Change the line that starts with What I want, and Bolt builds the feature without guessing an endpoint.
Prompt for your AI agent
Paste it into the Bolt chat. It carries the textbee API facts and the Bolt details the agent needs, so it does not guess.
Add SMS to the app I am building in Bolt. Use textbee, an SMS gateway that sends and receives SMS through my own Android phone.
Facts about the textbee API. Use only these. Do not invent endpoints or fields.
- Send an SMS: POST https://api.textbee.dev/api/v1/gateway/send-sms with the header x-api-key: <TEXTBEE_API_KEY> and a JSON body like {"recipients": ["+12015550123"], "message": "Hello"}. recipients must be a JSON array of E.164 numbers, even for one number. Optional fields: deviceId, simSubscriptionId, scheduledAt (ISO 8601, in the future). The response is {"data": {"success": true, "smsBatchId": "..."}}.
- Check delivery or read replies: GET https://api.textbee.dev/api/v1/gateway/messages with the same header. Filters: direction=received, smsBatchId=<id from the send>, from and to as ISO timestamps. Each row has a status such as sent, delivered, failed or received.
- Receive an SMS: textbee posts JSON to a webhook URL I register in the dashboard. A MESSAGE_RECEIVED delivery has these top-level fields: smsId, message, deviceId, webhookSubscriptionId, webhookEvent, idempotencyKey, sender, receivedAt. The header X-Signature holds an HMAC-SHA256 hex digest of the raw body, keyed with the signing secret I set on the webhook. Retries reuse the same idempotencyKey.
- Limits: One Android phone sends roughly 10 to 15 messages a minute. Text only, no MMS. Messages over 160 characters are split into segments.
Rules:
- Store the API key as a secret named TEXTBEE_API_KEY. Call textbee only from server-side code, never from code that runs in the browser.
- Do not ask me to paste the real key into this chat. Tell me where to add the secret instead.
- For incoming texts, create a public server endpoint, check the X-Signature header against a secret named TEXTBEE_WEBHOOK_SECRET, and ignore a repeated idempotencyKey.
What I want: Text the shop owner when a new order is placed, and text the customer when the order is ready for pickup.
Bolt specifics you should know:
- Write the textbee calls as Bolt server functions (Deno). Read secrets with Deno.env.get.
- Secrets live in the database panel under Secrets. Tell me the exact names to add there.
- The webhook function receives requests from textbee, not from a signed-in user, so it must not require a Supabase JWT.
- For Supabase phone sign-in, a Send SMS Hook can call a server function that sends the code through textbee.
Build it, tell me where to add each secret in Bolt, and add a way to send one test message to my own number.Features to build
- Order texts
- A database trigger or the checkout code calls the send function with an order id. The function looks up the phone number on the server, so the browser never chooses who gets texted.
- Phone login codes
- Supabase Auth can hand every login code to a Send SMS Hook. Point the hook at a server function that forwards sms.otp to textbee and returns an empty 200.
- Waitlist and pickup
- A Ready button on an admin page texts the next person in line. Their reply YES or NO arrives at the webhook function and updates the queue.
- Daily digest
- A scheduled function counts yesterday's signups or sales and texts the owner one line each morning.
Why Bolt builders text from their own phone
- Ship before the paperwork
- A Bolt app can go from prompt to published in an hour. Sender registration with a cloud provider can take days. textbee sends from your phone today, and you can move to a registered provider later by changing one function.
- Cheap login codes
- Verification products bill per successful code on top of the SMS fee. With textbee, each code is one message from the plan allowance, sent through the Send SMS Hook.
- One number for the whole shop
- Order texts and pickup texts come from the number customers already call, and replies come back to the same function that sent them.
A cloud SMS provider in Bolt vs textbee in Bolt
| What you care about | Cloud SMS provider | textbee |
|---|---|---|
| Setup | Create a provider account, verify a number, register a sender, add two or three secrets | Pair a phone, add one secret in the database panel, paste one prompt |
| Sender the contact sees | A rented virtual number, or an alphanumeric sender where the country allows it | Your own mobile number, which your contacts already have saved |
| Monthly cost | Per message, plus number rental and carrier surcharges in some countries | A flat plan with messages included: Pro is $14.99 a month for 5,000 messages. No per-message fee, no number rental, no carrier surcharge. |
| Throughput | Set by the provider tier and by sender registration | One phone sends roughly 10 to 15 messages a minute. Add phones to scale. |
| Replies | Inbound webhook from the provider, or the provider app in the tool | textbee webhook: flat JSON, signed with HMAC-SHA256 |
| Where the message leaves from | The provider data center | An Android phone you own, plugged in, on Wi-Fi or mobile data |
| Bolt cost | Tokens for the prompts, plus the provider bill | Tokens for the prompts only |
Per-message prices by provider and country, with sources and dates, are on the provider comparison pages.
What works and what does not
Works today
- Sends from any Bolt server function, with the key read from Secrets
- Replies through a public webhook function with a signature check
- Login codes through a Supabase Send SMS Hook
- Logs for every call under Server Functions in the database panel
Not with this route
- Calls from frontend code: the key would ship to every visitor
- A Bolt connector for textbee: this route uses a plain server function
- Delivery status inside Bolt without code: read it from the textbee messages endpoint
- MMS
What Bolt charges
Bolt Free includes 1M tokens a month with a 300K daily cap. Pro is $25 a month, or $18 a month billed annually, with 10M tokens. Connecting your own Supabase project directly needs Pro or Teams. bolt.new, checked on October 22, 2026. textbee itself charges a flat monthly plan with messages included; see pricing.
Frequently asked questions
Who can add secrets to a Bolt project?
The project owner on a personal account. On a team, owners, co-owners and team admins. Other members see "Project admin access required" in the Secrets tab.
Why does my Bolt webhook function return 401 to textbee?
Supabase edge functions require a login token by default, and textbee does not send one. Ask Bolt to turn off JWT verification for that one function. The X-Signature check then does the job the token did.
Can a Supabase Send SMS Hook in a Bolt app send codes through textbee?
Yes. The hook posts the user and sms.otp to an HTTPS endpoint and expects an empty 200 within 5 seconds. A server function that verifies the Standard Webhooks signature, calls textbee and returns quickly fits that budget. Phone sign-in must be turned on in Supabase Auth.
Can the Bolt chat send a test text while I build?
Yes, through a custom MCP server: the + icon in the chatbox, Connectors, Manage connectors and Custom MCP server, with https://mcp.textbee.dev/mcp as the URL, HTTP transport and your key as the API key. Your published app still uses the server function.
Does the free Bolt plan run server functions?
Bolt documents server functions as part of Bolt Cloud without a plan gate on the functions themselves. Free has a monthly token budget for the prompts, and a direct connection to your own Supabase project needs Pro.
Where do I find the textbee response when a text does not arrive?
Open the database panel, Server Functions, the send function and View Logs. A 401 means the secret name or value is wrong. A 400 usually means recipients was a string instead of an array. A success with no text means the phone is offline.
How long does the setup take?
About ten minutes: pair the phone, create an API key, add it under Secrets and paste the prompt. Replies add a second function and a webhook in the textbee dashboard.
Can I keep using textbee if I claim the Bolt database into my own Supabase?
Yes. The functions keep calling the same endpoint. Move TEXTBEE_API_KEY and TEXTBEE_WEBHOOK_SECRET into the Supabase project secrets, and update the webhook URL in textbee if the function URL changes.
Sources
- bolt.new, checked on October 22, 2026
- support.bolt.new: Secrets, checked on October 22, 2026
- support.bolt.new: Server functions, checked on October 22, 2026
- support.bolt.new: MCP connectors, checked on October 22, 2026
- supabase.com: Send SMS Hook, checked on October 22, 2026
Read next
- Order and delivery notifications with SMS from your own Android number
- SMS OTP and verification API: text verification codes from your own number
- Build with AI: one prompt for every builder
- Webhook signature check
- Add SMS to a v0 app: Next.js route handlers that text from your own phone
- Add SMS to a Replit app: Secrets, a server route and a published webhook URL
- All integrations
Your phone is already an SMS gateway. Switch it on.
Set up in minutes and send your first message for free. No credit card, no per-message fees, no carrier contracts.
Need self-hosting help or a custom integration? See services