arbol-sdk is the Arbol API over HTTPS for Rust services. Its types, operations and client methods are generated from the API’s public OpenAPI document; it uses reqwest with rustls, serde and thiserror, runs on any Tokio runtime and needs Rust 1.85 or newer. The source is on GitHub under the Apache 2.0 license.
Install
The crate isn’t on crates.io yet. Add it as a git dependency, pinned to a commit for reproducible builds:
[dependencies]
arbol-sdk = { git = "https://github.com/getarbol/project-arbol-sdk-rust", rev = "<commit>" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }The library is arbol_sdk. Tokio is listed only for the example’s #[tokio::main]; the crate runs on any Tokio runtime.
Create a client and call an operation
use arbol_sdk::{Client, Credential, types};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let arbol = Client::new(Credential::ApiKey(std::env::var("ARBOL_API_KEY")?))?;
let input = types::AgendaAppointmentsListInput {
from: Some("2026-10-12T00:00:00Z".into()),
to: Some("2026-10-19T00:00:00Z".into()),
..Default::default()
};
let page = arbol.agenda().appointments().list(&input).await?;
println!("{page:?}");
Ok(())
}Every operation is a method named after its operation id: account.apiKeys.create is arbol.account().api_keys().create(&input), with types::AccountApiKeysCreateInput in and types::AccountApiKeysCreateOutput out.
- One credential.
Credential::ApiKeytakes an API key (arb_live_…) for a machine;Credential::AccessTokentakes a person’s access token for the audiencehttps://api.getarbol.com. See Authentication. - HTTPS only.
Client::newcallshttps://api.getarbol.com, and no redirect is followed. - The data, unwrapped. A method returns the
dataof the success envelope. A response larger than its operation’s limit is refused.
Types
Types follow the schema:
- An optional field is
Option<T>and is left out of the request whenNone. - An optional field that may also be null is
Option<Option<T>>:Some(None)sendsnull. - A union is an untagged enum whose members’ literal fields tell them apart.
- What Rust can’t express exactly is a
serde_json::Value.
Errors
Every failure is an arbol_sdk::Error:
| Field | Meaning |
|---|---|
code |
The API’s stable error code, such as FORBIDDEN, or the client’s own: NETWORK_ERROR, REDIRECT_REFUSED, INVALID_RESPONSE. |
message, status, retryable, data |
The error’s message, the HTTP status, the API’s retry hint and the error’s declared data. |
request_id |
The request id to quote when you report a problem. |
outcome |
Refused: nothing happened. NotSent: stopped before the request left. Unknown: a write or delete that may have happened. |
Nothing is retried. A read that fails is Refused or NotSent; only a write or a delete can end Unknown, and then you read the current state before you repeat it:
use arbol_sdk::{Error, Outcome};
fn report(error: &Error) {
match error.outcome {
Outcome::Unknown => eprintln!(
"{} may have been applied; read its state before repeating (request {:?})",
error.code, error.request_id
),
Outcome::Refused | Outcome::NotSent => eprintln!("{}: {}", error.code, error.message),
}
}See Retries.
Versions
The crate is regenerated by hand, so it can trail the API. arbol_sdk::RELEASE names the API release it was generated from, such as 1.20261019.4056, and Cargo.toml records it under [package.metadata.arbol.openapi]. Compare it with the info.version of https://api.getarbol.com/openapi.json: operations added since then aren’t in the crate until it is regenerated. The API is at release 1.20261104.21009 (see Versions and updates).