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

# Rust SDK

> Strongly-typed Rust client for the Rootly API, generated from the OpenAPI spec with full async/await support, builder patterns, and complete API coverage.

The Rootly Rust SDK (`rootly-rs`) is a strongly-typed client for the Rootly API. Types and methods are generated directly from the OpenAPI specification using [Progenitor](https://github.com/oxidecomputer/progenitor), giving you full type safety for every endpoint, parameter, and response.

## Features

* **Full coverage** — every API operation with builder pattern
* **Strongly typed** — every endpoint, parameter, and response is a Rust type
* **Async/await** — powered by [reqwest](https://github.com/seanmonstar/reqwest) and [tokio](https://tokio.rs)
* **JSON:API compliant** — handles `application/vnd.api+json` content negotiation

## Requirements

* Rust 1.85+
* tokio runtime

## Installation

Add to your `Cargo.toml`:

```toml theme={null}
[dependencies]
rootly = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

## Quick Start

```rust theme={null}
use rootly::RootlyClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = RootlyClient::from_token(std::env::var("ROOTLY_API_TOKEN")?);

    let response = client.client().list_incidents().page_size(10).send().await?;

    for item in &response.data {
        println!("{}: {}", item.id, item.attributes.title);
    }

    Ok(())
}
```

### Getting an API Key

1. Log in to your Rootly account
2. Navigate to **Settings** > **API Keys**
3. Create a new API key with the permissions you need

## Usage

### List Incidents

```rust theme={null}
let response = client
    .client()
    .list_incidents()
    .filter_status("started".to_string())
    .page_number(1)
    .page_size(10)
    .include("causes,services".to_string())
    .send()
    .await?;

for item in &response.data {
    println!(
        "[{}] {} ({})",
        item.id,
        item.attributes.title,
        item.attributes.status.as_deref().unwrap_or("unknown"),
    );
}
```

### Get an Incident

```rust theme={null}
let response = client
    .client()
    .get_incident()
    .id("abc123")
    .include("sub_statuses,causes,subscribers".to_string())
    .send()
    .await?;

let incident = &response.data.attributes;
println!("Title: {}", incident.title);
println!("Summary: {}", incident.summary.as_deref().unwrap_or(""));
```

### Create an Incident

```rust theme={null}
use rootly::types::{NewIncident, NewIncidentData, NewIncidentDataAttributes, NewIncidentDataType};

let body = NewIncident::builder()
    .data(
        NewIncidentData::builder()
            .type_(NewIncidentDataType::Incidents)
            .attributes(
                NewIncidentDataAttributes::builder()
                    .title("Service degradation".to_string())
                    .summary("Users experiencing elevated latency".to_string())
                    .severity_id("sev-1".to_string()),
            ),
    )
    .build()
    .unwrap();

let response = client.client().create_incident().body(body).send().await?;
```

### Update an Incident

```rust theme={null}
use rootly::types::{UpdateIncident, UpdateIncidentData, UpdateIncidentDataAttributes, UpdateIncidentDataType};

let body = UpdateIncident::builder()
    .data(
        UpdateIncidentData::builder()
            .type_(UpdateIncidentDataType::Incidents)
            .attributes(
                UpdateIncidentDataAttributes::builder()
                    .summary("Root cause identified — deploying fix".to_string()),
            ),
    )
    .build()
    .unwrap();

let response = client
    .client()
    .update_incident()
    .id("abc123")
    .body(body)
    .send()
    .await?;
```

### List Services

```rust theme={null}
let response = client.client().list_services().page_size(50).send().await?;

for svc in &response.data {
    println!("{}: {}", svc.id, svc.attributes.name);
}
```

### Create an Alert

```rust theme={null}
use rootly::types::{NewAlert, NewAlertData, NewAlertDataAttributes, NewAlertDataType};

let body = NewAlert::builder()
    .data(
        NewAlertData::builder()
            .type_(NewAlertDataType::Alerts)
            .attributes(
                NewAlertDataAttributes::builder()
                    .summary("High error rate on payments service".to_string())
                    .source("datadog".to_string()),
            ),
    )
    .build()
    .unwrap();

let response = client
    .client()
    .create_alert()
    .alerts_source_id("src-123")
    .body(body)
    .send()
    .await?;
```

### Pagination

```rust theme={null}
let mut page = 1;
loop {
    let response = client
        .client()
        .list_incidents()
        .page_number(page)
        .page_size(25)
        .send()
        .await?;

    let data = response.into_inner();
    if data.data.is_empty() {
        break;
    }

    for item in &data.data {
        println!("{}: {}", item.id, item.attributes.title);
    }

    page += 1;
}
```

### Error Handling

```rust theme={null}
use rootly::ClientError;

match client.client().get_incident().id("nonexistent").send().await {
    Ok(response) => println!("Found: {}", response.data.attributes.title),
    Err(ClientError::ErrorResponse(resp)) => {
        eprintln!("API error {}: {}", resp.status(), resp.status());
    }
    Err(e) => eprintln!("Request failed: {e}"),
}
```

### Retry with Backoff

For handling rate limits (HTTP 429):

```rust theme={null}
use rootly::retry::{with_backoff, RateLimitConfig};

let config = RateLimitConfig {
    max_retries: 5,
    initial_backoff_ms: 500,
};

let response = with_backoff(config, || {
    client.client().list_incidents().page_size(100).send()
}).await?;
```

## Using Types

All generated types are available under `rootly::types`:

```rust theme={null}
use rootly::types::{
    Incident,
    IncidentList,
    NewIncident,
    Service,
    Alert,
    Severity,
    Team,
    // ... and many more
};
```

## Configuration

### Custom Base URL

```rust theme={null}
use rootly::{RootlyClient, RootlyClientConfig};

let client = RootlyClient::new(RootlyClientConfig {
    token: "your-token".into(),
    base_url: "https://custom.rootly.com".into(),
});
```

### Quick Setup with Defaults

```rust theme={null}
let client = RootlyClient::from_token("your-token");
```

## API Coverage

Full coverage of the Rootly API v1:

| Resource            | Operations                                           |
| ------------------- | ---------------------------------------------------- |
| Incidents           | list, get, create, update, delete                    |
| Services            | list, get, create, update, delete                    |
| Alerts              | list, get, create, update, resolve, snooze, escalate |
| Teams               | list, get, create, update, delete                    |
| Severities          | list, get, create, update, delete                    |
| Environments        | list, get, create, update, delete                    |
| Workflows           | list, get, create, update, delete                    |
| Playbooks           | list, get, create, update, delete                    |
| Schedules           | list, get, create, update, delete                    |
| Escalation Policies | list, get, create, update, delete                    |
| Dashboards          | list, get, create, update, delete                    |
| Status Pages        | list, get, create, update, delete                    |
| Custom Fields       | list, get, create, update, delete                    |
| Catalogs            | list, get, create, update, delete                    |

## Feedback & Support

* **Crate**: [rootly on crates.io](https://crates.io/crates/rootly)
* **Source Code**: [GitHub Repository](https://github.com/rootlyhq/rootly-rs)
* **Issues**: [GitHub Issues](https://github.com/rootlyhq/rootly-rs/issues)
