# Your first phone number: get your projects texting (Kit 10)

Kit 9 caught an email address. This kit gives your projects a phone number, so they can send a
text and receive one back. A code to verify a signup. A "your order shipped" to a customer. A
note to your own phone when something on your server breaks at 3am. One number, one key, and
from then on "text me when it happens" is a sentence Claude can act on.

I use Twilio. It is the one everybody's code already speaks, it starts free, and it has the
scoped-key setup you learned in Kit 6, so nothing here is a new idea. What IS new is a rule the
phone carriers added, and it decides how you set this up, so I'm putting it first.

## Before you start (Claude reads this first)

This kit assumes a few things are already in place. If one is missing, fetch that kit from the
list and run it before continuing. Every kit lives at the same address pattern.

| It assumes | Which kit provides it | Get it |
|---|---|---|
| Claude Code running in a terminal | Kit 1 | connectwithcliff.com/downloads/claude-code-quickstart.md |
| A safe place for secrets (vault or env file) | Kit 5.1 note inside Kit 5 | connectwithcliff.com/downloads/domain-setup.md |
| You know what an API key is, and email sends from your domain | Kit 6 | connectwithcliff.com/downloads/mailgun-email-setup.md |
| A server that stays on, for the inbound webhook | Kit 7 | connectwithcliff.com/downloads/vps-server-setup.md |
| The endpoint pattern (one small piece of code that answers a request) | Kit 9 | connectwithcliff.com/downloads/signup-form-setup.md |

The full list of kits, what each sets up, and what each assumes: connectwithcliff.com/downloads/INDEX.md

## The carrier rule (read this once)

In the US, a business texting people from a normal 10-digit number has to be registered first.
The carriers call it A2P 10DLC. Unregistered traffic from a local number is blocked outright
(Twilio has blocked it fully since 2023), and there is no way around it from code. Two more
things the rule drags in: registration needs a paid Twilio account (the free trial cannot
register, so a card goes on before this step), and registration creates a Messaging Service
that your number lives inside from then on. Remember that second one; it decides where the
webhook goes later. So the kit gives you two doors, and you pick one before you buy a
number.

**Door 1: a local number, registered.** You register yourself (a "Sole Proprietor" brand if you
are one person without an EIN, a "Low Volume Standard" brand if you have a business entity), then
register one campaign that describes what you send. Twilio quotes a one-time fee of $4.50 for the
brand, $15 to vet the campaign, and about $2 a month to keep it. Reviews run days, not minutes;
Twilio's own page currently says 5 to 10 days (some pages say about a week). You can build
everything else while you wait.
One more thing about this door: a Sole Proprietor brand is deliberately small. One campaign, one
number, one message a second, and a daily cap in the low thousands. That is plenty for one person.
But it is only for people WITHOUT an EIN. If you have one, register as Low Volume Standard instead,
or the brand gets rejected.

**Door 2: a toll-free number, verified.** No campaign registration, no monthly campaign fee, and
verification takes about 3 to 5 business days. One catch: since January 31, 2024 an unverified
or still-pending toll-free number cannot send at all, so you cannot even test until it clears. A toll-free number
also reads as "a company" rather than "a person," which is exactly right for order updates and
codes, and exactly wrong for a text that is supposed to feel like it came from you.

My take: if you are one person building your own thing, take Door 1 and start the registration
today. If you are setting this up for a business with an EIN and the texts are transactional, Door
2 is less paperwork, though not none: you still describe the use case, the opt-in flow, your
website and sample messages, and most rejections come from vague opt-in wording. Either way, the
free trial lets you verify your own mobile and send a test to that number, with the "Sent from your
Twilio trial account" prefix on it. A custom message from your own new number can still wait on
Door 1 or Door 2 clearing. So do the paperwork first; the test is the last step, not the first.

## Prerequisite
- Kit 6 done. The API-key idea is the same; the key just points at a different service.
- Kit 7's server, so the number has somewhere to deliver replies.
- A safe home for two secrets (Kit 5.1). Twilio gives you an Account SID and an Auth Token at
  signup. You will make a separate, narrower API key for Claude and keep the Auth Token out of
  everything except the server that checks Twilio's signatures.
