Skip to content

Commit 2294f00

Browse files
mivertowskiclaude
andcommitted
Release v3.2.0: reports, pipelines, saved searches, predictive risk, comparative AI, sanctions browse, PDF profiles
Adds 21 new endpoints (8 high-priority + 13 medium-priority): High priority: - ai.comparative — AI comparative dossier for 2-5 companies - ai.predictive_risk — dissolution probability + credit risk scoring - companies.pdf — structured profile data for PDF rendering - reports.industries / reports.get / reports.generate — industry reports - screening.browse_sanctions — browse SECO/OpenSanctions/FINMA databases - changes.review — mark changes as reviewed (compliance workflow) Medium priority: - pipelines (new resource) — CRUD for sales/prospect tracking pipelines with entries, stages, and statistics - saved_searches (new resource) — persist and schedule search queries Also fixes BenchmarkDimension nullable fields (industryMedian, percentile) and adds peersWithData field. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2b76b23 commit 2294f00

14 files changed

Lines changed: 1303 additions & 8 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "vynco"
3-
version = "2.3.0"
3+
version = "2.4.0"
44
edition = "2021"
55
rust-version = "1.83"
66
license = "Apache-2.0"

src/blocking.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,18 @@ impl Client {
161161
pub fn graph(&self) -> Graph<'_> {
162162
Graph { client: self }
163163
}
164+
165+
pub fn reports(&self) -> Reports<'_> {
166+
Reports { client: self }
167+
}
168+
169+
pub fn pipelines(&self) -> Pipelines<'_> {
170+
Pipelines { client: self }
171+
}
172+
173+
pub fn saved_searches(&self) -> SavedSearches<'_> {
174+
SavedSearches { client: self }
175+
}
164176
}
165177

166178
// ---------------------------------------------------------------------------
@@ -305,6 +317,10 @@ impl Companies<'_> {
305317
.block_on(self.client.inner.companies().all_tags())
306318
}
307319

320+
pub fn pdf(&self, uid: &str) -> Result<Response<PdfProfileResponse>> {
321+
self.client.block_on(self.client.inner.companies().pdf(uid))
322+
}
323+
308324
pub fn export_csv(&self, req: &ExcelExportRequest) -> Result<ExportFile> {
309325
self.client
310326
.block_on(self.client.inner.companies().export_csv(req))
@@ -354,6 +370,19 @@ impl Screening<'_> {
354370
self.client
355371
.block_on(self.client.inner.screening().screen(req))
356372
}
373+
374+
pub fn batch(&self, req: &BatchScreeningRequest) -> Result<Response<BatchScreeningResponse>> {
375+
self.client
376+
.block_on(self.client.inner.screening().batch(req))
377+
}
378+
379+
pub fn browse_sanctions(
380+
&self,
381+
params: &SanctionsSearchParams,
382+
) -> Result<Response<SanctionsListResponse>> {
383+
self.client
384+
.block_on(self.client.inner.screening().browse_sanctions(params))
385+
}
357386
}
358387

359388
pub struct Watchlists<'a> {
@@ -478,6 +507,28 @@ impl Ai<'_> {
478507
pub fn risk_score(&self, req: &RiskScoreRequest) -> Result<Response<RiskScoreResponse>> {
479508
self.client.block_on(self.client.inner.ai().risk_score(req))
480509
}
510+
511+
pub fn risk_score_batch(
512+
&self,
513+
req: &BatchRiskScoreRequest,
514+
) -> Result<Response<BatchRiskScoreResponse>> {
515+
self.client
516+
.block_on(self.client.inner.ai().risk_score_batch(req))
517+
}
518+
519+
pub fn comparative(&self, req: &ComparativeRequest) -> Result<Response<ComparativeResponse>> {
520+
self.client
521+
.block_on(self.client.inner.ai().comparative(req))
522+
}
523+
524+
pub fn predictive_risk(
525+
&self,
526+
uid: &str,
527+
req: &PredictiveRiskRequest,
528+
) -> Result<Response<PredictiveRiskResponse>> {
529+
self.client
530+
.block_on(self.client.inner.ai().predictive_risk(uid, req))
531+
}
481532
}
482533

483534
// ---------------------------------------------------------------------------
@@ -612,6 +663,10 @@ impl Changes<'_> {
612663
self.client
613664
.block_on(self.client.inner.changes().statistics())
614665
}
666+
667+
pub fn review(&self, id: &str) -> Result<ResponseMeta> {
668+
self.client.block_on(self.client.inner.changes().review(id))
669+
}
615670
}
616671

