---
title: "Rust SDK"
description: "Add the arbol-sdk crate and call the Arbol API from async Rust."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.getarbol.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rust SDK

`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](https://github.com/getarbol/project-arbol-sdk-rust) 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:

```toml
[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

```rust
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::ApiKey` takes an API key (`arb_live_…`) for a machine; `Credential::AccessToken` takes a person's access token for the audience `https://api.getarbol.com`. See [Authentication](/en/developers/authentication/).
- **HTTPS only.** `Client::new` calls `https://api.getarbol.com`, and no redirect is followed.
- **The data, unwrapped.** A method returns the `data` of 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 when `None`.
- An optional field that may also be null is `Option<Option<T>>`: `Some(None)` sends `null`.
- 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:

```rust
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](/en/developers/concepts/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 (see [Versions and updates](/en/developers/concepts/versions/)).

Source: https://docs.getarbol.com/en/developers/sdks/rust/index.mdx
