SMS Worker (Text Me The App)
Overview
The SMS Cloudflare Worker implements the Text Me The App (TMTA) feature.
When a prospective user visits floatme.io or floatme.com on desktop and enters their phone number, the web page calls this worker, which sends an SMS containing the app download link via Twilio.
The worker is deployed at sms.floatme.io (prod) and sms.test.floatme.io (test).
Source
cloudflare/workers/sms/
| File | Purpose |
|---|---|
|
Entry point, CORS handling, phone validation, Twilio dispatch |
|
OpenAPI 3.0.3 spec defining the single |
|
Worker name, routes, and environment variables (non-secret) |
|
Uploads |
API Endpoint
Full spec: cloudflare/workers/sms/spec.yaml (server: https://tmta.floatme.io).
| Method | Path | Description |
|---|---|---|
|
|
CORS preflight check |
|
|
Send the app download link to the given phone number |
|
|
All other methods return |
POST /{campaign_id}
| Field | Type | Notes |
|---|---|---|
|
string |
Destination phone number; any format accepted by the |
| Status | Meaning |
|---|---|
|
SMS dispatched successfully via Twilio |
|
Origin not allowed, body malformed, |
|
Twilio call failed |
TMTA Flow
Browser (floatme.io)
│
├─ OPTIONS /{campaign_id} (CORS preflight)
│ worker validates Origin header against allowlist
│ → 204 No Content + CORS headers OR 403 Forbidden
│
└─ POST /{campaign_id}
worker validates Origin header
worker parses { to } from JSON body
worker validates phone number (phone library) ──→ 403 if invalid or non-US
worker extracts campaign_id from URL path
worker calls Twilio Messages API
├─ success → 201 Created
└─ failure → 500 Internal Server Error
Campaign System
The URL path doubles as a campaign selector.
The campaign_id is extracted from the last path segment (before any . extension).
Known campaigns and their message text:
| Campaign ID | SMS message body |
|---|---|
|
|
|
|
If the campaign ID is not found in the map, getCampaign() returns undefined and Twilio will receive an empty body, resulting in an API error.
Phone Number Validation
The worker uses the phone npm library for validation and normalization.
-
Parse the raw
tostring withphone(to). -
Reject if
phoneNumber.isValidisfalse. -
Reject if
phoneNumber.countryIso2is notUS(only US numbers are allowed). -
Normalize to E.164 format (
phoneNumber.phoneNumber, e.g.+12105551234) before passing to Twilio.
Abuse Prevention and Rate Limiting
The worker implements several layers of abuse prevention:
Origin Allowlist (CORS)
Only requests from the following origins are accepted:
https://*.floatme.io
https://www.floatme.io
https://*.floatme.com
https://www.floatme.com
All other origins receive 403 Forbidden immediately, before any phone validation or Twilio call.
Both the CORS preflight (OPTIONS) and the actual POST independently check the Origin header.
The isOriginAllowed function uses an exact string match (allowedHosts.includes(origin)), so the wildcard entries (https://*.floatme.io, https://*.floatme.com) are matched literally and will not match subdomains like https://staging.floatme.io. Only https://www.floatme.io and https://www.floatme.com are effectively allowed. This is a known code bug.
|
Country Restriction
Only US phone numbers are accepted (countryIso2 === "US").
International numbers are rejected with 403 Forbidden at validation time, before any Twilio call.
Input Validation
-
Missing or unparseable JSON body →
403 Forbidden(error logged to Datadog). -
Missing
tofield →403 Forbidden. -
Invalid phone number format →
403 Forbidden.
| There is no explicit per-IP or per-number rate limit implemented in the worker itself. Abuse prevention beyond the allowlist and country restriction relies on Cloudflare WAF rules applied at the zone level. |
Twilio Integration
Twilio calls are made via the shared service client at cloudflare/services/twilio/index.ts.
The client POSTs to https://api.twilio.com/2010-04-01/Accounts/{accountSID}/Messages.json
using HTTP Basic auth (accountSID:authToken, Base64-encoded).
| Parameter | Source |
|---|---|
|
Campaign message string (from |
|
|
|
Normalized E.164 phone number from |
|
|
| Prod and test environments share the same Twilio account SID, auth token, from number, and messaging service SID. There is no separate test Twilio environment. |
Environment Variables
| Variable | Kind | Description |
|---|---|---|
|
var |
|
|
var |
Twilio sender phone number in E.164 format |
|
var |
Twilio Messaging Service SID |
|
var |
Twilio account SID (same for prod and test) |
|
secret |
Twilio auth token (Cloudflare secret, not in toml) |
|
secret |
Datadog ingest key for structured log shipping |
Upload secrets with:
make secrets.sms.host
Local Development
make sms.local
This invokes:
wrangler dev cloudflare/workers/sms/index.ts \
-c cloudflare/workers/sms/wrangler.toml
No --env flag is passed; wrangler uses the top-level defaults from wrangler.toml (worker name sms-local, route localhost/*).
Provide TWILIO_AUTH_TOKEN and DATADOG_API_KEY via a .dev.vars file or your shell environment.
Wrangler starts a local HTTP server (default port 8787). Example test request:
curl -X POST http://localhost:8787/tt \
-H "Origin: https://www.floatme.io" \
-H "Content-Type: application/json" \
-d '{"to": "+12105551234"}'
See Also
-
Architecture — Twilio as an external service, Cloudflare zone routing for
sms.floatme.io -
Infrastructure — Terraform and wrangler resources for this worker
-
Feature Summary — SMS / TMTA capability summary