Skip to content

v4.0.0: Align SDK with stabilized API + usage/audit/compliance/bulk resources#1

Merged
mivertowski merged 23 commits into
mainfrom
feat/api-alignment-v4
May 20, 2026
Merged

v4.0.0: Align SDK with stabilized API + usage/audit/compliance/bulk resources#1
mivertowski merged 23 commits into
mainfrom
feat/api-alignment-v4

Conversation

@mivertowski
Copy link
Copy Markdown
Contributor

Summary

Full alignment of the vynco SDK to the now-stabilized VynCo API, released as 4.0.0. The axum router (VynCorpApi/src/routes/) was treated as the source of truth — the OpenAPI doc is incomplete (~40 live routes undocumented), so reconciliation was driven by handler signatures and verified with a reproducible route-gap script (now 0 phantom endpoints).

Breaking changes

  • Removed dead client.credits (+ Credit* types) → added client.usage.current() (/v1/usage/current).
  • ResponseMeta: dropped credits_used/credits_remaining (API emits no X-Credits-*); now exposes the full X-RateLimit-* set (added rate_limit_group/rate_limit_window).
  • Tier starterbasic (API normalizes the legacy alias).
  • Team/BillingSummary/MemberUsage: removed phantom credit fields; Team gained stripe_subscription_id/current_period_end/cancellation_effective_at.
  • UboPerson.person_id intstr (UUID); AiSearchResponse.resultslist[AiSearchResult]; ComparativeResponse.auditor_analysis and WatchlistCompanyEntry.name now non-optional.

P0 correctness fixes (with regression tests)

  • DiffEntry now reads wire key from (was aliased fromValue → always None).
  • UboPerson.person_id UUID type (was intValidationError).
  • Dossier.citations + Citation model (was silently dropped).
  • screening.browse_sanctions sends snake entity_type and no longer leaks _build_params into the query.

Added

  • New resources: usage, settings, notifications, sync, audit, compliance, risk, bulk, watches.
  • New methods: ownership.analytics, analytics.prospects, pipelines.update.
  • New params: 17 companies.list filters, include_internal (events/changes/watchlists), 8 persons.search filters.
  • Completed drifted models (Company, AuditCandidate, Benchmark nullability, persons nationality fields, MigrationResponse, UboResponse parent LEI/name).
  • Tooling: scripts/api_gap.py (reproducible diff) + opt-in @pytest.mark.live smoke suite.

Test plan

  • uv run pytest — 69 passed, 6 live deselected
  • uv run mypy src/ — clean (78 files)
  • uv run ruff check + ruff format --check — clean
  • python scripts/api_gap.py — 0 phantom (only /audit-log deferred, out of scope)
  • Live prod connectivity verified via /health
  • Authenticated live smoke — pending VYNCO_API_KEY: VYNCO_API_KEY=... uv run pytest -m live -v

Follow-up (API repo, optional)

GET /v1/sanctions is the only query struct using snake_case (entity_type); recommend adding #[serde(rename_all = "camelCase")] so the SDK special-case can be removed. See docs/superpowers/plans/2026-05-20-sdk-api-alignment.md.

🤖 Generated with Claude Code

