Skip to main content
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, 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 and tokio
  • JSON:API compliant — handles application/vnd.api+json content negotiation

Requirements

  • Rust 1.85+
  • tokio runtime

Installation

Add to your Cargo.toml:
[dependencies]
rootly = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Quick Start

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

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

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

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

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

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

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

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

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):
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:
use rootly::types::{
    Incident,
    IncidentList,
    NewIncident,
    Service,
    Alert,
    Severity,
    Team,
    // ... and many more
};

Configuration

Custom Base URL

use rootly::{RootlyClient, RootlyClientConfig};

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

Quick Setup with Defaults

let client = RootlyClient::from_token("your-token");

API Coverage

Full coverage of the Rootly API v1:
ResourceOperations
Incidentslist, get, create, update, delete
Serviceslist, get, create, update, delete
Alertslist, get, create, update, resolve, snooze, escalate
Teamslist, get, create, update, delete
Severitieslist, get, create, update, delete
Environmentslist, get, create, update, delete
Workflowslist, get, create, update, delete
Playbookslist, get, create, update, delete
Scheduleslist, get, create, update, delete
Escalation Policieslist, get, create, update, delete
Dashboardslist, get, create, update, delete
Status Pageslist, get, create, update, delete
Custom Fieldslist, get, create, update, delete
Catalogslist, get, create, update, delete

Feedback & Support