Home
Home/Developers/SDKs/rust
Ed25519 signaturesSHA-256 hashes8 SDKs
Status
Sign inStart free
Home
Start here
Overview
Authentication
Errors
FAQ
API
Events
Canonical JSON and hashes
Documents
Anchoring a file
AI attestations
Attestation schema
Verifying attestations
Traces
Sealing a trace
Audit logs
Organizations
Streams
Portal
Public proof
Event schema
Exporting events
Integrations
Clerk
Auth0
Embeddable viewer
All endpoints
Reference
SDKs
Node.js
Python
Go
Java
Ruby
Rust
.NET
PHP
REST
Verification
Docs · SDKs

Rust SDK

Install the Rust SDK, build a client, see every method with a Rust sample, and verify records offline.

sha-256 · 3a352297…2592
sha-256 · 971e439d…e24c
RESTNode.jsPythonGoJavaRubyRust.NETPHP
Install

Rust

invoance on crates.io.

Rust 1.86 or later. Async on tokio and reqwest with rustls; no OpenSSL.

Cargo.toml
cargo add invoance

# or in Cargo.toml
[dependencies]
invoance = "0.2"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
Client
api_keyThe API key. Falls back to INVOANCE_API_KEY; build() returns a validation error when neither is set.
base_urlAPI host. Falls back to INVOANCE_BASE_URL, then https://api.invoance.com. Trailing slashes are removed.
api_versionPath prefix put before every request path. Default v1.
timeoutPer-request timeout as a Duration. Default 30 seconds; past it the error answers is_timeout().
idempotency_keyDefault Idempotency-Key header for every mutating request; a per-call key wins.
header(name, value) / extra_headersHeaders merged into every request.
from_configInvoanceClient::from_config(ClientConfig { .. }) takes the same fields as a struct.
RetriesNone. Each request is sent once; when is_timeout() or is_network() is true, retry it yourself with the same idempotency_key.
Rust
use std::time::Duration;
use invoance::InvoanceClient;

#[tokio::main]
async fn main() -> Result<(), invoance::Error> {
    // Reads INVOANCE_API_KEY and INVOANCE_BASE_URL from the environment.
    let client = InvoanceClient::new()?;

    // Or pass options.
    let configured = InvoanceClient::builder()
        .api_key("invoance_live_...")
        .base_url("https://api.invoance.com")
        .timeout(Duration::from_secs(60))
        .build()?;
    let _ = configured;

    // GET /v1/me checks no scope, so any live key passes. Never errors.
    let result = client.validate().await;
    println!("{} {:?}", result.valid, result.reason);
    Ok(())
}
Methods

Every endpoint with a Rust sample, by resource. Open a row for the sample; the link opens the endpoint card with its fields, response and errors.

