> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiveku.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send SMS with Twilio

> Send text messages for 2FA, notifications, or marketing

SMS is the highest-open-rate channel you have access to — 98% open rates, read within 3 minutes on average. Twilio is the easiest way to send it from your Hiveku site.

<Info>
  Common use cases: two-factor authentication, order confirmations, delivery notifications, abandoned cart recovery, appointment reminders, on-call paging.
</Info>

## Step 1: Set Up Twilio

<Steps>
  <Step title="Sign up for Twilio">
    Go to [twilio.com](https://www.twilio.com) and create an account. The free trial includes credit for testing, but you'll only be able to send to numbers you've manually verified until you upgrade.
  </Step>

  <Step title="Buy a phone number">
    In the Twilio Console, go to **Phone Numbers > Buy a Number**. Pick one with SMS capabilities. US local numbers run about \$1/month.
  </Step>

  <Step title="Find your credentials">
    On the Console homepage, find your **Account SID** and **Auth Token**. Copy both.
  </Step>

  <Step title="Store in Hiveku">
    In your project, go to **Settings > Environment Variables** and add:

    * `TWILIO_ACCOUNT_SID`
    * `TWILIO_AUTH_TOKEN`
    * `TWILIO_FROM_NUMBER` — the number you bought, in E.164 format like `+15551234567`
  </Step>
</Steps>

## Step 2: Install the SDK

From your project's code editor or terminal:

```bash theme={null}
npm install twilio
```

## Step 3: Create the Send Endpoint

Create `api/send-sms.ts`:

```typescript theme={null}
import twilio from 'twilio';

const client = twilio(
  process.env.TWILIO_ACCOUNT_SID!,
  process.env.TWILIO_AUTH_TOKEN!
);

export default async function handler(req: Request) {
  const { to, body } = await req.json();
  const message = await client.messages.create({
    from: process.env.TWILIO_FROM_NUMBER,
    to,
    body,
  });
  return Response.json({ sid: message.sid });
}
```

Deploy the project. Your endpoint is now live at `https://yoursite.hiveku.com/api/send-sms`.

## Step 4: Call It from a Workflow

From any workflow, add an **HTTP Request** action pointing at your endpoint:

```
POST https://yoursite.hiveku.com/api/send-sms
Content-Type: application/json

{
  "to": "{{trigger.phone}}",
  "body": "Your order #{{trigger.order_id}} has shipped!"
}
```

## Two-Factor Authentication Pattern

<Steps>
  <Step title="User enters phone number">
    On signup or login, capture the user's phone in E.164 format.
  </Step>

  <Step title="Generate a one-time code">
    Create a 6-digit numeric code. Store it in a `sms_codes` table with:

    * `phone` — the number
    * `code` — the 6-digit string
    * `expires_at` — now + 10 minutes
    * `used` — false
  </Step>

  <Step title="Send the SMS">
    ```
    Your Acme code is 123456. Don't share this with anyone.
    ```

    Keep it short and unambiguous. Mention your brand name.
  </Step>

  <Step title="Verify on entry">
    When the user enters the code, query the table: match phone + code, not expired, not used. If valid, mark used = true and mark the user's phone as verified.
  </Step>
</Steps>

## Receiving SMS (Webhooks)

When users reply to your SMS, Twilio can POST the message to your site:

<Steps>
  <Step title="Create the webhook endpoint">
    `api/sms-webhook.ts`:

    ```typescript theme={null}
    export default async function handler(req: Request) {
      const form = await req.formData();
      const from = form.get('From');
      const body = form.get('Body');
      
      // Save, trigger a workflow, or auto-reply
      
      return new Response('', { status: 200 });
    }
    ```

    Twilio sends form-encoded data, not JSON.
  </Step>

  <Step title="Configure in Twilio">
    Console > Phone Numbers > click your number > **Messaging** section > set the **Webhook** to `https://yoursite.hiveku.com/api/sms-webhook` and set method to `HTTP POST`.
  </Step>

  <Step title="Respond with TwiML for auto-reply (optional)">
    ```xml theme={null}
    <Response>
      <Message>Thanks! We'll get back to you soon.</Message>
    </Response>
    ```
  </Step>
</Steps>

## Cost Notes

Twilio charges per message:

* US outbound: \~\$0.0079/SMS
* Inbound: free
* International: varies widely by country

Check [twilio.com/pricing](https://www.twilio.com/pricing) for current rates. For high-volume sending, Twilio also offers discounted rates via committed spend.

<Warning>
  Sending A2P (application-to-person) SMS in the US requires A2P 10DLC registration. Without it, your messages get filtered by carriers or blocked entirely. Register your business and use case in the Twilio console before you launch — approval can take several days.
</Warning>

<Warning>
  Never send marketing SMS without explicit opt-in. TCPA violations in the US carry fines of $500-$1,500 per message. Include a clear opt-out instruction ("Reply STOP to unsubscribe") and honor it immediately.
</Warning>

## Verify It Worked

<Steps>
  <Step title="Hit your endpoint from the terminal">
    ```bash theme={null}
    curl -X POST https://yoursite.hiveku.com/api/send-sms \
      -H "Content-Type: application/json" \
      -d '{"to": "+15551234567", "body": "Test from Hiveku"}'
    ```

    Replace the `to` with your own phone number.
  </Step>

  <Step title="Check your phone">
    The SMS should arrive within a few seconds.
  </Step>

  <Step title="Check the Twilio logs">
    In the Twilio Console, **Monitor > Logs > Messaging** shows every send attempt, status, and any error codes.
  </Step>
</Steps>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Trial account: can only send to verified numbers">
    Until you upgrade to a paid account, Twilio restricts sends to numbers you've manually verified. Verify recipient numbers in Console > Phone Numbers > Verified Caller IDs, or upgrade to unlock unrestricted sending.
  </Accordion>

  <Accordion title="'Invalid From number' error">
    Use E.164 format with country code: `+15551234567`, not `(555) 123-4567` or `5551234567`. Also confirm you've actually bought a number — the `TWILIO_FROM_NUMBER` must match an owned number in your Twilio account.
  </Accordion>

  <Accordion title="Messages show 'delivered' but never arrive">
    Most often an A2P 10DLC registration issue — carriers silently drop unregistered A2P traffic. Complete registration in Twilio Console > Messaging > Regulatory Compliance > A2P 10DLC.
  </Accordion>

  <Accordion title="Webhook not firing on inbound SMS">
    Check that the webhook URL in Twilio matches your live endpoint exactly (including protocol). Also check the request method is POST. Visit the endpoint directly in a browser — if you get a 404, the route isn't deployed.
  </Accordion>

  <Accordion title="Costs adding up faster than expected">
    Switch marketing SMS to cheaper alternatives (email where possible, or push notifications for app users). Keep SMS for high-value use cases: 2FA, transactional confirmations, urgent alerts. Bulk marketing SMS gets expensive fast.
  </Accordion>
</AccordionGroup>

## What's Next?

<CardGroup cols={2}>
  <Card title="Workflows" icon="diagram-project" href="/how-tos/workflows">
    Trigger SMS from any workflow event
  </Card>

  <Card title="Environment Variables" icon="key" href="/how-tos/env-vars">
    Manage API keys and secrets safely
  </Card>
</CardGroup>
