notra 0.1.0

Unofficial Rust SDK for the Notra API
Documentation

notra

Unofficial Rust SDK for the Notra API.

Crates.io License: MIT

Installation

Add to your Cargo.toml:

[dependencies]
notra = "0.1"
tokio = { version = "1", features = ["full"] }

Quick Start

use notra::Notra;
use notra::models::{ContentType, LookbackWindow, PostStatus};

#[tokio::main]
async fn main() -> Result<(), notra::NotraError> {
    let notra = Notra::builder()
        .bearer_auth("your-api-key")
        .build()?;

    // List all published posts
    let response = notra.content()
        .list_posts()
        .status(PostStatus::Published)
        .limit(10)
        .send()
        .await?;

    for post in &response.posts {
        println!("{} ({})", post.title, post.id);
    }

    Ok(())
}

Usage

Client Configuration

use std::time::Duration;
use notra::Notra;

let notra = Notra::builder()
    .bearer_auth("your-api-key")
    .server_url("https://api.usenotra.com")  // optional, this is the default
    .timeout(Duration::from_secs(60))        // optional, defaults to 30s
    .build()?;

Posts

use notra::models::*;

// List posts with filters
let posts = notra.content()
    .list_posts()
    .status(PostStatus::Published)
    .content_type(ContentType::Changelog)
    .sort(Sort::Desc)
    .limit(20)
    .page(1)
    .send()
    .await?;

// Get a single post
let post = notra.content()
    .get_post("post-id")
    .send()
    .await?;

// Update a post
let updated = notra.content()
    .update_post("post-id")
    .title("Updated Title")
    .markdown("# Hello\n\nNew content here.")
    .status(PostStatus::Published)
    .slug("updated-title")
    .send()
    .await?;

// Delete a post
notra.content()
    .delete_post("post-id")
    .send()
    .await?;

Post Generation

Generate posts from your connected GitHub repositories and Linear integrations:

use notra::models::*;

// Start a generation job
let job = notra.content()
    .create_post_generation(ContentType::Changelog)
    .lookback_window(LookbackWindow::Last7Days)
    .brand_identity_id("brand-id")
    .github_integration_ids(vec!["integration-1".into()])
    .repositories(vec![
        Repository { owner: "my-org".into(), repo: "my-repo".into() },
    ])
    .data_points(DataPoints {
        commits: true,
        pull_requests: true,
        releases: true,
        linear_data: false,
    })
    .send()
    .await?;

println!("Job started: {}", job.job.id);

// Poll for completion
let status = notra.content()
    .get_post_generation(&job.job.id)
    .send()
    .await?;

println!("Status: {:?}", status.job.status);

Brand Identities

use notra::models::*;

// List brand identities
let identities = notra.content()
    .list_brand_identities()
    .send()
    .await?;

// Generate a brand identity from a website
let job = notra.content()
    .create_brand_identity("https://example.com")
    .name("My Brand")
    .send()
    .await?;

// Check generation progress
let status = notra.content()
    .get_brand_identity_generation(&job.job.id)
    .send()
    .await?;

// Get a brand identity
let identity = notra.content()
    .get_brand_identity("identity-id")
    .send()
    .await?;

// Update a brand identity
let updated = notra.content()
    .update_brand_identity("identity-id")
    .name("New Name")
    .tone_profile(ToneProfile::Professional)
    .language(Language::English)
    .audience("Developers")
    .is_default(true)
    .send()
    .await?;

// Delete a brand identity
notra.content()
    .delete_brand_identity("identity-id")
    .send()
    .await?;

Integrations

// List all integrations
let integrations = notra.content()
    .list_integrations()
    .send()
    .await?;

for gh in &integrations.github {
    println!("{}/{} ({})", gh.owner, gh.repo, gh.default_branch);
}

// Connect a GitHub repository
let gh = notra.content()
    .create_github_integration("my-org", "my-repo")
    .branch("main")
    .send()
    .await?;

// Disconnect an integration
notra.content()
    .delete_integration("integration-id")
    .send()
    .await?;

Error Handling

All methods return Result<T, NotraError>. The error type covers HTTP errors, API errors, and client misconfiguration:

use notra::NotraError;

match notra.content().get_post("bad-id").send().await {
    Ok(response) => println!("Found: {}", response.post.unwrap().title),
    Err(NotraError::Api { status: 404, .. }) => println!("Post not found"),
    Err(NotraError::Api { status, message }) => {
        println!("API error ({}): {}", status, message);
    }
    Err(e) => println!("Other error: {e}"),
}

API Reference

All operations are accessible through notra.content():

Method HTTP Description
list_posts() GET /v1/posts List posts with optional filters
get_post(id) GET /v1/posts/{id} Get a single post
update_post(id) PATCH /v1/posts/{id} Update a post
delete_post(id) DELETE /v1/posts/{id} Delete a post
create_post_generation(type) POST /v1/posts/generate Start AI post generation
get_post_generation(job_id) GET /v1/posts/generate/{id} Check generation status
list_brand_identities() GET /v1/brand-identities List brand identities
get_brand_identity(id) GET /v1/brand-identities/{id} Get a brand identity
create_brand_identity(url) POST /v1/brand-identities/generate Generate brand identity from website
get_brand_identity_generation(job_id) GET /v1/brand-identities/generate/{id} Check generation status
update_brand_identity(id) PATCH /v1/brand-identities/{id} Update a brand identity
delete_brand_identity(id) DELETE /v1/brand-identities/{id} Delete a brand identity
list_integrations() GET /v1/integrations List connected integrations
create_github_integration(owner, repo) POST /v1/integrations/github Connect a GitHub repo
delete_integration(id) DELETE /v1/integrations/{id} Disconnect an integration

Disclaimer

This is an unofficial, community-maintained SDK and is not affiliated with or endorsed by Notra. Use at your own discretion.

License

MIT