SDKs & CLI

Two official clients are built and tested against the running API: Python and TypeScript. Neither is on PyPI or npm yet, and this page says so plainly rather than showing an install command that fails.

Status: built and verified, not yet published. The clients are complete for the 0.1 surface below and run against the sandbox on every change. What is missing is the registry release, so pip install voxelion and npm i @voxelion/sdk do not work yet. Until they do, the HTTP reference is the supported path — it is generated from the running API rather than written by hand.

What the clients cover

Deliberately one job, done properly, rather than every endpoint half-modelled. The 0.1 surface is the work path — dedup, jobs, reports, manifests and balance. Account settings, API keys, billing history and administration are not modelled: an endpoint a client exposes is one whose shape we are promising to keep, and that promise is worth making narrowly.

PackageStatusSurface
Python
voxelion
Built & tested. Not published.Typed client on httpx and pydantic, and nothing else. Batch dedup, queued jobs with polling, report and manifest models, balance.
TypeScript
@voxelion/sdk
Built & tested. Not published.The same surface, method for method. Platform fetch only, so it runs unchanged in Node, the browser and edge runtimes. Ships ESM and CJS with type declarations.
CLI
not started
Planned, on top of the TypeScript client.For people who have a directory and a question, not an integration. Built on the SDK so it is an argument parser, not a third implementation to keep in sync.

What both clients guarantee

  • Nothing is ever deleted. A report and its manifest tell you what is redundant. Acting on that stays your decision — there is no call in either client that removes a file.
  • Typed errors on code, not on status. A 402 is an InsufficientCreditError carrying what the run needed and what you had. Branch on the class or on code; the prose message may be reworded at any time.
  • Retries that do not make things worse. Retry-After is honoured on 429; 5xx backs off exponentially with full jitter. A 400 or a 402 is never retried — neither becomes valid by asking again, and retrying a metered call risks doing the work twice.
  • Both speak /api/v1. A field may be added to a documented response, never removed, renamed or retyped. Anything that has to change incompatibly is a v2.

Python

from voxelion import Voxelion

vx = Voxelion()                                   # reads VOXELION_API_KEY

report = vx.dedup(["a.png", "b.png"], engine="curate")
print(report.leakage, len(report.clusters))

# A large archive is queued rather than held on one connection.
job = vx.submit_job("scans.zip", engine="health")
report = job.wait(timeout=1800)                   # polls with backoff

plan = vx.manifest(report.id)                     # what to keep, what to drop
print(len(plan.keep), len(plan.drop))

TypeScript

import { Voxelion } from "@voxelion/sdk";

const vx = new Voxelion();                        // reads VOXELION_API_KEY

const report = await vx.dedup(["a.png", "b.png"], { engine: "curate" });
console.log(report.leakage, report.clusters.length);

const job = await vx.submitJob("scans.zip", { engine: "health" });
const done = await job.wait({ timeoutMs: 1_800_000 });

In a browser served from the same origin as the API, point it at the path rather than an origin — that keeps the calls same-origin instead of buying a CORS preflight for nothing — and pass a function when the credential can change:

const vx = new Voxelion({
  baseUrl: "/api/v1",
  apiKey: () => localStorage.getItem("session"),  // asked on every request
});

This is what our own console does. It runs on this package, which is the point: the client you would install is the client we use, so it cannot quietly rot into something that only works for us.

Until they are published

The API is plain HTTP with bearer auth and JSON responses, so any HTTP client works. This is the whole batch path:

import os, requests

BASE = "https://api.voxelion.ai/api/v1"
KEY  = os.environ["VOXELION_API_KEY"]

def dedup(paths, engine="curate", max_distance=10):
    files = [("files", (os.path.basename(p), open(p, "rb"))) for p in paths]
    r = requests.post(
        f"{BASE}/dedup",
        headers={"Authorization": f"Bearer {KEY}"},
        files=files,
        data={"engine": engine, "maxDistance": max_distance},
        timeout=600,
    )
    r.raise_for_status()          # 402 = top up, 403 = consent, 429 = back off
    return r.json()

report = dedup(["a.png", "b.png"])
print(report["leakage"], len(report["clusters"]))

Read retry semantics before putting that in a loop.

Reference generated from live API (https://api.voxelion.ai) on 2026-08-30. The endpoint list, error codes and limits on this page are produced from the API's own route table — if an endpoint is not listed here, it is not enabled on production.