voip-ms
Async client for the voip.ms REST API.
A thin, idiomatic Rust wrapper around every method exposed by the voip.ms
REST endpoint (https://voip.ms/api/v1/rest.php). Each WSDL operation gets a
typed *Params request struct and methods on Client. The default method
deserializes into a generated *Response struct, and each operation also has
a *_raw variant that returns serde_json::Value.
Installation
[]
= "0.1"
= { = "1", = ["macros", "rt-multi-thread"] }
By default the crate enables rustls with system root certificates. To use a
different TLS backend:
# Embed Mozilla's roots (good for scratch/distroless images):
= { = "0.1", = false, = ["rustls-tls-webpki-roots"] }
# Use the platform's native TLS stack:
= { = "0.1", = false, = ["native-tls"] }
Authentication
voip.ms uses two pieces of credential, both of which you control entirely:
api_username— your account email.api_password— a distinct password generated on the SOAP and REST/JSON API page in the voip.ms customer portal.
You must also allow-list the source IP address(es) you'll be calling from on
that same page. This crate does not load credentials from the environment,
files, or any other source — pass them when you construct the Client.
Usage
use ;
async
Every API method follows the same pattern: construct a *Params struct
(every field is Option<T> and omitted from the request when None), then
call either:
client.some_method(...)for typed deserialization into the generatedSomeMethodResponsestruct, orclient.some_method_raw(...)for a rawserde_json::Valueenvelope.
use ;
async
Customizing the HTTP client
Use Client::builder to plug in your own reqwest::Client — for proxies,
custom timeouts, retry middleware, or anything else you'd configure on
reqwest directly.
use Duration;
use Client;
let http = builder
.timeout
.build
.unwrap;
let client = builder
.http_client
.build
.unwrap;
Typed responses
The WSDL doesn't describe response shapes (all 222 operations declare the
same generic arrayResponse), so this crate generates per-method *Response
structs inferred from the official HTML docs. Each unsuffixed method returns
its generated *Response type, and *_raw is available as an escape hatch
when you want the full JSON envelope:
use ;
async
All fields in the generated *Response structs are Option<T> so unknown
omissions or future shape drift don't fail deserialization. If you need a
shape the generated struct doesn't capture, use *_raw and deserialize
manually, or drop down to call / call_at with your own type.
For methods where you only want a nested field, use
Client::call_at with a JSON pointer:
use Deserialize;
use ;
async
Running the examples
The examples/ directory contains small runnable programs that
read credentials from VOIP_MS_USERNAME and VOIP_MS_PASSWORD:
VOIP_MS_USERNAME=you@example.com \
VOIP_MS_PASSWORD=your-api-password \
VOIP_MS_USERNAME=you@example.com \
VOIP_MS_PASSWORD=your-api-password \
VOIP_MS_USERNAME=you@example.com \
VOIP_MS_PASSWORD=your-api-password \
VOIP_MS_FROM_DID=5551234567 \
VOIP_MS_TO=5557654321 \
VOIP_MS_MESSAGE="Hello from Rust" \
send_sms requires a DID with SMS enabled. You can pass the message body either
through VOIP_MS_MESSAGE or as the first argument after --.
Calling methods this crate hasn't been regenerated for
If voip.ms adds an API method that isn't yet in this crate, use
Client::call_raw directly with a serde-serializable parameter set:
use Client;
async
Error model
All errors surface through voip_ms::Error. The three variants are:
Error::Http— the request failed at the transport or HTTP-status level.Error::Api(ApiStatus)— the response was a well-formed JSON envelope but thestatusfield was something other thansuccess(e.g.invalid_credentials,missing_method,api_not_enabled). The wire string is exposed verbatim — the set of values is per-method and not stable, so consult the voip.ms documentation for the methods you use.Error::InvalidResponse— the response was not the expected JSON envelope (e.g. missingstatusfield).
Development and release
Contributor and maintainer workflows (regeneration, verification, and release) are documented in DEVELOPMENT.md.
See AGENTS.md for design decisions and project-specific guidance.
License
Licensed under the MIT license.