617672
pub struct Persons<'a> {
@@ -732,3 +787,112 @@ impl Graph<'_> {
732787
self.client.block_on(self.client.inner.graph().analyze(req))
733788
}
734789
}
790+
791+
pub struct Reports<'a> {
792+
client: &'a Client,
793+
}
794+
795+
impl Reports<'_> {
796+
pub fn industries(&self) -> Result<Response<IndustryListResponse>> {
797+
self.client
798+
.block_on(self.client.inner.reports().industries())
799+
}
800+
801+
pub fn get(&self, industry: &str) -> Result<Response<IndustryReportResponse>> {
802+
self.client
803+
.block_on(self.client.inner.reports().get(industry))
804+
}
805+
806+
pub fn generate(&self, industry: &str) -> Result<Response<GeneratedIndustryReport>> {
807+
self.client
808+
.block_on(self.client.inner.reports().generate(industry))
809+
}
810+
}
811+
812+
pub struct Pipelines<'a> {
813+
client: &'a Client,
814+
}
815+
816+
impl Pipelines<'_> {
817+
pub fn list(&self) -> Result<Response<Vec<Pipeline>>> {
818+
self.client.block_on(self.client.inner.pipelines().list())
819+
}
820+
821+
pub fn create(&self, req: &CreatePipelineRequest) -> Result<Response<Pipeline>> {
822+
self.client
823+
.block_on(self.client.inner.pipelines().create(req))
824+
}
825+
826+
pub fn get(&self, id: &str) -> Result<Response<PipelineWithEntries>> {
827+
self.client.block_on(self.client.inner.pipelines().get(id))
828+
}
829+
830+
pub fn delete(&self, id: &str) -> Result<ResponseMeta> {
831+
self.client
832+
.block_on(self.client.inner.pipelines().delete(id))
833+
}
834+
835+
pub fn add_entry(&self, id: &str, req: &AddEntryRequest) -> Result<Response<PipelineEntry>> {
836+
self.client
837+
.block_on(self.client.inner.pipelines().add_entry(id, req))
838+
}
839+
840+
pub fn update_entry(
841+
&self,
842+
id: &str,
843+
entry_id: &str,
844+
req: &UpdateEntryRequest,
845+
) -> Result<Response<PipelineEntry>> {
846+
self.client.block_on(
847+
self.client
848+
.inner
849+
.pipelines()
850+
.update_entry(id, entry_id, req),
851+
)
852+
}
853+
854+
pub fn remove_entry(&self, id: &str, entry_id: &str) -> Result<ResponseMeta> {
855+
self.client
856+
.block_on(self.client.inner.pipelines().remove_entry(id, entry_id))
857+
}
858+
859+
pub fn stats(&self, id: &str) -> Result<Response<PipelineStats>> {
860+
self.client
861+
.block_on(self.client.inner.pipelines().stats(id))
862+
}
863+
}
864+
865+
pub struct SavedSearches<'a> {
866+
client: &'a Client,
867+
}
868+
869+
impl SavedSearches<'_> {
870+
pub fn list(&self) -> Result<Response<Vec<SavedSearch>>> {
871+
self.client
872+
.block_on(self.client.inner.saved_searches().list())
873+
}
874+
875+
pub fn create(&self, req: &CreateSavedSearchRequest) -> Result<Response<SavedSearch>> {
876+
self.client
877+
.block_on(self.client.inner.saved_searches().create(req))
878+
}
879+
880+
pub fn get(&self, id: &str) -> Result<Response<SavedSearch>> {
881+
self.client
882+
.block_on(self.client.inner.saved_searches().get(id))
883+
}
884+
885+
pub fn update(
886+
&self,
887+
id: &str,
888+
req: &UpdateSavedSearchRequest,
889+
) -> Result<Response<SavedSearch>> {
890+
self.client
891+
.block_on(self.client.inner.saved_searches().update(id, req))
892+
}
893+
894+
pub fn delete(&self, id: &str) -> Result<ResponseMeta> {
895+
self.client
896+
.block_on(self.client.inner.saved_searches().delete(id))
897+
}
898+
}

src/client.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,18 @@ impl Client {
175175
Ownership::new(self)
176176
}
177177