EventsReference
POST/v1/eventsIngest an event
Rust
use invoance::InvoanceClient;
use invoance::models::IngestEventParams;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let result = client
        .events()
        .ingest(IngestEventParams {
            event_type: "policy.approval".into(),
            event_time: Some("2026-09-22T08:14:07Z".into()),
            payload: json!({
                "policy_id": "pol_8472",
                "approved_by": "risk_committee",
                "decision": "approved",
            })
            .as_object()
            .unwrap()
            .clone(),
            idempotency_key: Some("policy-approval-pol_8472".into()),
            ..Default::default()
        })
        .await?;
    println!("{} {}", result.event_id, result.ingested_at);

    Ok(())
}
Ingest an event: fields, response and errors
GET/v1/eventsList events
Rust
use invoance::InvoanceClient;
use invoance::models::ListEventsParams;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let page = client
        .events()
        .list(ListEventsParams {
            page: Some(1),
            limit: Some(50),
            event_type: Some("policy.approval".into()),
            ..Default::default()
        })
        .await?;
    println!("{} {}", page.total, page.has_more);
    for event in page.events {
        println!("{} {} {}", event.event_id, event.ingested_at, event.payload_hash);
    }

    Ok(())
}
List events: fields, response and errors
GET/v1/events/{event_id}Get an event
Rust
use invoance::InvoanceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let event = client
        .events()
        .get("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4")
        .await?;
    println!("{} {}", event.event_type, event.ingested_at);
    println!("{} {} {}", event.payload_hash, event.event_hash, event.request_hash);
    println!("{:?}", event.payload);

    Ok(())
}
Get an event: fields, response and errors
POST/v1/events/{event_id}/verifyVerify an event
Rust
use invoance::InvoanceClient;
use invoance::models::VerifyEventParams;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let result = client
        .events()
        .verify(
            "7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4",
            VerifyEventParams {
                payload: json!({
                    "policy_id": "pol_8472",
                    "approved_by": "risk_committee",
                    "decision": "approved",
                })
                .as_object()
                .cloned(),
                ..Default::default()
            },
        )
        .await?;
    println!("{} {:?}", result.match_result, result.matched_field);
    println!("{} {} {}", result.anchored_hash, result.submitted_hash, result.anchored_at);

    Ok(())
}
Verify an event: fields, response and errors
DocumentsReference
POST/v1/document/anchorAnchor a document
Rust
// cargo add invoance sha2 hex serde_json tokio --features tokio/full
use invoance::models::AnchorDocumentParams;
use invoance::InvoanceClient;
use serde_json::json;
use sha2::{Digest, Sha256};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = std::fs::read("./INV-2026-0917.pdf")?;
    let document_hash = hex::encode(Sha256::digest(&file));

    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let result = client
        .documents()
        .anchor(AnchorDocumentParams {
            document_hash: document_hash.clone(),
            document_ref: Some("INV-2026-0917.pdf".into()),
            event_type: Some("invoice.issued".into()),
            metadata: json!({
                "invoice_number": "INV-2026-0917",
                "amount": 5230,
                "currency": "USD",
            })
            .as_object()
            .cloned(),
            idempotency_key: Some(format!("anchor-{document_hash}")),
            ..Default::default()
        })
        .await?;
    println!("{} {}", result.event_id, result.status);

    Ok(())
}
Anchor a document: fields, response and errors
GET/v1/documentList documents
Rust
use invoance::models::ListDocumentsParams;
use invoance::InvoanceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let page = client
        .documents()
        .list(ListDocumentsParams {
            limit: Some(25),
            date_from: Some("2026-09-01T00:00:00Z".into()),
            ..Default::default()
        })
        .await?;
    println!("{} {}", page.total, page.has_more);
    for d in &page.documents {
        println!("{} {} {}", d.event_id, d.document_ref, d.has_original);
    }

    Ok(())
}
List documents: fields, response and errors
GET/v1/document/{event_id}Get a document
Rust
use invoance::InvoanceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let doc = client
        .documents()
        .get("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4")
        .await?;
    println!("{} {} {}", doc.document_hash, doc.has_original, doc.created_at);
    if let Some(org) = &doc.organization {
        println!("{} {}", org.issuer_name, org.domain_verified);
    }

    Ok(())
}
Get a document: fields, response and errors
GET/v1/document/{event_id}/originalDownload the original
Rust
use invoance::InvoanceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let data = client
        .documents()
        .get_original("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4")
        .await?;
    std::fs::write("./INV-2026-0917.pdf", &data)?;
    println!("{}", data.len());

    Ok(())
}
Download the original: fields, response and errors
POST/v1/document/{event_id}/verifyVerify a document hash
Rust
// cargo add invoance sha2 hex tokio --features tokio/full
use invoance::models::VerifyDocumentParams;
use invoance::InvoanceClient;
use sha2::{Digest, Sha256};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = std::fs::read("./INV-2026-0917.pdf")?;
    let document_hash = hex::encode(Sha256::digest(&file));

    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let result = client
        .documents()
        .verify(
            "7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4",
            VerifyDocumentParams { document_hash },
        )
        .await?;
    println!("{} {} {}", result.match_result, result.anchored_hash, result.anchored_at);

    Ok(())
}
Verify a document hash: fields, response and errors
AI AttestationsReference
POST/v1/ai/attestationsIngest an attestation
Rust
use invoance::InvoanceClient;
use invoance::models::IngestAttestationParams;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let result = client
        .attestations()
        .ingest(IngestAttestationParams {
            r#type: "output".into(),
            input: "Summarize the termination clause in contract CT-8472.".into(),
            output: "Either party may terminate with 30 days written notice. Early termination fees do not apply after month 12.".into(),
            model_provider: "openai".into(),
            model_name: "gpt-4.1".into(),
            model_version: "2026-04-14".into(),
            subject: json!({
                "user_id": "u_4821",
                "session_id": "sess_9f3a",
                "department": "legal",
            })
            .as_object()
            .cloned(),
            idempotency_key: Some("ct-8472-summary-1".into()),
            ..Default::default()
        })
        .await?;
    println!("{} {}", result.attestation_id, result.payload_hash);

    Ok(())
}
Ingest an attestation: fields, response and errors
GET/v1/ai/attestationsList attestations
Rust
use invoance::InvoanceClient;
use invoance::models::ListAttestationsParams;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let page = client
        .attestations()
        .list(ListAttestationsParams {
            limit: Some(50),
            attestation_type: Some("output".into()),
            model_provider: Some("openai".into()),
            ..Default::default()
        })
        .await?;
    println!("{} {} {}", page.total, page.has_more, page.attestations.len());

    Ok(())
}
List attestations: fields, response and errors
GET/v1/ai/attestations/{attestation_id}Get an attestation
Rust
use invoance::InvoanceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let att = client
        .attestations()
        .get("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4")
        .await?;
    println!("{} {} {}", att.attestation_hash, att.signature_alg, att.public_key);

    Ok(())
}
Get an attestation: fields, response and errors
GET/v1/ai/attestations/{attestation_id}/rawGet the raw payload
Rust
use invoance::InvoanceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let raw = client
        .attestations()
        .get_raw("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4")
        .await?;
    println!("{} {}", raw["type"], raw["context"]["model_name"]);

    Ok(())
}
Get the raw payload: fields, response and errors
POST/v1/ai/attestations/{attestation_id}/verifyVerify a hash
Rust
use invoance::InvoanceClient;
use invoance::models::VerifyAttestationParams;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let result = client
        .attestations()
        .verify(
            "7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4",
            VerifyAttestationParams {
                content_hash: "c4efe15781214a84046ad7e0592977c634a5cf45f4c1e06160daf760a295a8df".into(),
            },
        )
        .await?;
    println!("{} {:?}", result.match_result, result.matched_field);

    Ok(())
}
Verify a hash: fields, response and errors
TracesReference
POST/v1/tracesCreate a trace
Rust
use invoance::InvoanceClient;
use invoance::models::CreateTraceParams;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let trace = client
        .traces()
        .create(CreateTraceParams {
            label: "Invoice batch 2026-09".into(),
            metadata: Some(
                json!({ "batch_id": "b_4471", "region": "eu-west" })
                    .as_object()
                    .unwrap()
                    .clone(),
            ),
        })
        .await?;
    println!("{} {}", trace.trace_id, trace.status);

    Ok(())
}
Create a trace: fields, response and errors
POST/v1/traces/{trace_id}/sealSeal a trace
Rust
use invoance::InvoanceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let sealed = client
        .traces()
        .seal("7c1e4b52-9a0f-4d2e-b6f3-2f8a61c0d9e4")
        .await?;
    println!("{} {}", sealed.status, sealed.message);

    Ok(())
}
Seal a trace: fields, response and errors
Audit LogsReference
POST/v1/audit/eventsIngest an audit event
Rust
use invoance::InvoanceClient;
use invoance::models::IngestAuditEventParams;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let result = client
        .audit()
        .events
        .ingest(IngestAuditEventParams {
            organization_id: "org_8472".into(),
            action: "user.signed_in".into(),
            occurred_at: Some("2026-09-22T08:14:07Z".into()),
            actor: json!({ "type": "user", "id": "u_4821", "name": "Ada Lovelace" })
                .as_object()
                .unwrap()
                .clone(),
            targets: Some(vec![json!({ "type": "workspace", "id": "ws_17" })]),
            context: Some(
                json!({ "location": "203.0.113.10", "user_agent": "Mozilla/5.0" })
                    .as_object()
                    .unwrap()
                    .clone(),
            ),
            metadata: Some(json!({ "method": "sso", "mfa": true }).as_object().unwrap().clone()),
            idempotency_key: Some("signin-u_4821-2026-09-22T08:14:07Z".into()),
        })
        .await?;
    println!("{} {}", result["event_id"], result["ingested_at"]);

    Ok(())
}
Ingest an audit event: fields, response and errors
POST/v1/audit/orgsCreate an audit org
Rust
use invoance::InvoanceClient;
use invoance::models::CreateAuditOrgParams;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let org = client
        .audit()
        .orgs
        .create(CreateAuditOrgParams {
            organization_id: "org_8472".into(),
            name: Some("Acme Robotics".into()),
        })
        .await?;
    println!("{} {}", org["id"], org["retention_days"]);

    Ok(())
}
Create an audit org: fields, response and errors
PlatformReference
GET/v1/meIntrospect the API key
Rust
use invoance::InvoanceClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Reads INVOANCE_API_KEY from the environment.
    let client = InvoanceClient::new()?;

    let me = client.me().await?;
    println!("{}", me["organization"]["primary_domain"]);
    println!("{}", me["limits"]["rate_limit_per_sec"]);

    Ok(())
}
Introspect the API key: fields, response and errors
Verify offlineHow verification works

