vynco 2.4.1

Rust SDK for the VynCo Swiss Corporate Intelligence API
Documentation

vynco

Crates.io Documentation CI License: Apache-2.0

Rust SDK for the VynCo Swiss Corporate Intelligence API. Access 780,000+ Swiss companies from the commercial register with historical timelines, change tracking, sanctions screening, AI-powered risk analysis, UBO resolution, network graphs, watchlists, webhooks, market-flow analytics, and bulk data exports.

Installation

[dependencies]
vynco = "2.3"

For the synchronous (blocking) client:

[dependencies]
vynco = { version = "2.3", features = ["blocking"] }

Quick Start

use vynco::{Client, CompanyListParams};

#[tokio::main]
async fn main() -> Result<(), vynco::VyncoError> {
    let client = Client::builder("vc_live_your_api_key").build()?;

    // List companies with filtering
    let params = CompanyListParams {
        search: Some("Novartis".into()),
        canton: Some("BS".into()),
        legal_form: Some("AG".into()),
        sort_by: Some("shareCapital".into()),
        sort_desc: Some(true),
        ..Default::default()
    };
    let resp = client.companies().list(&params).await?;
    println!("Found {} companies", resp.data.total);

    // Get a single company (full details with address, geo, FINMA status, etc.)
    let company = client.companies().get("CHE-105.805.080").await?;
    println!("{}: {:?} ({})", company.data.name, company.data.legal_form,
        company.data.address_city.as_deref().unwrap_or("unknown"));

    // Get full company view (persons, changes, relationships in one call)
    let full = client.companies().get_full("CHE-105.805.080").await?;
    println!("{} board members, {} recent changes",
        full.data.persons.len(), full.data.recent_changes.len());

    // Sanctions screening
    let screening = client.screening().screen(&vynco::ScreeningRequest {
        name: "Suspicious Corp".into(), uid: None, sources: None,
    }).await?;
    println!("Risk: {} ({} hits)", screening.data.risk_level, screening.data.hit_count);

    // AI risk score
    let risk = client.ai().risk_score(&vynco::RiskScoreRequest {
        uid: "CHE-105.805.080".into(),
    }).await?;
    println!("Risk score: {}/100 ({})", risk.data.overall_score, risk.data.risk_level);

    // Credit balance
    let credits = client.credits().balance().await?;
    println!("Credits remaining: {}", credits.data.balance);

    Ok(())
}

Blocking Client

use vynco::blocking::Client;

fn main() -> Result<(), vynco::VyncoError> {
    let client = Client::builder("vc_live_your_api_key")
        .build()?;

    let count = client.companies().count()?;
    println!("Companies: {}", count.data.count);

    Ok(())
}

API Coverage

20 resource modules covering 100+ endpoints:

Resource Methods
health() check
companies() list, get, get_full, count, events, statistics, compare, structure, acquisitions, news, reports, relationships, hierarchy, classification, fingerprint, nearby, timeline, timeline_summary, similar, ubo, media, media_analyze, notes, create_note, update_note, delete_note, tags, create_tag, delete_tag, all_tags, export_csv
auditors() history, tenures
dashboard() get
screening() screen, batch
watchlists() list, create, delete, companies, add_companies, remove_company, events
webhooks() list, create, update, delete, test, deliveries
exports() create, get, download
ai() dossier, search, risk_score, risk_score_batch
api_keys() list, create, revoke
credits() balance, usage, history
billing() create_checkout, create_portal
teams() me, create, members, invite_member, update_member_role, remove_member, billing_summary, join
changes() list, by_company, statistics
persons() board_members, board_members_paged, search, get, network
analytics() cantons, auditors, cluster, anomalies, rfm_segments, cohorts, candidates, flows, migrations, benchmark
dossiers() create, list, get, delete, generate
graph() get, export, analyze
alerts() list, create, delete
ownership() trace

New in v2.3

  • Historical timelinecompanies().timeline(uid, &params) and AI narrative via timeline_summary(...)
  • Similar companiescompanies().similar(uid, limit) scored on industry, canton, capital, legal form, auditor tier
  • UBO resolutioncompanies().ubo(uid) walks the ownership chain and identifies natural persons
  • Ownership traceownership().trace(uid, &req) exposes the full chain with circular-ownership detection
  • Media with sentimentcompanies().media(uid, &params) filtered by positive/neutral/negative
  • Batch operationsscreening().batch(&req) (up to 100 UIDs) and ai().risk_score_batch(&req) (up to 50 UIDs)
  • Market analyticsanalytics().flows(&params), analytics().migrations(since), analytics().benchmark(&params)
  • Person networkpersons().network(id) for person-centric investigations with co-directors
  • Saved alerts — persistent saved queries with optional webhook delivery
  • Pagination on board_members — new board_members_paged(uid, &params) (max 500)
  • Typed hierarchyHierarchyResponse now uses HierarchyEntity (was serde_json::Value)
  • Enriched watchlistsWatchlistCompaniesResponse.companies includes name/status/canton
  • export_csv — new canonical name (export_excel kept as deprecated alias)

