truto
Rust SDK for the Truto REST API: async (tokio), typed models generated from Truto's OpenAPI spec, automatic retries and lazy cursor pagination.
Install
Guide: https://truto.one/docs/sdks/rust. API reference: https://docs.rs/truto.
Minimum supported Rust version: 1.88.
Quick start
Every method returns a request builder. Chain options onto it, then .await
it. List methods return a lazy Pager.
use json;
async
Client is cheap to clone (an Arc inside). Use Client::builder() for
settings:
use Duration;
let client = builder
.token
.base_url // default
.timeout // per attempt, default 30s
.max_retries // default 3
.default_retry_after // 429 without Retry-After
.on_retry
.build?;
# Ok::
Unified API with pagination
Unified, Proxy and Custom API items are truto::Record
(serde_json::Map<String, Value>), because their shape depends on the
integration.
use TryStreamExt;
use Query;
# async
The pager copies your query and adds next_cursor for each following page; it
stops when the server returns no cursor. Responses carrying results instead
of result are handled too.
Proxy and Custom APIs
use json;
# async
Query parameters
.query(..) takes a serde_json::Value object, a serde_json::Map, or a
truto::Query. Nested values are encoded like the qs package
(filter[status]=open, ids[0]=a), keys sorted. Repeated .query calls merge.
Admin list endpoints filter on related fields with a dotted key, not a nested
object: the API rejects integration[name]=... but accepts integration.name=....
# use json;
# async
Error handling
All methods return Result<T, truto::Error>:
use ;
# async
Retries and timeouts
Requests are retried on 408, 409, 425, 429, 502, 503 and 504, and on
connection errors (never on timeouts), up to max_retries times. A 429 waits
for the Retry-After header (in seconds, default 10s); other statuses back off
exponentially with full jitter (500ms base, 10s cap). Dropping the future
cancels any wait.
Every request can override these:
use Duration;
# async
Reuse a set of overrides with truto::RequestOptions and .options(opts).
Typed decode
Admin resources return generated models from truto::models. Every struct
decodes leniently (unknown fields ignored, missing fields defaulted), enums
are open (an unknown value becomes Other(String) and serialises back
unchanged), and union types keep the raw JSON with an as_<variant>()
accessor per variant.
For dynamic payloads, decode into your own types with .typed::<T>() on any
request or pager, or truto::decode on a record:
# async
Resources
client.<resource>() for: api_tokens, environments, categories,
teams, users, tenants, link_tokens, session_tokens,
integrated_accounts, sandbox_integrated_accounts, integrations,
environment_integrations, unified_models, environment_unified_models,
unified_model_resource_methods, environment_unified_model_resource_methods,
sync_jobs, sync_job_runs, sync_job_cron_triggers, sync_job_templates,
sync_job_run_states, daemons, daemon_jobs, daemon_job_runs,
daemon_job_cron_triggers, alarms, workflows, workflow_runs, webhooks,
datastores, documentation, logs, static_gates,
observability_destinations, analytics, batch_requests,
environment_integration_webhooks, integrated_account_webhooks,
unified_api, proxy_api, custom_api, mcp; plus client.ping().
logs().list(log_type) takes the log_type the server requires:
unified_proxy_api, rapid_bridge, webhook, mcp or sync_job_cron_trigger.
Examples
TRUTO_API_TOKEN=... TRUTO_API_TOKEN=... TRUTO_API_TOKEN=...
Regenerating the models
src/models/generated.rs is generated from spec/openapi.json. After
updating the spec:
Both scripts need only Python 3. Do not edit the generated file by hand.
Development
Tests run against a local mock server; no network or token is needed.
License
MIT. See LICENSE.