Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

twilio

Mock Twilio service and Go SDK wrapper for local development and testing.

Features

  • SMS Messaging: Send SMS via Twilio Messaging API v2010
  • Verify (SMS): Twilio Verify v2 Verifications + VerificationCheck with seedable per-number behavior
  • Lookup: Twilio Lookup v2 line_type_intelligence driven by the same seed
  • Delivery Simulation: Automatic status callbacks for tracking
  • SDK Wrapper: Simplified Go client wrapping github.com/twilio/twilio-go
  • Configurable Modes: dev, test, prod-like behavior
  • Compatible: Drop-in replacement for real Twilio API

Quick Start

# Simple docker run
just docker

# Run locally
just run

# Run tests
just ci

Configuration

Credentials must use proper Twilio format:

  • AccountSID: AC + 32 hex characters
  • AuthToken: 32 hex characters

Environment Variables

ACCOUNT_SID=AC0123456789abcdef0123456789abcdef
AUTH_TOKEN=0123456789abcdef0123456789abcdef
FROM_NUMBER=+15551234567
PORT=8080
MODE=dev                    # dev, test, prod-like
DELAY=1s                    # Delivery delay
FAILURE_RATE=0.0            # 0.0 to 1.0

YAML Configuration

account_sid: ACtest
auth_token: test_token
from_number: "+15551234567"
port: 8080
mode: dev
delay: 1s
failure_rate: 0.0

SDK Usage

package main

import (
	"context"
	"log"

	"github.com/46labs/twilio/pkg/client"
)

func main() {
	cfg := client.Config{
		AccountSID: "ACtest",
		AuthToken:  "test_token",
		BaseURL:    "http://localhost:8080", // or https://api.twilio.com
		FromNumber: "+15551234567",
	}

	c, err := client.New(cfg)
	if err != nil {
		log.Fatal(err)
	}

	req := &client.SendSMSRequest{
		To:   "+14155552345",
		Body: "Hello from Twilio!",
	}

	resp, err := c.SendSMS(context.Background(), req)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("Message sent: %s (status: %s)", resp.SID, resp.Status)
}

API Endpoints

Create Message

POST /2010-04-01/Accounts/{AccountSid}/Messages.json
Authorization: Basic {base64(AccountSid:AuthToken)}
Content-Type: application/x-www-form-urlencoded

To=+14155552345
From=+15551234567
Body=Message text
StatusCallback=https://example.com/callback (optional)

Response (201):

{
  "sid": "SMxxxxx",
  "account_sid": "ACtest",
  "from": "+15551234567",
  "to": "+14155552345",
  "body": "Message text",
  "status": "queued",
  "direction": "outbound-api",
  "date_created": "Mon, 12 Jan 2026 12:00:00 +0000",
  "date_sent": null,
  "date_updated": "Mon, 12 Jan 2026 12:00:00 +0000"
}

Get Message

GET /2010-04-01/Accounts/{AccountSid}/Messages/{MessageSid}.json
Authorization: Basic {base64(AccountSid:AuthToken)}

Create Verification (Verify v2)

POST /v2/Services/{ServiceSid}/Verifications
Authorization: Basic {base64(AccountSid:AuthToken)}
Content-Type: application/x-www-form-urlencoded

To=+15551230001
Channel=sms

Per-number behavior is driven by the phone_numbers seed (see Configuration):

  • line_type: landline → 400 with Twilio error 60205 (SMS not supported by landline)
  • valid: false → 400 with Twilio error 60200 (invalid To)
  • otherwise → 201, status pending, a 6-digit code is generated and stored

Generated codes are visible at GET /status/verify for tests.

Check Verification

POST /v2/Services/{ServiceSid}/VerificationCheck
Authorization: Basic {base64(AccountSid:AuthToken)}
Content-Type: application/x-www-form-urlencoded

To=+15551230001
Code=123456

Matches Twilio behavior: a wrong code returns 200 with status: pending (so the caller can retry); a correct code returns status: approved, valid: true. If no pending verification exists for To/VerificationSid, 404 is returned.

Lookup (Lookup v2)

GET /v2/PhoneNumbers/{E164}?Fields=line_type_intelligence
Authorization: Basic {base64(AccountSid:AuthToken)}

Returns the seeded classification (mobile, landline, nonFixedVoip, etc.) and carrier metadata. Unseeded numbers default to type: mobile. Numbers seeded with valid: false return 404.

Status Endpoints (Dev Only)

GET    /status          # List all SMS messages
DELETE /status          # Clear SMS messages
GET    /status/verify   # List verifications (includes the generated code)
DELETE /status/verify   # Clear verifications
GET    /status/lookup   # List seeded phone numbers
DELETE /status/lookup   # Clear seeded phone numbers
GET    /status/email    # List emails
DELETE /status/email    # Clear emails

Seeding Phone Numbers

The phone_numbers block in config.yaml (or unmarshalled via config.WithPhoneNumbers(...)) drives both Verify and Lookup:

phone_numbers:
  - phone_number: "+15551230001"
    line_type: mobile          # mobile | landline | fixedVoip | nonFixedVoip | tollFree | personal | unknown
    carrier_name: "Verizon"
    mobile_country_code: "310"
    mobile_network_code: "012"
    valid: true
  - phone_number: "+15551230002"
    line_type: landline        # Verify will reject SMS to this number with 60205
    valid: true
  - phone_number: "+15551239999"
    valid: false               # Lookup 404 + Verify 60200

Modes

  • dev: All messages succeed immediately, 1s delay
  • test: Support failure injection via headers
  • prod-like: Random failures, realistic delays

Integration

Add to your go.mod:

require github.com/46labs/twilio v0.1.0

Configure for your service:

TWILIO_ACCOUNT_SID=ACtest
TWILIO_AUTH_TOKEN=test_token
TWILIO_BASE_URL=http://localhost:8080           # Mock
# TWILIO_BASE_URL=https://api.twilio.com        # Production
TWILIO_FROM_NUMBER=+15551234567

Testing

# Run all tests
just ci

# Or directly
go test -v ./...

# With linting
golangci-lint run

Building

# Local binary
go build -o bin/twilio ./cmd

# Docker image
docker build -t twilio:dev .

# Multi-arch (via CI)
# Automatically builds for linux/amd64 and linux/arm64

Use Cases

  • Local Development: Replace Twilio in development environments
  • Testing: Automated testing without external dependencies
  • CI/CD: Integration tests with SMS delivery simulation
  • Demos: Quick setup for proof-of-concepts

Differences from Real Twilio

This is a mock service for development and testing. Key differences:

  1. No Actual SMS: Messages are simulated, not sent
  2. In-Memory Storage: Messages are not persisted
  3. Simplified API: Only essential Messaging API endpoints
  4. No Rate Limiting: Unlimited requests
  5. No Production Security: Use only for development/testing

License

See LICENSE for details.

About

Twilio Mock for SMS & Email

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages