OpenAPI specification
The control plane publishes a versioned OpenAPI 3.1 document. It is generated from the running application (all mounted services included) and committed to the repository as packages/contracts/schemas/v1/openapi.json; a running control plane also serves it at /openapi.json. A contract test fails the build if the committed document differs from what the application generates.
The document describes, for every operation:
- the credential kind (
x-auth) and the permission it needs (x-permission), withuserSession,agentAccessTokenandenrollmentTokensecurity schemes; ApiErrorbodies for every error status, theX-Correlation-Idresponse header, andRetry-Afteron the operations that can return 429;- the
Idempotency-Keyheader andIdempotent-Replayedresponse header on idempotent operations (x-idempotency-key: true); - cursor pagination (
x-pagination) and the optional list filters (x-list-filters); - the data class of every field (
x-data-class). No field classedPROHIBITED_RAW_DATAcan appear.
Agent-protocol envelopes (AgentEnvelope, ControlPlaneEnvelope) and every protocol message, agent command and platform event are listed under x-event-schemas. DataNivra v1 does not push webhooks to customers: job and audit events are read by polling the cursor-paginated /v1/jobs/{job_id}/events and /v1/audit-events routes.
Installation
The SDKs are not published to PyPI or npm yet. Once they are, install them with pip install datanivra-sdk and npm install @datanivra/sdk. Until then, use the verified release assets or build from source. Versions follow Semantic Versioning: the contract packages (datanivra-contracts, @datanivra/contracts) carry the API version (v1 is 1.x). The SDKs and the CLI are released together and accept any 1.x contract version.
Python SDK
datanivra-sdk (module datanivra_sdk) has one typed method per user or public operation, generated from the route contract and checked against the OpenAPI document. Requests and responses use the shared contract models, so a response that does not match the v1 contract raises an error instead of returning guessed data.
from datanivra_sdk import DataNivraApiError, DataNivraClient
with DataNivraClient("https://api.example.test", token=session_token) as api:
me = api.get_me()
# One page (typed Page[Job]) or every item, following next_cursor.
failed = api.list_jobs(state="FAILED", limit=20)
for job in api.paginate(api.list_jobs, kind="REFRESH"):
print(job.id, job.state)
# Idempotent create: re-running with the same key returns the original request.
request = api.create_dataset_request(body, idempotency_key="ticket-4711")
try:
api.get_dataset("00000000-0000-4000-8000-000000000000")
except DataNivraApiError as err:
print(err.status, err.code, err.correlation_id) # 404 NOT_FOUND <id>TypeScript SDK
@datanivra/sdk exposes the same operations with types from @datanivra/contracts.
import { createDataNivraClient } from '@datanivra/sdk';
const api = createDataNivraClient({
baseUrl: 'https://api.example.test',
getAccessToken: () => session.token,
retry: { maxAttempts: 3 }, // optional; retry-safe operations only
});
const page = await api.listJobs({ query: { limit: 20, filters: { state: 'FAILED' } } });
const all = await api.listAll('listDatasets', { filters: { status: 'CERTIFIED' } });
const job = await api.discoverSource({ path: { source_id }, idempotencyKey });Retries
Both SDKs retry only operations that cannot create duplicates: GET requests, and POST requests that carry an Idempotency-Key (the same key is sent on every attempt). They retry transport errors and 502/503/504 responses with bounded exponential back-off. A 429 is retried only when the server's Retry-After is short; a daily refresh limit is reported to you straight away. Other changes, such as cancelling a job or updating a policy, are never retried automatically. The Python SDK retries up to 3 attempts by default. The TypeScript SDK does not retry unless you set retry, so browser pages show errors immediately.
Errors
Every error status becomes an exception with status, code, message and correlation_id — DataNivraApiError in Python, the same fields (correlationId) in TypeScript. If a response is not a well-formed ApiError (for example an HTML error page from a proxy), the SDK does not copy its body into the exception. It reports a generic HTTP_<status> code instead.
What the SDKs cannot do
The SDKs cannot call the agent protocol or the billing-provider webhook, and they never import connectors or the engine. They only exchange metadata with the control plane: ids, states, counts, checksums and evidence references. They never handle raw rows or secret values.