Skip to main content
Both SDKs are thin. They are generated from the same OpenAPI document as the API reference, with no caching and no validation beyond types. They add two things of their own: they retry failed requests that are safe to repeat, and they import large sets of documents in batches. Any request the SDK makes, you can make with curl against https://api.vainona.ai/v1.

Methods

Methods mirror the routes. TypeScript uses the same names in camelCase.
The rest of the API: Namespace names and document ids may contain /. The SDKs send it as %2F, as the API requires. A template is a namespace handle on a prefix ending in /*, such as db.namespace("acme/prod/*"), and its * is sent as it is.

Requests and responses are the API’s JSON

Request and response bodies use the API’s own field names (wait_for, top_k, rank_by) in both languages. Any JSON body in these docs, or one copied from the dashboard’s query builder, can be passed to the SDK unchanged. Options that are not part of a JSON body follow each language’s conventions, such as include_history=True in Python and { includeHistory: true } in TypeScript. The types are strict:
  • Answers and definitions are discriminated unions on type. In TypeScript, answer.p type-checks only after answer.type === "bool".
  • Filters are typed tuples: [field, op, value], ["And" | "Or", [...]] or ["Not", filter]. An unknown operator is a type error.
In Python, filters are tuples. mypy cannot check a nested tuple literal, so use And, Or and Not:
Python responses are plain dicts, typed with TypedDicts in vainona.types. Nothing is validated at runtime, so fields and enum values the API adds later never break your client.

Errors and retries

Every error response becomes an ApiError with the HTTP status, the API’s code (such as budget_exceeded or too_large), its message and details. An error response that is not the API’s JSON, such as a proxy’s error page, or a success whose body is not JSON, gets the code unknown, a generic message and, when the response has one, details.request_id. Network errors, and timeouts in Python, are raised as they are. Each call is retried at most twice by default. Set max_retries in Python or maxRetries in TypeScript on the client to change it.
  • 429 or 503 with Retry-After. Retried after waiting that long, for any call: the API refused it without acting on it. A Retry-After over 60 seconds (MAX_RETRY_AFTER_SECONDS) is not waited out, and the error is returned at once. A daily allowance that is used up sends no Retry-After and says when it renews in details.resets_at.
  • Network errors, timeouts, 500, 502, 503 and 504. Retried only when the call is safe to repeat: a read (every GET, and query), a write, which is idempotent by construction, or any call with an idempotency key. The wait starts at 0.5 seconds and doubles on each retry up to 8 seconds, with random jitter, unless the response gives a Retry-After.
  • Anything else is returned at once, including every other 4xx, and a failed call that is not safe to repeat, such as creating a judgment without a key.

Idempotency keys

Every call that changes something takes an idempotency key, sent as the Idempotency-Key header: idempotency_key="..." in Python and { idempotencyKey: "..." } as the last argument in TypeScript. While the API still has the original response, a request with the same key gets that response back instead of running again. Use one key per logical request, and reuse it only for the same request. A call with a key is retried like a write.
Writes need no key to be retried safely; a key only saves the second write when the first one landed.

Importing documents

ns.import_documents(documents) in Python and ns.importDocuments(documents) in TypeScript upsert a large set of documents. They read documents as they go, from any iterable (and in TypeScript any async iterable), so an import never has to fit in memory.
  • Batches. Each write holds up to 1,000 documents or 64 MB, the most the API takes.
  • Concurrency. Up to concurrency writes at once, 4 by default. Python runs them on a thread pool.
  • Retries. Each batch has its own idempotency key, reused on its retries, which follow the client’s rules above.
  • Repeated ids. No id is in two writes at once. A document whose id is still being written waits for that write, so when your input repeats an id, the later document is the one that stays.
  • Failures. A batch that still fails after its retries is recorded, and the import carries on. stop_on_failure=True (stopOnFailure: true) stops starting new batches after the first failure.
  • Progress. on_progress (onProgress) is called after each batch with the totals so far.
It returns a summary: documents and batches written, failures, each with the batch’s ids and its error, and stopped. A write commits all of its documents or none, and writing them again is safe, so once you have fixed the cause, write a failed batch’s ids again. See import existing data.