Skip to content

SDKs

Venturi maintains first-party, fully typed SDKs for TypeScript and Python. Both are generated from the same OpenAPI 3.1 document that defines the REST API, so the client surface always matches the contract. Each SDK builds in the platform conventions you would otherwise implement by hand: token refresh, cursor-pagination iterators, idempotency-key generation, Retry-After-aware backoff, and typed problem+json errors.

Package availability

The SDKs are distributed in each customer’s onboarding artifact bundle and private package channel. The public npm package is not published, and the public PyPI project named venturi is unrelated. Do not install either from a public registry. Your bundle manifest pins the package filename, version, SHA-256 digest, and matching OpenAPI version.

Generated, never hand-written

The SDKs are regenerated from each released OpenAPI version and pinned for reproducible builds. The generated client cannot drift from the published contract (a mismatch fails CI), so the methods, models, and error types you use are exactly the API’s.

Install

Bash
npm install ./venturi-sdk-<version>.tgz
Bash
pip install ./venturi_sdk-<version>-py3-none-any.whl

Configure the client

The base URL is your Venturi instance, since the platform runs inside your trust boundary. Supply a token (or API key) and the client manages refresh.

TypeScript
import { Venturi } from "@venturi/sdk";

const venturi = new Venturi({
  baseUrl: "https://<your-venturi-instance>",
  clientId: process.env.VENTURI_CLIENT_ID,
  clientSecret: process.env.VENTURI_CLIENT_SECRET,
  // or: apiKey: process.env.VENTURI_API_KEY
});
Python
import os

from venturi import Venturi

venturi = Venturi(
    base_url="https://<your-venturi-instance>",
    client_id=os.environ["VENTURI_CLIENT_ID"],
    client_secret=os.environ["VENTURI_CLIENT_SECRET"],
    # or: api_key=os.environ["VENTURI_API_KEY"]
)

Reading attribution

Every record carries the interpretation evidence card (stage_origin, confidence, confidence_band, evidence_basis, model_version, degradation_state, freshness, and export_eligibility), fully typed.

TypeScript
const record = await venturi.attribution.get("attr_01HF8...");
console.log(record.costUsd, record.interpretation.confidenceBand);

if (record.interpretation.exportEligibility === "eligible") {
  // safe to include in chargeback
}
Python
record = venturi.attribution.get("attr_01HF8...")
print(record.cost_usd, record.interpretation.confidence_band)

if record.interpretation.export_eligibility == "eligible":
    ...  # safe to include in chargeback

Pagination: transparent iterators

Paginated resources expose an async iterator that follows cursors for you. You never construct, sign, or carry a cursor by hand.

TypeScript
for await (const record of venturi.attribution.list({
  filter: { provider: { eq: "openai" } },
  sort: "-costUsd",
})) {
  console.log(record.id, record.costUsd);
}
Python
for record in venturi.attribution.list(
    filter={"provider": {"eq": "openai"}},
    sort="-cost_usd",
):
    print(record.id, record.cost_usd)

The iterator walks next_cursor to exhaustion, returning each record exactly once. See pagination for the underlying contract.

Ingestion coverage

Both SDK bundles include typed clients for the InvocationEvent and generic observability ingestion routes, including caller-supplied idempotency keys. The REST wire format in Send events remains authoritative.

Idempotency: automatic

The SDK attaches a fresh Idempotency-Key to every mutating call by default, so a transient network retry never creates a duplicate. Pass your own key to make a specific operation safe to retry across process restarts.

TypeScript
const job = await venturi.exports.create(
  { format: "focus", period: { from: "2026-05-01", to: "2026-05-31" } },
  { idempotencyKey: "monthly-2026-05" }, // stable across retries
);
Python
job = venturi.exports.create(
    format="focus",
    period={"from": "2026-05-01", "to": "2026-05-31"},
    idempotency_key="monthly-2026-05",  # stable across retries
)

Rate limits and backoff: automatic

On a 429, the SDK honors Retry-After and retries with jittered backoff. After exhausting retries it raises a typed RateLimitError rather than a bare HTTP error, so you can branch deliberately.

TypeScript
import { RateLimitError } from "@venturi/sdk";

try {
  await venturi.exports.create({ format: "focus", period });
} catch (err) {
  if (err instanceof RateLimitError) {
    // backoff exhausted: slow down or queue
  }
}
Python
from venturi import RateLimitError

try:
    venturi.exports.create(format="focus", period=period)
except RateLimitError:
    ...  # backoff exhausted: slow down or queue

Typed errors

Errors are deserialized into a typed union derived from the published error catalog. Branch on the error_code, not on prose.

TypeScript
import { VenturiError } from "@venturi/sdk";

try {
  await venturi.exports.create(input);
} catch (err) {
  if (err instanceof VenturiError && err.errorCode === "INSUFFICIENT_SCOPE") {
    // this credential cannot create exports
  }
}
Python
from venturi import VenturiError

try:
    venturi.exports.create(**input)
except VenturiError as err:
    if err.error_code == "INSUFFICIENT_SCOPE":
        ...  # this credential cannot create exports

Verifying webhooks

Each SDK ships a signature-verification helper so you do not reimplement the HMAC check. See webhooks.

TypeScript
import { verifyWebhook } from "@venturi/sdk";

app.post("/venturi", (req, res) => {
  const event = verifyWebhook(req.rawBody, req.headers["venturi-signature"], secret);
  // throws on bad signature or timestamp skew
  handle(event);
  res.sendStatus(200);
});
Python
from venturi.webhooks import verify_webhook

@app.post("/venturi")
def handle(request):
    event = verify_webhook(request.body, request.headers["Venturi-Signature"], secret)
    # raises on bad signature or timestamp skew
    process(event)
    return "", 200

Sample apps

Each SDK ships with runnable reference apps you can clone and point at the sandbox:

  • Chargeback exporter: generates a FOCUS export and downloads the result.
  • Webhook receiver: verifies signatures and processes events.
  • Anomaly-alert forwarder: relays anomaly.detected events to your channel.

Versioning

SDK major versions track API major versions. A breaking API change ships alongside a coordinated new SDK major version, and the changelog records the mapping. Within a major version, upgrades are additive and safe. See versioning and rate limits.