- Your own mobile number, to verify with Twilio and to receive the test.

## How to use it (any OS)
- **Quick:** hit Copy, open Claude Code, paste this in, and say the line below.
- **Most reliable:** hit Download, then tell Claude:
  *"read ~/Downloads/twilio-sms-setup.md and set it up with me."*

Either way, say:

> "Help me set up Twilio so my projects can send and receive text messages. Walk me through
> creating the account and verifying my own mobile number. Ask me which door I am taking: a local
> number with A2P 10DLC registration, or a toll-free number with verification. Then buy the number,
> start the registration or verification for me, and tell me exactly which fields are mine to fill.
> Create a Restricted API key that can only send messages (fall back to a Standard key if my
> account does not offer Restricted keys), never use my Auth Token from code, and store the SID
> and secret safely. Build the sending helper and a small inbound endpoint on my Kit 7 server that
> receives replies to my number and emails them to me through my Kit 6 Mailgun, with Twilio's
> signature check on the server. Point the inbound webhook at it on the Messaging Service the
> registration created (or on the number itself if I took the toll-free door and have no
> Messaging Service). Keep a do-not-text list that every send checks first. Test the endpoint
> with a signed fake request today, and send the first real text to my verified phone once the
> registration or verification has cleared. Tell me which clicks are mine as we go."

## What it sets up

**1. A Twilio account, your verified phone, and a card.** Free to open, and the trial is fine for
looking around and verifying your own mobile. But everything that matters in this kit, the
registration and the number you will actually send from, needs the account upgraded with a card.
Trials expire, can only text up to five verified numbers, stamp a trial notice on every message,
and cannot register for A2P 10DLC at all. Put the card on early. Verify your own mobile first; that
is the test target for everything below.

**2. A number, through the door you picked.** Claude searches for a number (you can ask for your
area code) and buys it. A local number is about a dollar a month; toll-free a little more. Then it
starts the registration or verification in the console and hands you the fields only you can
answer: your legal name or business name, address, website, and one honest paragraph on what you
will send and how people opt in. Write that paragraph like a person, because a person reads it.
On Door 1 the registration creates a Messaging Service and adds your number to it as a sender. A
Messaging Service is just a folder for your number with its own settings, and its settings win
over the number's own, which is why step 5 points the webhook there.

**3. A restricted API key, handed to Claude.** Twilio's Auth Token can do everything on your
account. You do not give Claude that. You create an API key, and Twilio has three kinds: Main
(as powerful as the token), Standard (everything except managing the account and other keys, so
it can still buy numbers and spend), and Restricted, where you tick exactly what it may do. Ask
for a Restricted key with permission to send messages and nothing else. If your account does not
offer Restricted keys yet, a Standard key is the fallback, and the Auth Token is never the
answer. The key gets its own SID and secret and can be revoked on its own without touching the
account. Same lesson as Kit 6: contain the blast radius. Store the key SID, the secret, and your
Account SID in your vault or env file; the secret is shown once.

**4. The sending helper, and the first real text.** Claude writes the one function every send
goes through (it checks the do-not-text list and the quiet hours before it calls Twilio), and
tests it against a stub today. The first real text to your verified phone waits for your door to
clear; on Door 1 an unregistered number is blocked, on Door 2 an unverified one is. When it
finally buzzes, you're through the hard part. That wait is the paperwork, not you.