Two checks run without trusting the server: attestations().verify_signature fetches the record and checks its Ed25519 signature over signed_payload; invoance::verify_audit_event rebuilds the invoance.audit/1 bytes of an audit event (as serde_json::Value) and checks its signature. Pass Some(hex key) from GET /keys/{domain} to pin it instead of the key on the row.

Rust
use invoance::{verify_audit_event, InvoanceClient};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = InvoanceClient::new()?;

    // AI attestation: Ed25519 over signed_payload, checked locally.
    let sig = client
        .attestations()
        .verify_signature("a1d4f8c2-7b3e-4e9a-b5c6-0d2e8f4a7c19")
        .await?;
    println!("{} {:?}", sig.valid, sig.reason);

    // Audit event: canonical bytes rebuilt locally, signature checked
    // against a pinned key (the public_key from GET /keys/{domain}, base64url decoded to hex).
    let pinned_hex_key = "d4443bd9d30ef4c2e0e5db03467e3c5c740358482c1a1e30cdb27a2e02a38176";
    let event = client.audit().events.get("aevt_01J8F3KQ2R7VWX9YB4ND6MCZAH").await?;
    let event_json = serde_json::to_value(&event)?;
    let result = verify_audit_event(&event_json, Some(pinned_hex_key));
    println!("{} {:?} {:?}", result.valid, result.reason, result.key_source); // Pinned
    Ok(())
}

Proof infrastructure. Records are hashed, signed with your organization's Ed25519 key, and stored append-only, so anyone can check them later.

Products

  • Audit Logs
  • Event Ledger
  • AI Attestation
  • Document Anchoring
  • Traces

Developers

  • Documentation
  • API reference
  • SDKs
  • How it works
  • How traces seal
  • System status

Verify

  • Audit Log
  • Event
  • AI Attestation
  • Document
  • Trace

Company

  • Why Invoance
  • Pricing
  • Security
  • Compliance teams
  • Finance teams
  • Partners
  • Resources
  • Help center
  • Contact
© 2026 Invoance
PrivacyLegal noticeLegal FAQGitHubLinkedInX