---
title: "Twilio API"
description: "Local, stateful API emulators for healthcare and life science development. FHIR, SMART on FHIR, EHRs, payers, and life science APIs, without PHI. Synthetic data only."
canonical_url: "https://www.emuhealth.dev/docs/twilio"
---
# Twilio API

Stateful Twilio REST emulation with seeded accounts, Auth Tokens, API keys, incoming phone numbers, Programmable Messaging, Messaging Services, Verify, basic Voice calls, Conversations REST resources, signed webhooks, local simulator routes, and an inspector.

## Start

```bash
npx emuhealth --service twilio
```

When Twilio is the only enabled service, it starts on `http://localhost:4000`. When all services are started, it uses `http://localhost:4013`.

## Defaults

```text
TWILIO_ACCOUNT_SID=AC00000000000000000000000000000000
TWILIO_AUTH_TOKEN=twilio_test_auth_token
TWILIO_API_KEY=SK00000000000000000000000000000000
TWILIO_API_SECRET=twilio_test_api_secret
TWILIO_PHONE_NUMBER=+15551234567
TWILIO_VERIFY_SERVICE_SID=VA00000000000000000000000000000000
```

## URL Mapping

| Real Twilio URL | Emulator URL |
|-----------------|--------------|
| `https://api.twilio.com/2010-04-01/...` | `$TWILIO_EMULATOR_URL/2010-04-01/...` |
| `https://messaging.twilio.com/v1/...` | `$TWILIO_EMULATOR_URL/messaging/v1/...` |
| `https://verify.twilio.com/v2/...` | `$TWILIO_EMULATOR_URL/verify/v2/...` |
| `https://conversations.twilio.com/v1/...` | `$TWILIO_EMULATOR_URL/conversations/v1/...` |

The official Node SDK builds absolute Twilio product URLs. In SDK tests, use a custom request client that rewrites those hosts to the emulator prefixes above.

## Supported Routes

- `GET /2010-04-01/Accounts/{AccountSid}.json`
- `GET /2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers.json`
- `POST /2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers.json`
- `POST /2010-04-01/Accounts/{AccountSid}/Messages.json`
- `GET /2010-04-01/Accounts/{AccountSid}/Messages.json`
- `GET /2010-04-01/Accounts/{AccountSid}/Messages/{MessageSid}.json`
- `POST /2010-04-01/Accounts/{AccountSid}/Messages/{MessageSid}.json`
- `DELETE /2010-04-01/Accounts/{AccountSid}/Messages/{MessageSid}.json`
- `POST /2010-04-01/Accounts/{AccountSid}/Calls.json`
- `GET /2010-04-01/Accounts/{AccountSid}/Calls.json`
- `POST /messaging/v1/Services`
- `GET /messaging/v1/Services`
- `POST /verify/v2/Services/{ServiceSid}/Verifications`
- `POST /verify/v2/Services/{ServiceSid}/VerificationCheck`
- `POST /conversations/v1/Services`
- `POST /conversations/v1/Services/{ServiceSid}/Conversations`
- `POST /conversations/v1/Services/{ServiceSid}/Conversations/{ConversationSid}/Participants`
- `POST /conversations/v1/Services/{ServiceSid}/Conversations/{ConversationSid}/Messages`

## SMS And OTP Testing

The seeded Verify Service uses code `123456`, so most local OTP tests can start a verification through the normal Verify API and submit that code. Tests that need to read the current local code can use the authenticated helper route:

```bash
curl -u "$TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN" \
  "http://localhost:4000/_twilio/simulate/verification-code?To=%2B15550002222&ServiceSid=$TWILIO_VERIFY_SERVICE_SID"
```

The helper returns the latest local verification for that phone number, including `verification_sid`, `status`, `attempts`, and `code`. It is local-only test support, not a production Twilio API. The Verify inspector also shows each attempted code.

For inbound SMS, configure a phone number `sms_url`, then call `POST /_twilio/simulate/inbound-message` with `To`, `From`, and `Body`. If the destination number is assigned to a Messaging Service with `inbound_request_url`, the simulator sends the inbound webhook there and includes `MessagingServiceSid`; otherwise it uses the phone number `sms_url`. For outbound delivery transitions, create a message with `StatusCallback`, then call `POST /_twilio/simulate/message-status`.

## Simulator

- `POST /_twilio/simulate/inbound-message`
- `POST /_twilio/simulate/message-status`
- `GET /_twilio/simulate/verification-code`
- `POST /_twilio/simulate/inbound-call`
- `POST /_twilio/simulate/call-status`
- `POST /_twilio/simulate/verification-status`

## Seed Config

```yaml
twilio:
  account:
    sid: AC00000000000000000000000000000000
    auth_token: twilio_test_auth_token
    friendly_name: Local Twilio Account
  api_keys:
    - sid: SK00000000000000000000000000000000
      secret: twilio_test_api_secret
      friendly_name: Local API Key
  phone_numbers:
    - phone_number: "+15551234567"
      friendly_name: Local SMS and Voice Number
      sms_url: http://localhost:3000/api/twilio/sms
      voice_url: http://localhost:3000/api/twilio/voice
  messaging_services:
    - friendly_name: Local Messaging Service
      phone_numbers: ["+15551234567"]
  verify_services:
    - friendly_name: Local Verify Service
      code: "123456"
      default_channel: sms
  conversations:
    services:
      - friendly_name: Local Conversations
```

## Inspector

Open `GET /` in the Twilio emulator to inspect messages, Verify attempts, calls, Conversations, phone numbers, services, credentials, and webhook deliveries.

## Current Limits

No real SMS, MMS, WhatsApp, email, voice, carrier, compliance, billing, SendGrid, Studio, Flex, TaskRouter, Video, Sync, Segment, Conversations SDK websocket behavior, or complete TwiML interpreter behavior is implemented.
