New: unified TypeScript, Python & Rust SDKs — available now in beta.

Rust SDK

Build with the official Forecite Rust SDK.

The official Rust SDK gives you a single typed surface across the Forecite scored feed, the Verdict Engine, reference data, webhooks, and the realtime stream. It's fully async, built on tokio + reqwest + tokio-tungstenite.

Beta

The Rust SDK is in beta while we harden the surface ahead of a stable 1.0. Method names and shapes may still change.

A single Forecite client exposes every resource as a method — feeds_list, providers_get, score, stream — all authenticated with one API key and returning Result<_, ForeciteError>.

Quickstart

Add the dependency

cargo add forecite tokio --features tokio/full

Create a client

Pass your fc_live_… key (get one from the API keys page). Keep it out of source control.

use forecite::Forecite;

let forecite = Forecite::new(std::env::var("FORECITE_API_KEY")?);

Fetch scored feeds

use forecite::{Forecite, FeedsQuery};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let forecite = Forecite::new(std::env::var("FORECITE_API_KEY")?);

    let page = forecite
        .feeds_list(&FeedsQuery {
            symbol: Some("NVDA".into()),
            actionability: Some(true),
            limit: Some(10),
            ..Default::default()
        })
        .await?;

    for item in &page.data {
        println!("{:?} {:?}", item.title, item.scoring.sentiment_score);
    }
    Ok(())
}

SDK patterns

The client uses consistent patterns for configuration, pagination, and errors across every method.

Response models

Reads deserialize into typed serde structs with snake_case fields matching the API. A FeedItem carries the source artifact plus its Verdict Engine scoring block:

pub struct FeedItem {
    pub id: String,
    pub title: Option<String>,
    pub source: String,
    pub published_at: String,
    pub scoring: Scoring,
    pub symbols: Vec<SymbolRef>,
    // …
}

pub struct Scoring {
    pub actionability: Option<bool>,
    pub sentiment_score: Option<i64>, // 0–10 (5 = neutral)
    // …
}

Environment configuration

Production is the default. Use the builder to target local dev or a custom deployment.

use forecite::Forecite;

let forecite = Forecite::builder(std::env::var("FORECITE_API_KEY")?)
    .base_url("http://localhost:3000/api")
    .ws_url("ws://localhost:8080")
    .build();

Pagination

feeds_list returns a FeedList { data, next_cursor }. Pass next_cursor back as cursor to page; a None cursor means you've reached the end.

let mut cursor: Option<String> = None;
loop {
    let page = forecite
        .feeds_list(&FeedsQuery { limit: Some(100), cursor: cursor.clone(), ..Default::default() })
        .await?;
    for item in &page.data {
        // handle(item)
    }
    cursor = page.next_cursor;
    if cursor.is_none() {
        break;
    }
}

Error handling

Every call returns Result<_, ForeciteError>. The Api variant carries the HTTP status and the API's code / message.

use forecite::ForeciteError;

match forecite.feeds_list(&Default::default()).await {
    Ok(page) => { /* … */ }
    Err(ForeciteError::Api { status: 429, .. }) => { /* retry with backoff */ }
    Err(ForeciteError::Api { status: 401, .. }) => { /* bad or missing key */ }
    Err(err) => return Err(err.into()),
}

Feed data

Read the scored feed — list with filters, or fetch a single item by id.

// Filtered list — actionable NVDA items, most bullish first
let page = forecite
    .feeds_list(&FeedsQuery {
        symbol: Some("NVDA".into()),
        actionability: Some(true),
        sentiment_min: Some(7),
        ..Default::default()
    })
    .await?;

// One item with full per-symbol detail
let item = forecite.feeds_get("0b3f2c1e-…").await?;

FeedsQuery fields: since / until (ISO 8601), symbol, exchange, aggregator, actionability, sentiment_min / sentiment_max, limit, cursor.

Discovery

Browse the reference data that powers the feed's filters.

let providers = forecite.providers_list().await?;
let one = forecite.providers_get(&providers[0].id).await?;
let sources = forecite.sources_list().await?; // Vec<String>
let activity = forecite.sources_get("globenewswire").await?;
let symbols = forecite.symbols_list(Some(500)).await?;
let nvda = forecite.symbols_get("NVDA").await?;
let by_dimension = forecite.tags_list().await?;
let corp_activity = forecite.tags_get("corp_activity").await?;

Scoring

Run the Verdict Engine on your own text. Pass an Artifact and optional ScoreOptions.

use forecite::{Artifact, ScoreOptions};

let artifact = Artifact {
    r#type: "filing".into(),
    title: "Acme cuts FY guide on softening demand".into(),
    body: "Acme Corp lowered its full-year revenue outlook…".into(),
    related_symbols: Some(vec!["ACME".into()]),
    ..Default::default()
};

let verdict = forecite
    .score(&artifact, Some(&ScoreOptions { model: Some("pro".into()), ..Default::default() }))
    .await?;

println!("{}", verdict.actionability.score);

Realtime streams

Subscribe to the scored feed over WebSocket. Pull events with next() and match on the StreamEvent variant.

use forecite::{StreamFilters, StreamEvent};

let filters = StreamFilters {
    symbols: Some(vec!["NVDA".into(), "TSLA".into()]),
    ..Default::default()
};

let mut stream = forecite.stream(&filters, 10).await?;

while let Some(event) = stream.next().await? {
    match event {
        StreamEvent::Feed { data, snapshot } => {
            println!("{} {:?}", if snapshot { "backfill" } else { "live" }, data.title);
        }
        StreamEvent::Welcome { tier, .. } => println!("connected: {tier}"),
        StreamEvent::QuotaExceeded { message, .. } => eprintln!("{message}"),
        _ => {}
    }
}

Account

Inspect the authenticated key and its usage.

let key = forecite.me().await?;          // tier, limits
let usage = forecite.usage(14).await?;   // daily feed vs. score usage

Webhooks

Manage outbound webhook endpoints.

use forecite::UpdateWebhook;

let hook = forecite
    .webhooks_create("https://example.com/forecite", Some("prod"))
    .await?;

forecite.webhooks_list().await?;
forecite
    .webhooks_update(&hook.id, &UpdateWebhook { enabled: Some(false), ..Default::default() })
    .await?;
forecite.webhooks_delete(&hook.id).await?;

Changelog

0.1.2

  • First public beta of the forecite crate.
  • Async client for feeds, scoring, discovery, account, webhooks.
  • Realtime feed stream (StreamEvent) with snapshot replay.

On this page