mivertowski and others added 23 commits May 20, 2026 15:10
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Remove /v1/credits/* endpoints (balance, usage, history) and replace with
GET /v1/usage/current backed by the live API handler. Adds GroupUsage and
UsageSnapshot Pydantic models with nullable used/limit fields matching the
Rust wire format (camelCase resetSeconds). InsufficientCreditsError retained:
ApiError::InsufficientCredits still maps to HTTP 402 in errors.rs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ing Task 2

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…'starter')

SDK surfaces tier as a free-form string and the API already maps the legacy
'starter' alias to 'basic' server-side (models/access.rs), so no SDK-side
validator is needed; only the stale test fixture referenced 'starter'.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…EAKING)

The API emits X-RateLimit-Group/-Window/-Limit/-Remaining/-Reset and no
X-Credits-* headers (middleware/rate_limit_headers.rs). Drop ResponseMeta
credits_used/credits_remaining; add rate_limit_group and rate_limit_window
to cover the complete header set. Update affected meta tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… dossier citations)

- UboPerson.person_id: int -> str (API sends a UUID; int caused ValidationError)
- UboResponse: add ultimate_parent_lei / ultimate_parent_name (were dropped)
- DiffEntry.from_value: alias to wire 'from' (was 'fromValue' -> always None)
- Dossier: add citations: list[Citation] + new Citation model (were dropped)
- Add regression tests for all three.

Verified against handler signatures in companies.rs/ownership.rs, changes.rs,
dossiers.rs and kg/types.rs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mark, persons, MigrationResponse)

- Company: add status_canonical, legal_form_code, auditor_opt_out,
  auditor_source, data_quality_score (all nullable, per CompanyResponse).
- AuditCandidate: add currency, change_count, score, risk_indicators,
  auditor_tenure_years (handler returns these; were dropped).
- BenchmarkDimension: company_value and peers_with_data are non-optional
  on the wire (fix wrong nullability).
- MigrationResponse: add data_coverage_note.
- PersonSearchResult/PersonDetail: add nationality_iso, nationality_display.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nges/watchlists include_internal, persons.search filters)

- companies.list: add 17 SearchParams filters (foundedAfter, minChanges,
  isFinmaRegulated, noga*, dataQuality*, statusCanonical, legalFormCode,
  hasAuditor/hasLei/hasWikidata, enriched, boardMemberSearch, uids).
- companies.events / changes.list / changes.by_company / watchlists.events:
  add include_internal.
- persons.search: add role_category, signing_authority, canton,
  nationality_iso, place_of_origin, is_active, sort_by, sort_desc.
- Add wire-key serialization regression test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- teams.Team: drop phantom credit_balance/monthly_credits; add
  stripe_subscription_id, current_period_end, cancellation_effective_at.
- teams.BillingSummary/MemberUsage: drop credit fields the API no longer returns.
- watchlists.WatchlistCompanyEntry.name: non-optional (API guarantees it).
- comparative.auditor_analysis: non-optional (handler always emits it).
- ai.search: typed AiSearchResult projection instead of full Company.
- screening.browse_sanctions: send snake_case entity_type (handler expects it)
  and fix locals() leaking _build_params into the query string.
- pipelines: add missing update() method (PUT /v1/pipelines/{id}).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… API note

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…k, watches resources

New resources (all sync+async, modeled from handler signatures):
- settings: get/update preferences (free-form Preferences, extra=allow)
- notifications: list, mark_read, get/update preferences, test
- sync: status (pipeline freshness)
- audit: playbook(uid) (full procedure/step tree)
- compliance: scope(uid) (regulation→control→evidence tree)
- risk: v2(uid) (Bayesian risk score)
- bulk: export (CSV bytes), screening, add_to_watchlist (multipart)
- watches: list, add, remove
Plus ownership.analytics(uid) and analytics.prospects() on existing resources.

Transport: thread optional files= through _request/_request_model for the
bulk watchlist multipart upload. Gap script now reports 0 phantom endpoints.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- pyproject: register 'live' marker, default addopts '-m not live'.
- tests/live/: session-scoped client fixture (skips without VYNCO_API_KEY),
  read-only smoke tests for health/usage/companies/changes with tier-gate (403)
  treated as skip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Bump version 3.2.1 -> 4.0.0 (_constants.py, pyproject.toml).
- CHANGELOG: full 4.0.0 entry (breaking changes, additions, fixes).
- README: rewrite resource table (remove credits, add usage/settings/
  notifications/sync/audit/compliance/risk/bulk/watches/pipelines/reports/
  saved_searches; update ai/changes/analytics/ownership/screening rows).
- Fix stale ResponseMeta.credits_used/remaining references in README and
  examples (quickstart, bulk_export) -> rate_limit_* fields.
- Format scripts/api_gap.py.

Gate: ruff (format+lint), mypy (78 files), pytest (69 passed, 6 live deselected)
all green. Gap script: 0 phantom endpoints.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…metadata intro

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hardcoded CHE-105.805.080 404s against prod; derive a real UID from a search
so the live smoke test is robust to dataset contents.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…key)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add examples/_common.py with get_client() (friendly missing-key message) and a
section() context manager that degrades gracefully on ForbiddenError (tier gate),
RateLimitError, and transient ServerError/ServiceUnavailableError. Refactor all
8 examples to wrap each section so the same script runs end-to-end on Free,
Professional, or Enterprise keys instead of crashing on the first gated call.

Verified live against production with a free-tier key: all 8 run to completion
(tier-gated sections print a clear skip note; free-tier sections show real data).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- pyproject: [project.optional-dependencies].notebooks = matplotlib/seaborn/
  networkx/numpy/jupyter/ipykernel so the example notebooks run via
  'pip install vynco[notebooks]' or 'uv run --extra notebooks ...'.
- notebooks/README: document the extra + the Professional-tier requirement.
- test_empty_api_key_raises_config_error: delenv VYNCO_API_KEY so it stays
  hermetic when the key is exported for the live suite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mivertowski mivertowski merged commit ceb2529 into main May 20, 2026
6 checks passed
@mivertowski mivertowski deleted the feat/api-alignment-v4 branch May 20, 2026 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant