π API Reference
SMS API Documentation
Authentication
All API requests require authentication via API keys. API keys can be passed in three ways:
1. Authorization Header (Recommended)
curl -H "Authorization: Bearer your_api_key_here" https://api.example.com/api/v1/sms/send
2. X-API-Key Header
curl -H "X-API-Key: your_api_key_here" https://api.example.com/api/v1/sms/send
3. Query Parameter
curl "https://api.example.com/api/v1/sms/send?api_key=your_api_key_here"
SMS API Endpoints
Send SMS Message
Send an SMS message to a recipient.
Endpoint: POST /api/v1/sms/send
Headers:
X-API-Key: your_api_keyContent-Type: application/json
Request Body:
{
"to": "+1234567890",
"message": "Hello, this is your SMS message!"
}
Note: FROM_NUMBER is automatically detected from your app's configured phone numbers! No need to specify it.
Success Response (201 Created):
{
"success": true,
"message": "SMS sent successfully",
"data": {
"id": 123,
"recipient": "+1234567890",
"message": "Hello, this is your SMS message!",
"status": "sent",
"bird_message_id": "msg_abc123",
"sent_at": "2025-08-07T09:15:30Z"
}
}
Error Responses:
// 400 Bad Request - Missing parameters
{
"error": "Recipient is required"
}
// 401 Unauthorized - Invalid API key
{
"error": "Invalid API key"
}
// 422 Unprocessable Entity - SMS service failure
{
"success": false,
"message": "Failed to send SMS",
"error": "Bird API error: Invalid recipient number"
}
Get Message Status
Retrieve the status of a specific SMS message.
Endpoint: GET /api/v1/sms/messages/:id
Headers:
X-API-Key: your_api_key
Success Response (200 OK):
{
"id": 123,
"recipient": "+1234567890",
"message": "Hello, this is your SMS message!",
"status": "delivered",
"bird_message_id": "msg_abc123",
"sent_at": "2025-08-07T09:15:30Z",
"delivered_at": "2025-08-07T09:15:45Z",
"error_message": null,
"organization_id": 5
}
Error Responses:
// 404 Not Found - Message doesn't exist or belongs to different organization
{
"error": "Message not found"
}
// 401 Unauthorized
{
"error": "Invalid API key"
}
List Messages
Get a paginated list of SMS messages for your organization.
Endpoint: GET /api/v1/sms/messages
Headers:
X-API-Key: your_api_key
Query Parameters:
page(optional): Page number (default: 1)per_page(optional): Messages per page (default: 20, max: 100)status(optional): Filter by status (pending,sent,delivered,failed)
Example Request:
curl -H "X-API-Key: your_api_key" \
"https://api.example.com/api/v1/sms/messages?page=1&per_page=10&status=sent"
Success Response (200 OK):
{
"messages": [
{
"id": 123,
"recipient": "+1234567890",
"message": "Hello, this is your SMS message!",
"status": "sent",
"bird_message_id": "msg_abc123",
"sent_at": "2025-08-07T09:15:30Z"
},
{
"id": 122,
"recipient": "+1234567891",
"message": "Another message",
"status": "delivered",
"bird_message_id": "msg_def456",
"sent_at": "2025-08-07T08:30:15Z"
}
],
"pagination": {
"current_page": 1,
"per_page": 10,
"total_pages": 5,
"total_count": 47
}
}
Message Status Types
pending: Message created but not yet sent to Bird APIsent: Message successfully sent to Bird API and accepted for deliverydelivered: Message confirmed delivered to recipient's devicefailed: Message delivery failed (carrier rejection, invalid number, etc.)expired: Message expired before delivery (exceeded TTL)
Get Available From Numbers
Get available phone numbers configured for your app. This is optional since FROM_NUMBER is auto-detected during SMS sending.
Endpoint: GET /api/v1/sms/from-numbers
Headers:
X-API-Key: your_api_key
Example Request:
curl -H "X-API-Key: your_api_key" \
"https://api.example.com/api/v1/sms/from-numbers"
Success Response (200 OK):
{
"app_name": "Guide Genetics Family History",
"phone_numbers": [
{
"number": "+18882127786",
"label": "Primary SMS",
"channel_id": "ce1de3ed-3fb0-439c-b5e8-94a95aa8e6ae"
}
],
"default_from_number": "+18882127786"
}
Use Cases:
- Display which phone number will be used for SMS sending
- Show users available phone numbers if an app has multiple configured
- Validate phone number configuration before sending messages
Technical Architecture
Bird SMS Integration
The SMS API integrates with Bird's platform using their connector-based architecture. Understanding this architecture helps explain how phone numbers and channels work:
Architecture Overview:
Your App Configuration
βββ Phone Numbers (User-facing)
β βββ Number: "+18882127279"
β βββ Label: "SMS - Secondary πΊπΈ"
β βββ Channel ID: "ea07f819-e8cb-56e9-bf5f-c62983fcc624"
β
Bird Workspace
βββ Connectors (8381371c-27ba-4e0d-bbea-0ccfb0bf84fa)
β βββ Channel Object
β β βββ channelId: "ea07f819-e8cb-56e9-bf5f-c62983fcc624" β Used for SMS sending
β β βββ platform: "sms-messagebird"
β βββ Number Object
β β βββ phoneNumber: "+18882127279"
β β βββ numberId: "01985b46-c1e4-7285-bef9-897a5c8efbf0"
β βββ Configuration...
Automatic Channel Resolution: The SMS API automatically handles the mapping between your app's phone number configuration and Bird's channel system:
- Configuration Storage: Your app stores phone numbers with their associated channel IDs
- Smart Resolution: The API detects if stored IDs are connector IDs and automatically resolves to channel IDs
- Backward Compatibility: Existing configurations work seamlessly without manual updates
- Dynamic Updates: Changing phone numbers updates the channel mapping automatically
SMS Sending Flow:
1. API receives SMS request with your API key
2. System identifies your organization and app
3. App's phone numbers are checked for available channels
4. If connector ID is stored, it's resolved to channel ID
5. SMS sent via Bird API using correct channel ID
6. Response mapped back to your message tracking
This architecture ensures that:
- Phone number changes don't require new API keys
- Multiple apps can use different phone numbers seamlessly
- Bird API changes are handled transparently
- Debugging information is comprehensive
Error Handling
Common HTTP Status Codes
- 200 OK: Request successful
- 201 Created: Resource created successfully
- 400 Bad Request: Invalid request parameters
- 401 Unauthorized: Authentication required or invalid
- 404 Not Found: Resource not found
- 422 Unprocessable Entity: Request valid but cannot be processed
- 500 Internal Server Error: Server error
Error Response Format
All errors return JSON in this format:
{
"error": "Error description here"
}
For validation errors:
{
"error": "Recipient (to) and message are required"
}
Rate Limiting
Note: Rate limiting is not currently implemented but is planned for future releases.
Code Examples
Ruby
require 'httparty'
class SmsClient
def initialize(api_key, base_url)
@api_key = api_key
@base_url = base_url
end
def send_sms(recipient, message)
HTTParty.post(
"#{@base_url}/api/v1/sms/send",
headers: { 'X-API-Key' => @api_key, 'Content-Type' => 'application/json' },
body: { recipient: recipient, message: message }.to_json
)
end
def get_message(id)
HTTParty.get(
"#{@base_url}/api/v1/sms/messages/#{id}",
headers: { 'X-API-Key' => @api_key }
)
end
def list_messages(page: 1, per_page: 20, status: nil)
params = { page: page, per_page: per_page }
params[:status] = status if status
HTTParty.get(
"#{@base_url}/api/v1/sms/messages",
headers: { 'X-API-Key' => @api_key },
query: params
)
end
end
# Usage
client = SmsClient.new('your_api_key', 'https://sms.guidegenetics.com')
response = client.send_sms('+1234567890', 'Hello from Ruby!')
puts response.parsed_response
Node.js
class SmsClient {
constructor(apiKey, baseUrl) {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
}
async sendSms(recipient, message) {
const response = await fetch(`${this.baseUrl}/api/v1/sms/send`, {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({ recipient, message })
});
return await response.json();
}
async getMessage(id) {
const response = await fetch(`${this.baseUrl}/api/v1/sms/messages/${id}`, {
headers: { 'X-API-Key': this.apiKey }
});
return await response.json();
}
async listMessages({ page = 1, perPage = 20, status = null } = {}) {
const params = new URLSearchParams({ page, per_page: perPage });
if (status) params.append('status', status);
const response = await fetch(`${this.baseUrl}/api/v1/sms/messages?${params}`, {
headers: { 'X-API-Key': this.apiKey }
});
return await response.json();
}
}
// Usage
const client = new SmsClient('your_api_key', 'https://sms.guidegenetics.com');
const result = await client.sendSms('+1234567890', 'Hello from Node.js!');
console.log(result);
Python
import requests
class SmsClient:
def __init__(self, api_key, base_url):
self.api_key = api_key
self.base_url = base_url
self.headers = {'X-API-Key': api_key}
def send_sms(self, recipient, message):
response = requests.post(
f"{self.base_url}/api/v1/sms/send",
headers={**self.headers, 'Content-Type': 'application/json'},
json={'recipient': recipient, 'message': message}
)
return response.json()
def get_message(self, message_id):
response = requests.get(
f"{self.base_url}/api/v1/sms/messages/{message_id}",
headers=self.headers
)
return response.json()
def list_messages(self, page=1, per_page=20, status=None):
params = {'page': page, 'per_page': per_page}
if status:
params['status'] = status
response = requests.get(
f"{self.base_url}/api/v1/sms/messages",
headers=self.headers,
params=params
)
return response.json()
# Usage
client = SmsClient('your_api_key', 'https://sms.guidegenetics.com')
result = client.send_sms('+1234567890', 'Hello from Python!')
print(result)
cURL Examples
Send SMS:
curl -X POST https://sms.guidegenetics.com/api/v1/sms/send \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"to": "+1234567890",
"message": "Hello from cURL!"
}'
Get message status:
curl -H "X-API-Key: your_api_key_here" \
https://sms.guidegenetics.com/api/v1/sms/messages/123
List messages:
curl -H "X-API-Key: your_api_key_here" \
"https://sms.guidegenetics.com/api/v1/sms/messages?page=1&per_page=10&status=sent"
Testing Your Integration
Test with Invalid API Key
curl -X POST https://sms.guidegenetics.com/api/v1/sms/send \
-H "X-API-Key: invalid_key" \
-H "Content-Type: application/json" \
-d '{"to": "+1234567890", "message": "Test"}'
Expected: 401 Unauthorized
Test with Missing Parameters
curl -X POST https://sms.guidegenetics.com/api/v1/sms/send \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"to": "+1234567890"}'
Expected: 400 Bad Request
Test Message Retrieval
curl -H "X-API-Key: your_api_key_here" \
https://sms.guidegenetics.com/api/v1/sms/messages/999999
Expected: 404 Not Found
Getting Started for Third-Party Developers
1. Obtain API Access
To integrate with the Guide Genetics SMS API:
- Contact the administrator to get your organization set up
- Receive your API key - a 64-character hex string
- Note the base URL - typically
https://sms.guidegenetics.com - Review rate limits - Currently no limits, but may be added
2. Quick Integration Test
# Test your API key
curl -H "X-API-Key: your_api_key_here" \
https://sms.guidegenetics.com/api/v1/sms/messages
# Expected: JSON array of your messages (may be empty)
3. SDK/Libraries
While no official SDKs exist, the API works with standard HTTP libraries:
- Ruby: HTTParty, Faraday, Net::HTTP
- Python: requests, urllib3
- Node.js: fetch, axios, request (deprecated)
- PHP: Guzzle, curl
- Java: OkHttp, HttpClient
- C#: HttpClient
- Go: net/http package
Integration Patterns
Pattern 1: Simple SMS Notifications
# Ruby example for basic notifications
class SmsNotifier
def initialize(api_key, base_url)
@api_key = api_key
@base_url = base_url
end
def send_notification(recipient, message)
HTTParty.post(
"#{@base_url}/api/v1/sms/send",
headers: { 'X-API-Key' => @api_key, 'Content-Type' => 'application/json' },
body: { recipient: recipient, message: message }.to_json
)
end
end
# Usage
notifier = SmsNotifier.new(ENV['SMS_API_KEY'], ENV['SMS_API_URL'])
response = notifier.send_notification('+1234567890', 'Your order is ready!')
Pattern 2: Bulk SMS with Status Tracking
# Python example for bulk messaging with status tracking
import requests
import time
class BulkSmsManager:
def __init__(self, api_key, base_url):
self.api_key = api_key
self.base_url = base_url
self.headers = {'X-API-Key': api_key, 'Content-Type': 'application/json'}
def send_bulk_sms(self, recipients, message):
message_ids = []
for recipient in recipients:
response = requests.post(
f"{self.base_url}/api/v1/sms/send",
headers=self.headers,
json={'recipient': recipient, 'message': message}
)
if response.status_code == 201:
data = response.json()
message_ids.append(data['data']['id'])
time.sleep(0.1) # Rate limiting courtesy
return message_ids
def check_delivery_status(self, message_ids):
statuses = {}
for msg_id in message_ids:
response = requests.get(
f"{self.base_url}/api/v1/sms/messages/{msg_id}",
headers={'X-API-Key': self.api_key}
)
if response.status_code == 200:
data = response.json()
statuses[msg_id] = {
'recipient': data['recipient'],
'status': data['status'],
'sent_at': data['sent_at']
}
return statuses
# Usage
sms_manager = BulkSmsManager(os.environ['SMS_API_KEY'], os.environ['SMS_API_URL'])
recipients = ['+1234567890', '+1234567891', '+1234567892']
message_ids = sms_manager.send_bulk_sms(recipients, 'Bulk notification message')
# Check status later
time.sleep(30)
statuses = sms_manager.check_delivery_status(message_ids)
print(statuses)
Pattern 3: Checking Delivery Status
// Node.js example for checking delivery status
class SmsStatusChecker {
constructor(apiKey, baseUrl) {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
}
async checkStatus(messageId) {
const response = await fetch(`${this.baseUrl}/api/v1/sms/messages/${messageId}`, {
headers: { 'X-API-Key': this.apiKey }
});
const data = await response.json();
// Check detailed status
if (data.status === 'delivered') {
console.log(`Delivered at: ${data.delivered_at}`);
} else if (data.status === 'failed') {
console.log(`Failed at: ${data.failed_at}`);
console.log(`Error: ${data.error_message}`);
}
return data;
}
}
// Usage
const checker = new SmsStatusChecker('your_api_key', 'https://sms.guidegenetics.com');
const status = await checker.checkStatus(123);
Error Handling Best Practices
Retry Logic
def send_sms_with_retry(api_client, recipient, message, max_retries=3):
for attempt in range(max_retries):
try:
response = api_client.send_sms(recipient, message)
if response.status_code == 201:
return response.json()
elif response.status_code == 429: # Rate limited
time.sleep(2 ** attempt) # Exponential backoff
continue
else:
print(f"API error {response.status_code}: {response.text}")
break
except requests.RequestException as e:
print(f"Network error on attempt {attempt + 1}: {e}")
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
return None
Status Code Handling
class SmsApiError < StandardError; end
class SmsRateLimitError < SmsApiError; end
class SmsAuthError < SmsApiError; end
class SmsValidationError < SmsApiError; end
def handle_sms_response(response)
case response.code
when 201
response.parsed_response
when 400
raise SmsValidationError, response.parsed_response['error']
when 401
raise SmsAuthError, 'Invalid API key'
when 422
raise SmsApiError, response.parsed_response['error']
when 429
raise SmsRateLimitError, 'Rate limit exceeded'
else
raise SmsApiError, "Unexpected error: #{response.code}"
end
end
Production Deployment Checklist
Environment Setup
- [ ] Store API keys in environment variables, not code
- [ ] Use HTTPS for all API calls
- [ ] Implement proper error logging
- [ ] Set up monitoring for API failures
- [ ] Configure retry logic with exponential backoff
- [ ] Validate phone numbers before sending
Security Considerations
- [ ] Never log API keys
- [ ] Rotate API keys regularly
- [ ] Use server-side API calls only (never expose keys in client-side code)
- [ ] Implement IP whitelisting if needed
- [ ] Monitor for unusual usage patterns
Performance Optimization
- [ ] Implement connection pooling
- [ ] Cache message status to reduce API calls
- [ ] Use asynchronous requests for bulk operations
- [ ] Implement circuit breaker pattern for reliability
- [ ] Set appropriate timeouts (recommend 30 seconds)
Frequently Asked Questions
Q: What's the message character limit?
A: While the API doesn't enforce a strict limit, SMS messages over 160 characters may be split into multiple parts by carriers. For best results, keep messages under 160 characters.
Q: Can I schedule messages for future delivery?
A: Not currently supported. Messages are sent immediately when the API is called.
Q: How do I handle international phone numbers?
A: Use E.164 format (e.g., +1234567890). The API accepts various formats but E.164 is recommended.
Q: What happens if Bird API is down?
A: The SMS will be marked as 'failed' in the database. Implement retry logic in your application.
Q: Can I send MMS or rich media?
A: Currently only SMS text messages are supported.
Q: How do I test without sending real SMS?
A: Contact the administrator about setting up a test environment with sandbox credentials.
Troubleshooting Common Issues
Issue: Invalid API key
error
Solution:
- Verify the API key is correct (64-character hex string)
- Check the X-API-Key header is properly set
- Ensure no extra spaces or characters in the key
Issue: Message appears sent but isn't received
Solution:
- Verify the phone number format (use E.164: +1234567890)
- Check if the number is on a carrier blocklist
- Review message content for spam-like characteristics
Issue: Message not found
when checking status
Solution:
- Verify you're using the correct message ID from the send response
- Ensure you're using the same API key that sent the message
- Messages are scoped to your organization only
Issue: Slow API responses
Solution:
- Check your network latency to the API server
- Implement connection reuse in your HTTP client
- Consider using asynchronous requests
Rate Limiting (Future)
Currently no rate limits are enforced, but they may be added in future versions:
- Planned limits: 100 requests/minute, 1000 requests/hour
- Rate limit headers:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset - Best practice: Implement exponential backoff when receiving 429 responses
Support
For technical support or questions about the API, please refer to the admin dashboard or contact the development team.
Webhook Configuration
Delivery Status Webhooks
The SMS API supports receiving real-time delivery status updates from Bird via webhooks. This enables automatic tracking of message delivery, failures, and detailed error information.
Webhook Endpoint: POST /api/v1/webhooks/bird-sms-status
Setup Instructions:
- Deploy the latest API code to your server
- Configure your Bird workspace to send webhooks to:
https://your-domain.com/api/v1/webhooks/bird-sms-status - Select all delivery status events in Bird dashboard
Status Updates Received:
- Message accepted by carrier
- Message delivered to device
- Delivery failures with detailed reasons
- Message expiration
Automatic Updates: When a webhook is received, the following fields are automatically updated:
status- Current delivery statusdelivered_at- Timestamp of successful deliveryfailed_at- Timestamp of failureerror_message- Detailed failure reason including:- Regulatory issues (unregistered sender/content)
- Carrier rejections
- Invalid numbers
- Network issues
Common Failure Reasons:
- Regulatory Compliance:
Sending messages to this network requires registration
- Invalid Number:
The destination number is not valid
- Carrier Rejection:
Message blocked by carrier spam filter
- Network Issues:
Temporary network failure
Monitoring Delivery Status
# Ruby example for monitoring delivery status
class DeliveryMonitor
def check_message_status(message_id)
response = HTTParty.get(
"#{@base_url}/api/v1/sms/messages/#{message_id}",
headers: { 'X-API-Key' => @api_key }
)
data = response.parsed_response
case data['status']
when 'delivered'
puts "β Delivered at #{data['delivered_at']}"
when 'failed'
puts "β Failed: #{data['error_message']}"
puts " Failed at: #{data['failed_at']}"
when 'sent'
puts "β³ Sent, awaiting delivery confirmation"
end
data
end
end
Changelog
v1.2.0 (2025-09-26)
- Major Fix: Resolved Bird SMS connector-to-channel ID mapping issue
- Enhanced Bird API integration with automatic connector resolution
- Improved phone number management with dynamic channel selection
- Added comprehensive debugging and error logging
- Backward compatibility maintained for existing configurations
- Enhanced admin interface for Bird channel selection
- Better error handling and fallback mechanisms
v1.1.0 (2025-08-27)
- Added webhook support for real-time delivery status
- Enhanced status tracking with delivery/failure timestamps
- Detailed error messages for failed deliveries
- Database indexes for improved performance
v1.0.0 (2025-08-07)
- Initial API release
- SMS sending via Bird platform
- Message status tracking
- Multi-tenant app β organization structure
- Token-based authentication
- Admin dashboard interface
Need Help?
If you have questions or need assistance with the API integration, we're here to help.