2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00
2025-10-22 17:22:17 +08:00

SMS Gateway API

A Ruby on Rails REST API and WebSocket server for managing SMS messaging through Android gateway devices. This system allows you to send and receive SMS messages programmatically, manage OTP codes, and integrate SMS capabilities into your applications.

Features

  • Gateway Management: Register and manage multiple Android SMS gateway devices
  • Inbound SMS: Receive and process incoming SMS messages
  • Outbound SMS: Send SMS messages through connected gateway devices
  • OTP Management: Generate, send, and verify one-time passwords
  • WebSocket Communication: Real-time bidirectional communication with gateway devices
  • Webhook Support: Trigger webhooks for SMS events
  • Rate Limiting: Protect API endpoints from abuse
  • Load Balancing: Automatically distribute messages across multiple gateways
  • Auto Failover: Retry failed messages and handle gateway offline scenarios

Tech Stack

  • Ruby: 3.4.7
  • Rails: 8.0.3
  • Database: PostgreSQL 14+
  • Cache/Queue: Redis 7+
  • Background Jobs: Sidekiq 7
  • WebSocket: Action Cable (Redis adapter)
  • API Authentication: JWT + API Keys

Prerequisites

  • Ruby 3.4.7
  • PostgreSQL 14+
  • Redis 7+
  • Bundler 2.x

Installation

1. Clone the repository

git clone <repository-url>
cd MySMSAPio

2. Install dependencies

bundle install

3. Set up environment variables

Create a .env file in the root directory:

# Database
DATABASE_URL=postgresql://localhost/my_smsa_pio_development

# Redis
REDIS_URL=redis://localhost:6379/1

# CORS
ALLOWED_ORIGINS=*

# Phone validation
DEFAULT_COUNTRY_CODE=US

# Rails
SECRET_KEY_BASE=your_secret_key_here
RAILS_ENV=development

4. Create and set up the database

bin/rails db:create
bin/rails db:migrate
bin/rails db:seed

Important: Save the API keys displayed after seeding! They won't be shown again.

5. Start Redis (if not running)

redis-server

6. Start Sidekiq (background jobs)

bundle exec sidekiq

7. Start the Rails server

bin/rails server

The API will be available at http://localhost:3000

API Documentation

Base URL

Development: http://localhost:3000
Production: https://your-domain.com

Authentication

All API endpoints (except gateway registration) require an API key in the Authorization header:

Authorization: Bearer your_api_key_here

There are two types of API keys:

  • Gateway Keys: Start with gw_live_ - used by Android gateway devices
  • Client Keys: Start with api_live_ - used by your applications

Gateway Device APIs

Register a New Gateway

Register an Android device as an SMS gateway.

Endpoint: POST /api/v1/gateway/register

Request:

{
  "device_id": "unique-device-identifier",
  "name": "My Gateway Phone"
}

Response (201 Created):

{
  "success": true,
  "api_key": "gw_live_abc123...",
  "device_id": "unique-device-identifier",
  "websocket_url": "ws://localhost:3000/cable"
}

⚠️ Important: Save the api_key immediately. It will only be shown once!

Send Heartbeat

Keep the gateway connection alive and update status.

Endpoint: POST /api/v1/gateway/heartbeat

Headers: Authorization: Bearer gw_live_...

Request:

{
  "status": "online",
  "messages_in_queue": 5,
  "battery_level": 85,
  "signal_strength": 4
}

Response (200 OK):

{
  "success": true,
  "pending_messages": 2
}

Report Received SMS

Submit an SMS message received by the gateway device.

Endpoint: POST /api/v1/gateway/sms/received

Headers: Authorization: Bearer gw_live_...

Request:

{
  "sender": "+1234567890",
  "message": "Hello, this is a test message",
  "timestamp": "2025-10-19T10:30:00Z"
}

Response (200 OK):

{
  "success": true,
  "message_id": "msg_abc123..."
}

Report SMS Delivery Status

Update the delivery status of an outbound SMS.

Endpoint: POST /api/v1/gateway/sms/status

Headers: Authorization: Bearer gw_live_...

Request:

{
  "message_id": "msg_abc123",
  "status": "delivered",
  "error_message": null
}

Status values: delivered, failed, sent

Response (200 OK):

{
  "success": true
}

Client Application APIs

Send SMS

Send an SMS message through the gateway.

Endpoint: POST /api/v1/sms/send

