SignalWire SDK for Rust
Unofficial SignalWire SDK for Rust. Async by default, optional blocking client behind a feature flag.
Features
- JWT auth
- Phone number management (available, owned, buy)
- SMS send + delivery status
- Subproject (account) management
- Phone number lookup & validation (basic / carrier / CNAM)
- Built on
reqwestwithrustls-tls(no OpenSSL) - Real
thiserror-based error type — preserves status code, response body, transport errors - 30s default timeout,
429 Too Many Requestsmapped toRateLimited(Option<Duration>)
Install
[]
= "0.2"
= { = "1", = ["macros", "rt-multi-thread"] }
Blocking client:
[]
= { = "0.2", = ["blocking"] }
Configuration
# .env
SIGNALWIRE_SPACE_NAME=your_space
SIGNALWIRE_PROJECT_ID=your_project_id
SIGNALWIRE_API_KEY=your_api_key
Async usage
Init
use ;
async
Phone numbers
use ;
let q = new.area_code.build;
let available = client.get_phone_numbers_available.await?;
let owned = client
.get_phone_numbers_owned
.await?;
let bought = client.buy_phone_number.await?;
SMS
use SmsMessage;
let msg = SmsMessage ;
let resp = client.send_sms.await?;
println!;
let status = client.get_message_status.await?;
println!; // MessageStatus enum
Subprojects
use SubprojectQueryParams;
let list = client.list_subprojects.await?;
let created = client.create_subproject.await?;
let updated = client.update_subproject.await?;
// signalwire wants Status=closed before delete
client.update_subproject.await?;
client.delete_subproject.await?;
let nums = client
.get_subproject_phone_numbers
.await?;
Lookup
use LookupKind;
let basic = client.lookup_phone_number.await?;
let carrier = client.lookup.await?;
let cnam = client.lookup.await?;
// fields are Option<T> — no implicit defaults
if let Some = basic.valid_number
Blocking usage
Same surface, sync. Built on reqwest::blocking — no hand-rolled tokio runtime per call.
use ;
Error handling
Match on it:
match client.send_sms.await
Custom HTTP client
Inject your own reqwest::Client (custom proxies, headers, TLS config):
let http = builder
.timeout
.build?;
let client = new?
.with_http_client;
Tests
Live integration tests live in tests/live.rs, all #[ignore]-gated. Run manually:
send_sms_costs_money and subproject_lifecycle mutate real resources — keep them gated.
License
Changelog
0.2.0
- Full rewrite. Edition 2024.
- One internal
handle<T>request helper kills ~600 lines of boilerplate. - Blocking client via
reqwest::blocking(was: hand-rolled tokio runtime per call). SignalWireErrorpreserves transport errors, status codes, response bodies. NewRateLimited(Option<Duration>)variant for 429s.SignalWireClient::new/BlockingClient::newreturnResult— noexpect/unwrapin the SDK.- Private fields on the client (was:
pub api_keyetc.). Daum→OwnedPhoneNumber. Dead#[serde(skip_deserializing)]compat fields onPhoneLookupResponseremoved.LookupKindenum + singlelookup(num, kind)method (the three named methods kept as thin wrappers).- One generic
QueryBuilderreplaces four duplicate query-param builders. - Drops
dotenv,serde_derive,chrono,tokio(runtime),urldirect deps.rustls-tlsinstead of native-tls. - 30s default request timeout.
- Tests moved to
tests/live.rs, all#[ignore]-gated.
0.1.8
- Phone number lookup and validation, carrier + CNAM info.
0.1.7
- Subproject (account) management.
0.1.6
- SMS messaging + status checking +
MessageStatusenum +NotFounderror variant.
0.1.5
- Initial release: JWT auth, phone number management, blocking support.