Skip to main content

Vautra Python SDK

Python SDK for Vautra projects, buckets, and object storage.

The SDK signs every request and sends it to https://app.vautra.com/api by default. Keep the secret access key on a trusted server; it is a credential, not a public identifier.

Requirements

  • Python 3.9 or newer.
  • requests, cryptography, and pqcrypto (installed automatically).

Installation

pip install vautra-sdk

The distribution is vautra-sdk; the import name is vautra. The npm package of the same name is the separate Node.js SDK.

Quick start

Set your SDK credentials:

$env:VAUTRA_ACCESS_KEY_ID="your-access-key-id"
$env:VAUTRA_SECRET_ACCESS_KEY="your-secret-access-key"

Then create one client and reuse it:

from vautra import Vautra

with Vautra() as vautra:
    projects = vautra.projects.list()
    print(projects["data"])

Upload a file:

from vautra import Vautra

with Vautra() as vautra:
    obj = vautra.objects.upload(
        bucket_id="bucket-id",
        key="contract.pdf",
        body="C:/files/contract.pdf",
    )
    print(obj["id"])

Download a file:

from vautra import Vautra

with Vautra() as vautra:
    vautra.objects.download("object-id", destination="C:/files/contract-copy.pdf")

Authentication

Create an access key in the Vautra dashboard, then build one client and reuse it — each client owns a connection pool:

from vautra import Vautra

vautra = Vautra(
    access_key_id="...",
    secret_access_key="...",
)

Credentials fall back to the VAUTRA_ACCESS_KEY_ID and VAUTRA_SECRET_ACCESS_KEY environment variables, and api_url to VAUTRA_API_URL, when the corresponding argument is omitted:

from vautra import Vautra

with Vautra() as vautra:              # reads the environment
    page = vautra.projects.list()

Every request carries a fresh nonce, including retries, so signed headers are never replayed. Access-key permissions and project or bucket restrictions are enforced by the Vautra backend.

Invalid configuration raises VautraConfigError immediately, before any request is sent. api_url must use https:// unless it points at a loopback address, so signed credentials never travel over plaintext.

Encryption and project scope

Object uploads use VS3 encryption v2. The SDK creates a random AES-256-GCM file key, encrypts each upload part locally, wraps the file key and storage reference with the project's ML-KEM-768 public key, and sends only ciphertext plus envelope metadata to Vautra.

Access keys can be scoped to Vautra-managed projects and, when explicitly granted by the backend, user-managed projects. Vautra-managed uploads need no customer key material. User-managed uploads require the project's ML-KEM public key as project_public_key; the SDK never receives the project private key.

Most integrations use one of these two flows:

Project type Upload needs Download needs
Vautra-managed project SDK access key only SDK access key only
User-managed project SDK access key + derived publicKey SDK access key + derived secretKey

For user-managed projects, the Python SDK does not take the 24-word recovery phrase directly. Derive keys with the Node SDK once, then use those derived keys from Python. See User-managed projects.

Client options

Option Default Description
access_key_id $VAUTRA_ACCESS_KEY_ID Required.
secret_access_key $VAUTRA_SECRET_ACCESS_KEY Required. Never logged; the client redacts it in repr().
api_url $VAUTRA_API_URL or https://app.vautra.com/api Must be https:// for remote hosts.
timeout 30.0 Seconds, for non-upload requests. Use 0 or None to disable.
session new session Supply your own requests.Session to control proxies or TLS verification.

Every method also accepts a per-call timeout= override and a cancel_event= (a threading.Event).

Vautra is a context manager, and close() releases the connection pool:

with Vautra(access_key_id="...", secret_access_key="...") as vautra:
    ...

Object keys

Vautra object keys are flat file names, not S3-style paths:

  • No / or \ separators — documents/report.pdf is rejected.
  • Maximum 255 bytes (UTF-8), no control characters, no trailing period.
  • The key must end in a supported extension.

Supported extensions are currently: txt, csv, json, xml, html, css, js, ts, md, pdf, png, jpg, jpeg, gif, webp, svg, zip, gz, doc, docx, xlsx, pptx, mp3, mp4, webm, wav, ogg. Files whose contents do not match their extension are rejected on upload.

Invalid keys raise VautraError immediately, before an upload session is created.

Projects

page = vautra.projects.list(
    page=1,
    page_size=20,
    search="production",
    key_management="managed",
)

project = vautra.projects.get("project-id")

List methods return {"data": [...], "meta": {"page", "pageSize", "total", "totalPages"}}.

Buckets

page = vautra.buckets.list(project_id="project-id", page=1, page_size=20)

bucket = vautra.buckets.get("bucket-id")

created = vautra.buckets.create(
    project_id="project-id",
    name="documents",
    versioning_enabled=True,
)

Bucket deletion is intentionally not exposed by the SDK.

List objects

page = vautra.objects.list("bucket-id", page=1, page_size=20, search="invoice")

Upload objects

New uploads use VS3 encryption v2. The SDK creates a random AES-256-GCM file key, encrypts every part locally, wraps the file key and storage reference with the project's ML-KEM-768 public key, and sends only ciphertext plus envelope metadata to Vautra. The SDK never receives or stores the project private key.

For large local files, pass a path. The SDK reads only the active chunks instead of loading the whole file into memory:

obj = vautra.objects.upload(
    bucket_id="bucket-id",
    key="movie.mp4",
    body="C:/videos/movie.mp4",     # str, pathlib.Path, or {"path": ...}
    content_type="video/mp4",
)

For content already in memory:

vautra.objects.upload(
    bucket_id="bucket-id",
    key="hello.txt",
    body=b"Hello from Vautra",
    content_type="text/plain",
)

When content_type is omitted, Vautra derives the stored MIME type from the key's extension.

Supported body types

Body Behaviour
bytes, bytearray, memoryview Used directly.
str Encoded as UTF-8.
pathlib.Path, os.PathLike, {"path": "..."} Opened and read by range; memory stays flat.
A seekable binary file object Read by range from its current position. The SDK does not close a handle it did not open.
A non-seekable stream (pipe, socket, generator of bytes) Spooled to a temporary file so failed parts can be retried, then cleaned up.
Any object with size and read(start, end) Used as a random-access source.

A stream cannot be rewound, so a failed part could not otherwise be retried. Spooling keeps memory flat regardless of stream size. Prefer a path when the data is already on disk.

Text-mode file objects are rejected — open files with "rb".

Upload options

import threading

cancel = threading.Event()

vautra.objects.upload(
    bucket_id="bucket-id",
    key="archive.zip",
    body="./archive.zip",
    concurrency=2,            # 1-4
    max_attempts=3,           # 1-5
    attempt_timeout=180.0,    # seconds per request
    cancel_event=cancel,
    on_started=lambda upload_id: print("session", upload_id),
    on_progress=lambda p: print(p["stage"], p["loadedBytes"], p["totalBytes"]),
)

Progress stages are starting, uploading, finalizing, and success. loaded_bytes never goes backwards and a retried part is counted once.

Storage part uploads and completion requests retry network failures, HTTP 408, 429, and 5xx. Retry delays are one second then three seconds. Other 4xx responses are terminal, as are errors raised locally by the SDK.

If an upload fails after its session is created, the SDK makes a best-effort request to cancel and clean up that session. Secure cross-process resume is not supported.

User-managed projects

User-managed projects need one extra step because Python does not accept the 24-word BIP39 recovery phrase directly.

Simple rule:

  • For upload, Python needs the derived publicKey.
  • For download, Python needs the derived secretKey.
  • Keep the recovery phrase and secretKey private.

First, install or use the Node SDK and derive the keys from the recovery phrase:

npm install vautra-sdk

$env:VAUTRA_CUSTOMER_MNEMONIC="your 24 word recovery phrase"
node --input-type=module -e "import { deriveCustomerMlKemKeypair } from 'vautra-sdk'; console.log(JSON.stringify(deriveCustomerMlKemKeypair(process.env.VAUTRA_CUSTOMER_MNEMONIC), null, 2));"

The output looks like this:

{
  "publicKey": "base64-ml-kem-public-key",
  "secretKey": "base64-ml-kem-secret-key"
}

Use publicKey for Python upload:

import os
from vautra import Vautra

with Vautra() as vautra:
    obj = vautra.objects.upload(
        bucket_id="bucket-id",
        key="contract.pdf",
        body="C:/files/contract.pdf",
        project_public_key=os.environ["VAUTRA_PROJECT_PUBLIC_KEY"],
    )
    print(obj["id"])

Use secretKey for Python download:

import os
from vautra import Vautra

with Vautra() as vautra:
    vautra.objects.download(
        "object-id",
        destination="C:/files/contract-copy.pdf",
        customer_private_key=os.environ["VAUTRA_CUSTOMER_PRIVATE_KEY"],
    )

You can also pass the values directly, but environment variables are safer:

$env:VAUTRA_PROJECT_PUBLIC_KEY="base64-ml-kem-public-key"
$env:VAUTRA_CUSTOMER_PRIVATE_KEY="base64-ml-kem-secret-key"

If a user-managed upload starts without project_public_key, the SDK stops before uploading any file parts.

For high-throughput user-managed downloads, opt into direct storage reads:

vautra.objects.download(
    "object-id",
    destination="C:/files/contract-copy.pdf",
    customer_private_key=os.environ["VAUTRA_CUSTOMER_PRIVATE_KEY"],
    direct_storage_download=True,
)

Keep the recovery phrase and derived secretKey in a trusted backend or secret manager. Do not commit either value, and do not send them to Vautra.

Part encryption metadata

Each content part is encrypted with AES-256-GCM using the upload's random file key and a fresh random 96-bit IV. The IV and authentication tag are recorded per part in the completion payload; the uploaded part body contains ciphertext only. A retried part may be encrypted again with a new IV/tag, and only the metadata from the successful storage write is submitted at completion.

Upload status and cancellation

status = vautra.objects.upload_status("upload-id")
vautra.objects.cancel_upload("upload-id")

upload_status() is for inspection only; it does not enable resume.

To cancel a running upload, set the threading.Event you passed as cancel_event:

import threading

cancel = threading.Event()
worker = threading.Thread(
    target=vautra.objects.upload,
    kwargs={
        "bucket_id": "bucket-id",
        "key": "large.zip",
        "body": "./large.zip",
        "cancel_event": cancel,
    },
)
worker.start()
cancel.set()

The upload raises VautraCancelledError, and the session is cleaned up. An already-set event raises before any request is sent.

Because requests is synchronous, cancellation takes effect between parts and between retry attempts — it does not interrupt a request already on the wire. attempt_timeout bounds that window.

Download objects

Return the object as bytes:

data = vautra.objects.download("object-id")

Buffered downloads are capped at 256 MiB so a large object cannot exhaust memory. Pass max_bytes to change the cap, or 0 to disable it. Objects above the cap raise VautraError with status 413.

Write directly to a file, which streams and is not capped:

vautra.objects.download("object-id", destination="./report.pdf")

The file is written to a temporary sibling and renamed into place, so an interrupted download never leaves a truncated file at destination.

Or consume the stream yourself:

with vautra.objects.download_stream("object-id") as stream:
    print(stream.content_type, stream.content_length)
    for chunk in stream:
        sink.write(chunk)

Vautra-managed objects use the backend managed download path. User-managed encryption v2 objects can be downloaded by passing the ML-KEM private key for that project; encrypted parts are fetched through the backend encrypted-range endpoint and decrypted locally:

data = vautra.objects.download(
    "object-id",
    customer_private_key="base64-ml-kem-secret-key",
)

The SDK does not send the private key to Vautra.

For high-throughput user-managed downloads, opt into direct storage reads. The SDK will use backend-authorized presigned part URLs, send the signed range headers returned by the API, and fall back to the backend encrypted-range path if direct storage fails:

vautra.objects.download(
    "object-id",
    customer_private_key="base64-ml-kem-secret-key",
    direct_storage_download=True,
    destination="./report.pdf",
)

Delete objects

vautra.objects.delete("object-id")

Deletion is subject to access-key permissions and backend object-state rules.

Errors

Every SDK error derives from VautraError:

from vautra import VautraError

try:
    vautra.buckets.get("missing-bucket")
except VautraError as error:
    print(error.status, error.code, error.message)
Exception Raised when
VautraError The API returned a failure. Carries status, code, details.
VautraConfigError Client configuration is unusable. Raised before any request.
VautraTimeoutError A request exceeded its time budget (status 408).
VautraConnectionError The API could not be reached (status 0).
VautraCancelledError The caller's cancel_event was set.

Errors also expose retryable, which the upload retry loop uses to avoid burning attempts on failures that would repeat identically.

The SDK never follows redirects: signed credentials are not forwarded to another host, and an unexpected 3xx surfaces as a VautraError with code unexpected_redirect.

Thread safety

A Vautra client is safe to share across threads. Uploads use a bounded worker pool internally and read bodies under a lock.

Development

python -m venv .venv && .venv/Scripts/activate    # or source .venv/bin/activate
pip install -e ".[dev]"
pytest
ruff check . && mypy

The test suite runs against a mock Vautra API whose signature verification is a port of the backend's verifier, so a passing test means the SDK interoperates with the real service rather than with a permissive stub.

To try a real upload:

python examples/upload_file.py ./examples/sample.txt --bucket-id BUCKET --key sample.txt

License

MIT. See LICENSE.

Release files for vautra-sdk 1.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for vautra-sdk 1.1.2
File Size Uploaded
vautra_sdk-1.1.2.tar.gz 56.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for vautra-sdk 1.1.2
File Interpreter ABI Platform
vautra_sdk-1.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 96.7 kB

Release files / vautra_sdk-1.1.2.tar.gz

Download URL vautra_sdk-1.1.2.tar.gz
Size 56.7 kB
Tags Source
SHA-256 checksum
How to use checksums
1376291f5e564db985c32c1e204e5ed04bb1120681160c198753e2042a15b55d
BLAKE2b-256 checksum
How to use checksums
ba4b9665a626e791ea05a671fc1edefc2743c16421d6a8570a6923cdc43e93b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / vautra_sdk-1.1.2-py3-none-any.whl

Download URL vautra_sdk-1.1.2-py3-none-any.whl
Size 40.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aa6b9756b069a42212ba2e50febe99c37d3abf04410877d2d78b72d79f4774f0
BLAKE2b-256 checksum
How to use checksums
671c9393776392144cf7c973e9d0165536ebd2d95b1718a3702e86d4812750a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

1.1.2 This release

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page