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

# Rust SDK

> Official Rust client for the Ticksupply API — async-first, builder pattern, typed errors and wire types

The official Rust client is async-first and built on Tokio. The crate is published as [`ticksupply`](https://crates.io/crates/ticksupply); rustdoc is hosted on [docs.rs](https://docs.rs/ticksupply).

<CardGroup cols={3}>
  <Card title="crates.io" icon="rust" href="https://crates.io/crates/ticksupply">
    Releases
  </Card>

  <Card title="docs.rs" icon="book" href="https://docs.rs/ticksupply">
    API reference (rustdoc)
  </Card>

  <Card title="GitHub" icon="github" href="https://github.com/Ticksupply/ticksupply-rust">
    Source & changelog
  </Card>
</CardGroup>

## Install

```toml theme={"system"}
[dependencies]
ticksupply = "0.2"
tokio      = { version = "1", features = ["macros", "rt-multi-thread"] }
```

Or via the CLI:

```bash theme={"system"}
cargo add ticksupply
cargo add tokio --features macros,rt-multi-thread
```

## Quick example

```rust theme={"system"}
use ticksupply::Client;

#[tokio::main]
async fn main() -> ticksupply::Result<()> {
    // Reads TICKSUPPLY_API_KEY from the environment.
    let client = Client::new()?;

    for ex in client.exchanges().list().await? {
        println!("{}: {}", ex.code, ex.display_name);
    }

    let sub = client.subscriptions().create(123).send().await?;
    println!("Subscription: {}", sub.id);
    Ok(())
}
```

## Features

* **Async-first** — every call returns a `Future`; pairs with any Tokio runtime
* **Builder pattern** — typed builders for every mutating endpoint with `.send().await?`
* **Cheap to clone** — `Client` wraps an `Arc`, shares a connection pool, and is `Send + Sync`
* **Automatic retries** — exponential backoff on transient errors and 5xx responses
* **Auto-pagination** — `.stream()` returns a Tokio `Stream` that walks every page
* **Typed errors** — match on `Error::NotFound`, `Error::RateLimited`, etc.; every variant carries the `request_id` from `X-Request-Id`
* **Configurable transport** — override timeout, retry count, base URL, or inject your own `reqwest::Client` for proxies / telemetry
* **Optional types** — Cargo features for `chrono` (default), `time`, and `rust_decimal`
* **Fully documented** — `#![warn(missing_docs)]` is enforced; every public item has rustdoc on [docs.rs](https://docs.rs/ticksupply)

## Configuration

`Client::new()` reads `TICKSUPPLY_API_KEY` from the environment. For more control, use the builder:

```rust theme={"system"}
use std::time::Duration;
use ticksupply::Client;

let client = Client::builder()
    .api_key("key_xxx.secret")
    .timeout(Duration::from_secs(60))
    .max_retries(5)
    .user_agent("my-bot/1.2") // appended to "ticksupply-rust/<version>"
    .build()?;
```

| Setting     | Default                          | Builder method      |
| ----------- | -------------------------------- | ------------------- |
| API key     | `$TICKSUPPLY_API_KEY` (required) | `.api_key(...)`     |
| Base URL    | `https://api.ticksupply.com/v1`  | `.base_url(...)`    |
| Timeout     | 30 s                             | `.timeout(...)`     |
| Max retries | 3                                | `.max_retries(...)` |
| User-Agent  | `ticksupply-rust/<version>`      | `.user_agent(...)`  |
| HTTP client | internal `reqwest::Client`       | `.http_client(...)` |

## Wire types

The API uses string-encoded primitives to preserve precision across implementations. The crate exposes them as small wrapper types that hold the raw wire form losslessly and convert on demand:

| Type        | Wire form                      | Typed accessors                                              |
| ----------- | ------------------------------ | ------------------------------------------------------------ |
| `Nanos`     | `i64` nanoseconds, JSON string | `.as_i64()`; `.to_chrono()` / `.to_time()` (under feature)   |
| `Timestamp` | RFC 3339 string                | `.as_str()`; `.to_chrono()` / `.to_time()` → `Result<...>`   |
| `Decimal`   | decimal string                 | `.as_str()`; `.to_f64()` (lossy); `.to_decimal()` (lossless) |

`Nanos` carries market-data timestamps (preserves nanosecond precision — `f64` would silently round). `Timestamp` carries control-plane timestamps (creation times, activity spans) and round-trips any RFC 3339 variant the server sends. `Decimal` carries amounts where float precision matters (currently `BillingUsage::export_gb_total`).

```rust theme={"system"}
use ticksupply::{Nanos, Timestamp, Decimal};

let n = Nanos::from_i64(1_704_067_200_000_000_000);
let dt = n.to_chrono(); // chrono::DateTime<Utc>, with the chrono feature

let t = Timestamp::from("2024-01-01T00:00:00Z");
let dt = t.to_chrono()?;

let d = Decimal::from("12.75");
let f = d.to_f64();              // Some(12.75) — lossy
let d2 = d.to_decimal();         // rust_decimal, with the rust_decimal feature
```

Request builders that take a timestamp accept anything that implements `IntoTimestamp` — `i64`, `&str`, `String`, `Nanos`, plus `chrono::DateTime<Utc>` (default feature) or `time::OffsetDateTime` (under `time`). So you can pass whatever your call site already uses:

```rust theme={"system"}
client.exports().create(123, chrono::Utc::now() - chrono::Duration::hours(1), chrono::Utc::now())
    .send().await?;

client.exports().create(123, 1_704_067_200_000_000_000_i64, 1_704_070_800_000_000_000_i64)
    .send().await?;
```

## Cargo features

Optional types are gated behind Cargo features so you only pay for what you use:

| Feature        | Default | Effect                                                                             |
| -------------- | ------- | ---------------------------------------------------------------------------------- |
| `chrono`       | yes     | `IntoTimestamp` accepts `chrono::DateTime<Utc>`; `Timestamp` deserializes into one |
| `time`         | no      | Same, but for `time::OffsetDateTime`                                               |
| `rust_decimal` | no      | `Decimal` wire values parse losslessly into `rust_decimal::Decimal`                |

Disable defaults if you only want raw `i64` nanoseconds (`Nanos`) and string timestamps:

```toml theme={"system"}
ticksupply = { version = "0.2", default-features = false }
```

Enable additional features as needed:

```toml theme={"system"}
ticksupply = { version = "0.2", features = ["time", "rust_decimal"] }
```

## Versioning & releases

The crate follows [SemVer](https://semver.org/). Pin to a minor range (`"0.2"`) to receive bug fixes; major bumps (`0.3`, `1.0`) may include breaking API changes documented in [`CHANGELOG.md`](https://github.com/Ticksupply/ticksupply-rust/blob/main/CHANGELOG.md). Every published version has its own rustdoc snapshot at `https://docs.rs/ticksupply/<version>`.

## Requirements

* Rust 1.75 or newer (edition 2021)
* A Tokio-compatible async runtime
* `rustls` for TLS (no system OpenSSL dependency)

<Tip>
  See the [Rust examples](/examples/rust) page for complete usage examples, [docs.rs/ticksupply](https://docs.rs/ticksupply) for the rustdoc API reference, and the [examples/](https://github.com/Ticksupply/ticksupply-rust/tree/main/examples) directory in the repo for runnable programs.
</Tip>