**5. The inbound endpoint.** Sending is half of it. When someone replies to your number, Twilio
does not keep the reply, it delivers it to a URL you name. Claude adds one small endpoint on your
Kit 7 server, the same shape as the Kit 9 form endpoint: Twilio posts the sender, the text and the
number it came to; the endpoint checks the request really came from Twilio, saves the message, and
emails it to you through your Kit 6 domain. Point the inbound webhook at that URL, on the
Messaging Service if you have one (its settings override the number's) or on the number itself
if you do not, and every reply lands in your inbox within seconds. Claude tests the endpoint
today with a signed fake request, so you know it works before the first real reply.

**6. Opt-out, built in from the start.** Twilio handles the legal words for you on standard
numbers: a reply of STOP blocks that person, START lets them back in, HELP gets an automatic
answer (Twilio answers it itself; your endpoint only sees HELP if Advanced Opt-Out is switched
on). But Twilio only stops what Twilio sees. So Claude also keeps a do-not-text list in the same
SQLite file from Kit 9, writes to it on every STOP that hits your endpoint, and every send checks
it first. Skip this and you are a spammer with a phone bill.

**7. Quiet hours and a sending window.** One rule in the code, and it is your rule, not Twilio's
(the common legal window is 8am to 9pm; this is a notch stricter): no marketing texts before 9am
or after 8pm in the recipient's time zone, and never more than a couple a week unless they asked.
Codes and order updates are exempt; they are answering something the person just did.

## Security: the part not to skip
- **A restricted key to Claude, the Auth Token to nobody but the server.** The token is the master
  key to your account and the money on it. It lives in the server's env file only because the
  signature check needs it; Claude's sending code uses the restricted key, which can be revoked
  on its own.
- **Validate the webhook.** Twilio signs every request it sends to your endpoint. Check the
  signature or anyone on the internet can post fake "replies" to your server.
- **Consent before the first marketing text, in writing, stored.** Kit 9 records the words a
  person agreed to when they gave an email. A phone number needs its own line: the checkbox text,
  the time, the IP. Kit 11 adds that field to the form properly, with a verification code.
- **Watch the balance.** Set a low balance alert in the console. A bug that texts in a loop is a
  bill, not a crash.

## If Claude needs the exact specs
Send: `POST https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json`, HTTP basic
auth with the API key SID as the username and its secret as the password, form fields `From`
(your Twilio number, E.164 like +15551234567), `To`, `Body`. Minimal test:

```
curl -s -X POST https://api.twilio.com/2010-04-01/Accounts/YOUR_ACCOUNT_SID/Messages.json \
  -u 'YOUR_API_KEY_SID:YOUR_API_KEY_SECRET' \
  --data-urlencode 'From=+15550001111' \
  --data-urlencode 'To=+15559998888' \
  --data-urlencode 'Body=Sent from my own number, by Claude.'
```

A success returns a message SID and status `queued`. Inbound: set the incoming-message webhook
to `https://yourdomain.com/sms` (HTTP POST) on the Messaging Service (Integration settings) when
the number is in one, otherwise on the number's "A message comes in" setting. Twilio posts `From`, `To`, `Body`,
`MessageSid` and signs the request with the `X-Twilio-Signature` header, computed from your Auth
Token, which is why the validation step runs on the server, never in the browser. Reply with empty
TwiML (`<Response></Response>`) unless you want to auto-answer. Official SDKs exist (Node, Python,
PHP, Ruby, Go, Java) if you'd rather a library than curl.

## Cost, straight
The account is free and the trial texts your own phone. A local number is about a dollar a month,
a toll-free number a little over two. Texts are under a cent each plus a small carrier fee.
Registration is the only real line item: about $20 once and $2 a month for a Sole Proprietor on
Door 1, nothing extra on Door 2. Nobody on this list will feel any of it. What you feel is the
first time your phone buzzes because your own code decided it should.

## Make it stick
Door picked, number bought, registration or verification started, restricted key in your vault
and handed to Claude, endpoint live, and then, once the door clears, the first text landed, a
reply in your inbox, STOP honoured. From then on, texting is one instruction. Wire it into anything: a code to confirm a signup, a heads-up when a
form comes in, an alert to your pocket when the server goes quiet.

You're done today when: the account is upgraded, the number is bought, the registration or
verification is submitted, the restricted key is in your vault, and your endpoint answers a signed
test request. You're done for real, a few days later, when: a text from your own number has
landed on your phone, a reply to that number has landed in your email, and a STOP from your phone
put you on your own do-not-text list.

That's Kit 10. Your projects can reach a person, not just an inbox. Next up, Kit 11: the Kit 9
form gets an optional phone field, with a one-time code so you only ever store a number that
really belongs to the person typing it.

-- Cliff (connectwithcliff.com)