Headers: Authorization: Bearer api_live_...

Request:

{
  "to": "+1234567890",
  "message": "Your verification code is: 123456"
}

Response (202 Accepted):

{
  "success": true,
  "message_id": "msg_xyz789",
  "status": "queued"
}

Check SMS Status

Check the delivery status of a sent message.

Endpoint: GET /api/v1/sms/status/:message_id

Headers: Authorization: Bearer api_live_...

Response (200 OK):

{
  "message_id": "msg_xyz789",
  "status": "delivered",
  "sent_at": "2025-10-19T10:30:00Z",
  "delivered_at": "2025-10-19T10:30:05Z",
  "failed_at": null,
  "error_message": null
}

Get Received SMS

Retrieve inbound SMS messages.

Endpoint: GET /api/v1/sms/received

Headers: Authorization: Bearer api_live_...

Query Parameters:

  • phone_number (optional): Filter by phone number
  • since (optional): ISO 8601 timestamp to filter messages after this time
  • limit (optional): Number of messages per page (default: 50, max: 100)

Response (200 OK):

{
  "messages": [
    {
      "message_id": "msg_abc",
      "from": "+1234567890",
      "message": "Reply message content",
      "received_at": "2025-10-19T10:30:00Z"
    }
  ],
  "total": 25,
  "page": 1,
  "pages": 1
}

OTP APIs

Send OTP

Generate and send a one-time password.

Endpoint: POST /api/v1/otp/send

Headers: Authorization: Bearer api_live_...

Request:

{
  "phone_number": "+1234567890",
  "purpose": "authentication",
  "expiry_minutes": 5
}

Response (200 OK):

{
  "success": true,
  "expires_at": "2025-10-19T10:35:00Z",
  "message_id": "msg_otp123"
}

Rate Limits: Maximum 3 OTP codes per phone number per hour.

Verify OTP

Verify an OTP code.

Endpoint: POST /api/v1/otp/verify

Headers: Authorization: Bearer api_live_...

Request:

{
  "phone_number": "+1234567890",
  "code": "123456"
}

Response (200 OK) - Success:

{
  "success": true,
  "verified": true
}

Response (200 OK) - Failed:

{
  "success": false,
  "verified": false,
  "error": "Invalid or expired OTP",
  "attempts_remaining": 2
}

Admin APIs

List Gateways

Get all registered gateway devices.

Endpoint: GET /api/v1/admin/gateways

Headers: Authorization: Bearer api_live_...

Response (200 OK):

{
  "gateways": [
    {
      "id": 1,
      "device_id": "test-gateway-001",
      "name": "Test Gateway 1",
      "status": "online",
      "last_heartbeat_at": "2025-10-19T10:30:00Z",
      "messages_sent_today": 145,
      "messages_received_today": 23,
      "total_messages_sent": 1543,
      "total_messages_received": 892,
      "active": true,
      "priority": 1,
      "metadata": {},
      "created_at": "2025-10-19T08:00:00Z"
    }
  ]
}

Toggle Gateway Status

Enable or disable a gateway.

Endpoint: POST /api/v1/admin/gateways/:id/toggle

Headers: Authorization: Bearer api_live_...

Response (200 OK):

{
  "success": true,
  "gateway": {
    "id": 1,
    "device_id": "test-gateway-001",
    "active": false
  }
}

Get System Statistics

Get overall system statistics.

Endpoint: GET /api/v1/admin/stats

Headers: Authorization: Bearer api_live_...

Response (200 OK):

{
  "gateways": {
    "total": 2,
    "active": 2,
    "online": 1,
    "offline": 1
  },
  "messages": {
    "total_sent": 5432,
    "total_received": 892,
    "sent_today": 168,
    "received_today": 23,
    "total_today": 191,
    "pending": 3,
    "failed_today": 2
  },
  "otp": {
    "sent_today": 45,
    "verified_today": 42,
    "verification_rate": 93.33
  },
  "timestamp": "2025-10-19T10:30:00Z"
}

WebSocket Connection (Gateway Devices)

Gateway devices connect via WebSocket for real-time bidirectional communication.

Connection URL

ws://localhost:3000/cable?api_key=gw_live_your_key_here

Subscribe to Gateway Channel

{
  "command": "subscribe",
  "identifier": "{\"channel\":\"GatewayChannel\",\"api_key_digest\":\"sha256_hash_of_api_key\"}"
}

Messages from Server

