IronDome Rust SDK
Rust integration guide · API reference · Plans and endpoints
An asynchronous client built on reqwest and rustls. Cloning Client shares the
connection pool, immutable credentials, and concurrency admission limit. The SDK
uses a separate Cargo workspace so native HTTP dependencies do not affect the
other workspaces.
Install
Add the SDK to a Tokio application:
[]
= "0.2.0"
= { = "1", = ["macros", "rt-multi-thread"] }
use ;
async
Use a timer-enabled Tokio runtime. Construct once inside application initialization, clone for concurrent tasks, and retain it across checks. Drop all clones after work completes. Creating a reqwest client per request throws away the pool. There is no blocking Rust wrapper and this native client is not a Fastly/Wasm runtime adapter.
Endpoints and bulk checks
Options::default() targets https://api.irondome.dev for the stable account-key API contract. The stable account-key backend is active in production as of 18 October 2026. One account key remains valid across plan changes; the server applies the current plan. Free accounts share 500 checks per organization per month, while paid accounts bypass that quota.
Do not configure the retired free origins (free.irondome.dev or
irondome-free.edgecompute.app). For trusted staging or local TLS tests, set
Options { base_url: "https://staging.example".into(), ..Options::default() }.
Each syntactically valid email in a bulk request counts as one check under the
unified API contract.
client.check_bulk(&["person@example.com", "invalid"]).await? accepts 1?100
strings. Results preserve input order as BulkOutcome::Checked or
BulkOutcome::Invalid, with checked and failed counts. Single request bodies
are limited to 1,024 bytes and bulk bodies to 65,536 bytes. No call retries
automatically; a timed-out request might already have been processed.
Cold-start and connection behavior
Construction performs no network I/O. client.warmup().await optionally sends an
unauthenticated health GET using the same pool. It does not submit a billable email
or validate authorization. Overlap it with independent initialization; do not insert
an extra health round trip before every check. True cold connection setup remains
necessary, and health cannot guarantee a subsequent request uses the same Fastly
sandbox or initialized detector/policy state.
TLS ALPN permits HTTP/2 with HTTP/1.1 fallback. TCP_NODELAY is enabled for small messages; idle connections are retained with a bound. This does not pin a POP or keep a socket alive across process destruction. HTTP/3/0-RTT, active heartbeat pings, IP pinning, and hand-written TLS are intentionally absent.
Configuration
Pass Options { field: value, ..Options::default() }.
| Field | Default | Meaning |
|---|---|---|
base_url |
https://api.irondome.dev |
Trusted unified API origin; old free origins are rejected |
timeout |
5 seconds | Total request deadline through response-body completion |
connect_timeout |
2 seconds | Connection establishment cap |
idle_timeout |
20 seconds | Idle connection expiry policy |
max_idle_connections |
8 | Idle pool capacity per host |
max_in_flight |
64 | Shared fail-fast admission limit across clones |
http1_only |
false | Explicit HTTP/1.1 diagnostic/fallback mode |
additional_root_certificates |
empty | Trusted PEM root certificates merged into trust |
Durations must be positive and at most one day. Admission is bounded to 65,536; idle capacity must be positive and no greater than admission. Active connection count is bounded indirectly by admitted operations, not by a separate socket-count option. An idle-pool bound is not an active HTTP/2 stream bound.
For a shorter individual deadline, wrap the operation in tokio::time::timeout.
Dropping or aborting the operation cancels its future and releases its admission
permit. The server may already have completed a canceled POST. Do not infer that
cancellation means no usage event was emitted.
Contract and failure handling
check(&str) serializes a single email field without normalization. The complete
UTF-8 JSON body must fit 1,024 bytes. Rust strings already guarantee valid UTF-8;
serialization overhead still counts. A verified result includes typed Provider and
Reason enums, valid, disposable, and optional request_id and detector_version.
Invalid/missing fields or inconsistent reason/disposable combinations are protocol
errors. valid means accepted syntax/normalization, not mailbox deliverability.
Error::Api exposes status, allowlisted code, request_id, and optional retry_after.
Unknown HTTP errors use http_error; raw body messages are not retained. Other
variants are Configuration, Validation, Protocol, Transport, Timeout, and Busy.
All variants have safe Display messages. Client Debug output redacts credentials,
and the Authorization header is marked sensitive in reqwest.
Requests are HTTPS-only, redirects and implicit environment proxies are disabled,
certificate/hostname verification remains enabled, and TLS minimum is 1.2. Explicit
tls_sslkeylogfile(false) avoids enabling session-key logging from environment
configuration. Custom CA certificates extend trust; they do not disable validation.
No cookie jar is enabled. Unexpected compression and bodies over 16 KiB fail closed.
Bodies are fully consumed or dropped to release transport resources.
The client explicitly selects reqwest::retry::never(): current reqwest has a
protocol-NACK retry policy by default. Do not assume a library has no retries merely
because application code has no loop. No Idempotency-Key header, classification
cache, or authorization cache is added. A response lost after a successful POST can
still be billable, and a new POST is a distinct request.1
Concurrency and deployment
Use client clones inside a bounded task fan-out. Error::Busy signals local
admission exhaustion, not a service classification. Keep keys/origins in trusted
configuration and create new immutable clients on rotation. Never overwrite one
shared credential for simultaneous tenants. Prevent tracing libraries from recording
request bodies or headers; redacted SDK errors cannot control external instrumentation.
For a serverless Rust process, preserve a client while its runtime stays alive and set deadlines below invocation expiry. Platform freeze/thaw, idle socket closure, DNS/routing changes, and instance replacement can require new connections. There is no SDK promise of immortal TCP state or a particular regional p99 improvement.
Test and review
Integration tests use the shared Python loopback TLS fixture with a generated trusted certificate. They cover reuse across clones, trust/hostname failures, redirect/no-replay behavior, body/schema limits, deadlines, and dropped-future cancellation. Tests require Python 3 and OpenSSL as well as Rust. No production credential or network endpoint is used. Testing distinguishes CI verification from hosted-runtime and production latency acceptance.
See reqwest retry::never and the shared research.