kwtsms
Rust client for the kwtSMS API. Send SMS, check balance, validate numbers, list sender IDs, check coverage, get delivery reports.
Install
# Cargo.toml
[]
= "0.1"
Or: cargo add kwtsms
Quick Start
use KwtSms;
Environment Variables
Create a .env file or set these environment variables:
KWTSMS_USERNAME=your_api_user
KWTSMS_PASSWORD=your_api_pass
KWTSMS_SENDER_ID=KWT-SMS
KWTSMS_TEST_MODE=1
KWTSMS_LOG_FILE=kwtsms.log
Or pass credentials directly:
let sms = new.unwrap;
API Reference
Verify Credentials
let result = sms.verify;
if result.ok
Send SMS
// Single number
let result = sms.send_one.unwrap;
// Multiple numbers
let result = sms.send.unwrap;
// Custom sender ID
let result = sms.send_one.unwrap;
// Comma-separated
let result = sms.send_one.unwrap;
The send method automatically:
- Normalizes phone numbers (strips +, 00, spaces, dashes, converts Arabic digits)
- Validates each number locally (rejects emails, too short/long, no digits)
- Cleans the message (strips emojis, HTML, invisible chars, converts Arabic digits)
- Deduplicates normalized numbers
- Auto-batches when >200 numbers (200 per batch, 0.5s delay)
Check Balance
let balance = sms.balance; // Option<f64>
Validate Numbers
let result = sms.validate.unwrap;
// Returns: ok[], er[], nr[], rejected[]
Sender IDs
let result = sms.senderids.unwrap;
Coverage
let result = sms.coverage.unwrap;
Message Status
let result = sms.status.unwrap;
Delivery Report (international only)
let result = sms.dlr.unwrap;
Utility Functions
use ;
// Normalize phone number
let phone = normalize_phone; // "96598765432"
// Validate phone input
let = validate_phone_input;
// valid=false, error="'user@gmail.com' is an email address..."
// Clean message text
let cleaned = clean_message;
// "Hello OTP: 123"
Error Codes
All 33 kwtSMS error codes are mapped to developer-friendly action messages:
use ;
// Access the error map directly
if let Some = API_ERRORS.get
Credential Management
Never hardcode credentials. Use one of these approaches:
- Environment variables / .env file (default):
KwtSms::from_env(None)loads from env vars, then.envfile. - Constructor injection:
KwtSms::new(username, password, ...)for custom config systems. - Secrets manager: Load from AWS Secrets Manager, Vault, etc., then pass to the constructor.
Best Practices
Always save msg-id and balance-after
let result = sms.send_one.unwrap;
if result == "OK"
Use Transactional Sender ID for OTP
KWT-SMS is a shared test sender. Register a private Transactional sender ID for OTP messages. Promotional sender IDs are blocked by DND on Zain and Ooredoo, causing silent delivery failure.
Validate locally before calling the API
use validate_phone_input;
let = validate_phone_input;
if !valid
Security Checklist
Before going live:
- Bot protection enabled (CAPTCHA for web)
- Rate limit per phone number (max 3-5/hour)
- Rate limit per IP address (max 10-20/hour)
- Rate limit per user/session if authenticated
- Monitoring/alerting on abuse patterns
- Admin notification on low balance
- Test mode OFF (
KWTSMS_TEST_MODE=0) - Private Sender ID registered (not KWT-SMS)
- Transactional Sender ID for OTP (not promotional)
CLI
Build the CLI binary:
cargo install kwtsms --features cli
Commands:
kwtsms verify # test credentials
kwtsms balance # show credits
kwtsms senderid # list sender IDs
kwtsms coverage # list active prefixes
kwtsms send <mobile> <message> [--sender ID] # send SMS
kwtsms validate <number> [number ...] # validate numbers
kwtsms status <msg-id> # check status
kwtsms dlr <msg-id> # delivery report
Testing
# Unit + mock tests (no credentials needed)
# Integration tests (real API, test mode, no credits consumed)
Publishing to crates.io
# 1. Sign in at https://crates.io (GitHub account)
# 2. Get API token: crates.io -> Account Settings -> New Token
# 3. Publish
# 4. Updates: bump version in Cargo.toml, then:
License
MIT