Send SMS Command:

{
  "action": "send_sms",
  "message_id": "msg_123",
  "recipient": "+1234567890",
  "message": "Your OTP is: 123456"
}

Messages to Server

Heartbeat:

{
  "action": "heartbeat",
  "battery_level": 85,
  "signal_strength": 4,
  "messages_in_queue": 0
}

Delivery Report:

{
  "action": "delivery_report",
  "message_id": "msg_123",
  "status": "delivered"
}

Message Received:

{
  "action": "message_received",
  "sender": "+1234567890",
  "message": "Hello",
  "timestamp": "2025-10-19T10:30:00Z"
}

Background Jobs

The system uses Sidekiq for background processing:

Scheduled Jobs

  • CheckGatewayHealthJob: Runs every minute to mark offline gateways
  • CleanupExpiredOtpsJob: Runs every 15 minutes to delete expired OTP codes
  • ResetDailyCountersJob: Runs daily at midnight to reset message counters

Processing Jobs

  • SendSmsJob: Handles outbound SMS delivery
  • ProcessInboundSmsJob: Processes received SMS and triggers webhooks
  • RetryFailedSmsJob: Retries failed messages with exponential backoff
  • TriggerWebhookJob: Executes webhook HTTP calls

Webhooks

Configure webhooks to receive real-time notifications for SMS events.

Webhook Events

  • sms_received: Triggered when an inbound SMS is received
  • sms_sent: Triggered when an outbound SMS is sent
  • sms_failed: Triggered when an SMS fails to send

Webhook Payload Example

{
  "event": "sms_received",
  "message_id": "msg_xyz",
  "from": "+1234567890",
  "message": "Hello",
  "received_at": "2025-10-19T10:30:00Z",
  "gateway_id": "test-gateway-001"
}

Webhook Signature

If a secret_key is configured, webhooks include an HMAC-SHA256 signature in the X-Webhook-Signature header for verification.


Error Responses

All errors follow this format:

{
  "error": "Error message here"
}

Common HTTP status codes:

  • 400 Bad Request: Invalid request parameters
  • 401 Unauthorized: Missing or invalid API key
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Resource not found
  • 422 Unprocessable Entity: Validation errors
  • 429 Too Many Requests: Rate limit exceeded
  • 500 Internal Server Error: Server error

Development

Running Tests

bin/rails test

Code Quality

Check code style:

bin/rubocop

Security scan:

bin/brakeman

Console Access

bin/rails console

Database Console

bin/rails dbconsole

Deployment

Using Kamal

This project is configured for deployment with Kamal.

# Deploy to production
bin/kamal deploy

# View logs
bin/kamal logs

# Access console
bin/kamal console

Environment Variables (Production)

Required environment variables:

DATABASE_URL=postgresql://user:pass@host/database
REDIS_URL=redis://host:6379/1
SECRET_KEY_BASE=your_production_secret
RAILS_ENV=production
ALLOWED_ORIGINS=https://yourdomain.com
DEFAULT_COUNTRY_CODE=US

Monitoring

Health Check

GET /up

Returns 200 if the application is healthy.

Sidekiq Web UI

Mount Sidekiq web interface in config/routes.rb (protect with authentication in production):

require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'

Architecture

┌─────────────────┐         ┌──────────────────┐
│                 │         │                  │
│  Android SMS    │◄───WS──►│  Rails API       │
│  Gateway App    │         │  Action Cable    │
│                 │         │                  │
└─────────────────┘         └────────┬─────────┘
                                     │
                            ┌────────┴─────────┐
                            │                  │
        ┌───────────────────┤  PostgreSQL      │
        │                   │  (Messages, OTP) │
        │                   │                  │
        │                   └──────────────────┘
        │
        │                   ┌──────────────────┐
        │                   │                  │
        └──────────────────►│  Redis           │
                            │  (Cache, Jobs,   │
                            │   WebSockets)    │
                            │                  │
                            └────────┬─────────┘
                                     │
                            ┌────────┴─────────┐
                            │                  │
                            │  Sidekiq         │
                            │  (Background     │
                            │   Jobs)          │
                            │                  │
                            └──────────────────┘

License

MIT License


Support

For issues and questions, please create an issue on GitHub.

Description
No description provided
Readme 215 KiB
Languages
HTML 60%
Ruby 37.1%
Shell 0.9%
Dockerfile 0.9%
JavaScript 0.6%
Other 0.5%