Documentation Index
Fetch the complete documentation index at: https://docs.usenotra.com/llms.txt
Use this file to discover all available pages before exploring further.
The notra crate is a community-maintained Rust SDK for the Notra API. It provides typed request builders, response structs, and async support via tokio.
Installation
Add the crate to your Cargo.toml:
[dependencies]
notra = "0.1.1"
tokio = { version = "1", features = ["full"] }
Quick Start
use notra::Notra;
#[tokio::main]
async fn main() -> Result<(), notra::NotraError> {
let notra = Notra::builder()
.bearer_auth(std::env::var("NOTRA_API_KEY").unwrap())
.build()?;
let result = notra.content()
.list_posts()
.send()
.await?;
for post in &result.posts {
println!("{} ({})", post.title, post.id);
}
Ok(())
}
Authentication
Pass your API key via the builder:
use notra::Notra;
let notra = Notra::builder()
.bearer_auth(std::env::var("NOTRA_BEARER_AUTH").unwrap())
.build()?;
You can also configure a custom base URL and timeout:
use std::time::Duration;
use notra::Notra;
let notra = Notra::builder()
.bearer_auth("your-api-key")
.server_url("https://api.usenotra.com") // default
.timeout(Duration::from_secs(60)) // default: 30s
.build()?;
Posts
List posts
use notra::Notra;
use notra::models::{PostStatus, Sort};
let result = notra.content()
.list_posts()
.status(PostStatus::Published)
.sort(Sort::Desc)
.limit(10)
.page(1)
.send()
.await?;
for post in &result.posts {
println!("{}", post.title);
}
println!(
"Page {} of {}",
result.pagination.current_page,
result.pagination.total_pages.unwrap_or(1)
);
Get a single post
let result = notra.content()
.get_post("post_abc")
.send()
.await?;
if let Some(post) = result.post {
println!("{}: {}", post.title, post.status);
}
Update a post
use notra::models::PostStatus;
let updated = notra.content()
.update_post("post_abc")
.title("Ship notes for week 11")
.markdown("# Ship notes\n\nWe shipped a faster editor.")
.status(PostStatus::Published)
.send()
.await?;
println!("{:?}", updated.post);
Delete a post
notra.content()
.delete_post("post_abc")
.send()
.await?;
Post Generation
Queue a generation job
use notra::models::*;
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 job status
let status = notra.content()
.get_post_generation("job-id")
.send()
.await?;
println!("Status: {:?}", status.job.status);
for event in &status.events {
println!(" {} at {}", event.event_type, event.created_at);
}
Brand Identities
List brand identities
let result = notra.content()
.list_brand_identities()
.send()
.await?;
for bi in &result.brand_identities {
println!("{} (default: {})", bi.name, bi.is_default);
}
Generate a brand identity from a website
let job = notra.content()
.create_brand_identity("https://example.com")
.name("My Brand")
.send()
.await?;
// Poll for completion
let status = notra.content()
.get_brand_identity_generation(&job.job.id)
.send()
.await?;
println!("Step: {:?}, Status: {:?}", status.job.current_step, status.job.status);
Update a brand identity
use notra::models::{ToneProfile, Language};
let updated = notra.content()
.update_brand_identity("identity-id")
.name("Updated Brand")
.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 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")
.auth_token("ghp_xxx") // optional, for private repos
.send()
.await?;
println!("Connected: {}", gh.github.display_name);
Disconnect an integration
notra.content()
.delete_integration("integration-id")
.send()
.await?;
Error Handling
The SDK uses a NotraError enum with three variants:
use notra::{Notra, NotraError};
match notra.content().get_post("bad-id").send().await {
Ok(response) => {
if let Some(post) = response.post {
println!("Found: {}", post.title);
}
}
Err(NotraError::Api { status, message }) => {
eprintln!("API error ({}): {}", status, message);
}
Err(NotraError::Http(e)) => eprintln!("Network error: {e}"),
Err(NotraError::Builder(msg)) => eprintln!("Config error: {msg}"),
}
Types
All types are exported under notra::models:
use notra::models::{
Post, PostStatus, ContentType, Sort,
Pagination, Organization,
LookbackWindow, DataPoints, Repository,
BrandIdentity, ToneProfile, Language,
GithubIntegration, LinearIntegration,
PostGenerationJob, JobStatus,
};