178+
pub fn reports(&self) -> Reports<'_> {
179+
Reports::new(self)
180+
}
181+
182+
pub fn pipelines(&self) -> Pipelines<'_> {
183+
Pipelines::new(self)
184+
}
185+
186+
pub fn saved_searches(&self) -> SavedSearches<'_> {
187+
SavedSearches::new(self)
188+
}
189+
178190
// -- Internal request methods --------------------------------------------
179191

180192
pub(crate) fn url(&self, path: &str) -> String {

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ pub use client::{Client, ClientBuilder};
1212
pub use error::{ErrorBody, VyncoError};
1313
pub use resources::{
1414
Ai, Alerts, Analytics, ApiKeys, Auditors, Billing, Changes, Companies, Credits, Dashboard,
15-
Dossiers, ExportFile, Exports, Graph, Health, Ownership, Persons, Screening, Teams, Watchlists,
16-
Webhooks,
15+
Dossiers, ExportFile, Exports, Graph, Health, Ownership, Persons, Pipelines, Reports,
16+
SavedSearches, Screening, Teams, Watchlists, Webhooks,
1717
};
1818
pub use response::{Response, ResponseMeta};
1919
pub use types::*;

src/resources/ai.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,29 @@ impl<'a> Ai<'a> {
4141
.request_with_body(Method::POST, "/v1/ai/risk-score/batch", req)
4242
.await
4343
}
44+
45+
/// Generate an AI comparative dossier for 2-5 companies.
46+
///
47+
/// `focus` is one of `governance`, `financial`, `risk`, or `all` (default).
48+
pub async fn comparative(
49+
&self,
50+
req: &ComparativeRequest,
51+
) -> Result<Response<ComparativeResponse>> {
52+
self.client
53+
.request_with_body(Method::POST, "/v1/ai/comparative", req)
54+
.await
55+
}
56+
57+
/// Get predictive risk scoring with dissolution probability.
58+
pub async fn predictive_risk(
59+
&self,
60+
uid: &str,
61+
req: &PredictiveRiskRequest,
62+
) -> Result<Response<PredictiveRiskResponse>> {
63+
self.client
64+
.request_with_body(Method::POST, &format!("/v1/risk/predictive/{uid}"), req)
65+
.await
66+
}
4467
}
4568

4669
#[cfg(test)]

src/resources/changes.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use reqwest::Method;
22

33
use crate::client::Client;
44
use crate::error::Result;
5-
use crate::response::Response;
5+
use crate::response::{Response, ResponseMeta};
66
use crate::types::*;
77

88
pub struct Changes<'a> {
@@ -57,6 +57,13 @@ impl<'a> Changes<'a> {
5757
.request(Method::GET, "/v1/changes/statistics")
5858
.await
5959
}
60+
61+
/// Mark a change as reviewed (compliance workflow).
62+
pub async fn review(&self, id: &str) -> Result<ResponseMeta> {
63+
self.client
64+
.request_empty(Method::PUT, &format!("/v1/changes/{id}/review"))
65+
.await
66+
}
6067
}
6168

6269
#[cfg(test)]

src/resources/companies.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,15 @@ impl<'a> Companies<'a> {
372372
.await
373373
}
374374

375+
// -- PDF profile --
376+
377+
/// Get structured company profile data suitable for PDF rendering.
378+
pub async fn pdf(&self, uid: &str) -> Result<Response<PdfProfileResponse>> {
379+
self.client
380+
.request(Method::GET, &format!("/v1/companies/{uid}/pdf"))
381+
.await
382+
}
383+
375384
// -- CSV / Excel export --
376385

377386
/// Export companies as CSV.

src/resources/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ mod graph;
1414
mod health;
1515
mod ownership;
1616
mod persons;
17+
mod pipelines;
18+
mod reports;
19+
mod saved_searches;
1720
mod screening;
1821
mod teams;
1922
mod watchlists;
@@ -35,6 +38,9 @@ pub use graph::Graph;
3538
pub use health::Health;
3639
pub use ownership::Ownership;
3740
pub use persons::Persons;
41+
pub use pipelines::Pipelines;
42+
pub use reports::Reports;
43+
pub use saved_searches::SavedSearches;
3844
pub use screening::Screening;
3945
pub use teams::Teams;
4046
pub use watchlists::Watchlists;

0 commit comments

Comments
 (0)