Response Metadata

Every response includes header metadata for credit tracking and rate limiting:

let resp = client.companies().get("CHE-105.805.080").await?;

println!("Request ID: {:?}", resp.meta.request_id);         // X-Request-Id
println!("Credits used: {:?}", resp.meta.credits_used);      // X-Credits-Used
println!("Credits remaining: {:?}", resp.meta.credits_remaining); // X-Credits-Remaining
println!("Rate limit: {:?}", resp.meta.rate_limit_limit);    // X-Rate-Limit-Limit
println!("Rate limit remaining: {:?}", resp.meta.rate_limit_remaining); // X-RateLimit-Remaining
println!("Rate limit reset: {:?}", resp.meta.rate_limit_reset); // X-RateLimit-Reset
println!("Data source: {:?}", resp.meta.data_source);        // X-Data-Source

Example CLI

A full CLI example is included to demonstrate real-world SDK usage:

export VYNCO_API_KEY="vc_live_your_api_key"

cargo run --example vynco_cli -- health                            # API health check
cargo run --example vynco_cli -- companies --canton ZH --search "Novartis"  # List with filters
cargo run --example vynco_cli -- company CHE-105.805.649           # Lookup by UID
cargo run --example vynco_cli -- count                             # Count companies
cargo run --example vynco_cli -- events CHE-105.805.649 --limit 10 # Company events
cargo run --example vynco_cli -- screen "Test Corp"                # Sanctions screening
cargo run --example vynco_cli -- dashboard                         # Admin dashboard
cargo run --example vynco_cli -- auditors --min-years 10 --canton ZH  # Long-tenure auditors
cargo run --example vynco_cli -- risk CHE-105.805.649              # AI risk score
cargo run --example vynco_cli -- fingerprint CHE-105.805.649       # Company data fingerprint
cargo run --example vynco_cli -- graph CHE-105.805.649             # Network graph
cargo run --example vynco_cli -- dossier CHE-105.805.649           # Generate AI dossier
cargo run --example vynco_cli -- compare CHE-105.805.649 CHE-109.340.740  # Compare companies
cargo run --example vynco_cli -- credits                           # Credit balance
cargo run --example vynco_cli -- team                              # Team info
cargo run --example vynco_cli -- changes --page 1 --page-size 10  # Recent SOGC changes
cargo run --example vynco_cli -- board-members CHE-105.805.649     # Board members

See examples/vynco_cli.rs for the full source.

Configuration

use std::time::Duration;

let client = Client::builder("vc_live_your_api_key")
    .base_url("https://vynco.ch/api")               // default
    .timeout(Duration::from_secs(60))               // default: 30s
    .max_retries(3)                                 // default: 2
    .build()?;

The client automatically retries on HTTP 429 (rate limited) and 5xx (server error) with exponential backoff (500ms x 2^attempt). It respects the Retry-After header when present.

Error Handling

All API errors are mapped to typed variants:

use vynco::VyncoError;

match client.companies().get("CHE-000.000.000").await {
    Ok(resp) => println!("{}", resp.data.name),
    Err(VyncoError::Authentication(_)) => println!("Invalid API key"),
    Err(VyncoError::InsufficientCredits(_)) => println!("Top up credits"),
    Err(VyncoError::Forbidden(_)) => println!("Insufficient permissions"),
    Err(VyncoError::NotFound(body)) => println!("Not found: {:?}", body.detail),
    Err(VyncoError::Validation(body)) => println!("Bad request: {:?}", body.detail),
    Err(VyncoError::Conflict(_)) => println!("Resource conflict"),
    Err(VyncoError::RateLimit(_)) => println!("Rate limited, retry later"),
    Err(VyncoError::Server(_)) => println!("Server error"),
    Err(e) => eprintln!("Error: {e}"),
}

Error bodies follow RFC 7807 Problem Details with error_type, title, status, detail, and instance fields.

Feature Flags

Feature Default Description
rustls-tls Yes Use rustls for TLS (no OpenSSL dependency)
native-tls No Use the platform's native TLS stack
blocking No Enable the synchronous blocking client

Minimum Supported Rust Version

Rust 1.83 or later.

License

Apache-2.0