Skip to main content
The Vaquill SDKs are typed clients for the US Data API. They wrap the same endpoints described in this guide and add retries, typed errors, pagination helpers and credit awareness. Anything an SDK can do, you can also do with plain HTTP. The Go, Java, Kotlin and integration packages are not on any registry yet. Their pages show the intended coordinates and how to build from source. All SDKs are MIT licensed. The data you retrieve is covered by separate terms. See Rights and licensing.
The SDKs cover the US document only. For India, use the separate OpenAPI document directly.

Authentication

Create a key in your dashboard under API Keys. Keys start with vq_key_. By default the client reads VAQUILL_API_KEY from the environment. You can also pass api_key (Python) or apiKey (TypeScript) explicitly, and an explicit value wins over the environment. The client rejects a key that does not start with vq_key_, and the key never appears in an error message or a log line.
Use the SDKs server-side only. A key shipped in browser code is visible to every visitor. The TypeScript client warns when it sees a browser.

Configuration

client.with_options(...) (Python) and client.withOptions({ ... }) (TypeScript) return a derived client that shares the key and the spend counter. Every method also takes per-call timeout, max_retries / maxRetries, headers and idempotency_key / idempotencyKey options.

Which calls cost credits

A call is charged when the API declares the Idempotency-Key header on its operation. That is 25 of the 36 operations in the US document. Both SDKs apply the same rule, and a test in each repo derives the list from the API contract. Free calls: statutes.coverage, boards.list, every watch operation except the change diff (create, list, update, delete, test, changes and deliveries), credits.balance and pricing.get. Prices are not hard-coded in the SDKs. client.pricing.get() is free and returns the live price list. Some charged calls return 0 credits (for example a body that is not held), so read the figure from the response.

Retries and timeouts

The clients retry 408, 429 and 5xx responses, plus 409 only for idempotency_in_progress. Connection errors and timeouts are retried when it is safe. Backoff starts at 0.5 seconds, doubles to an 8 second cap and is scaled down by 0 to 25 percent jitter. The default is 2 retries; max_retries=0 / maxRetries: 0 turns them off. retry-after-ms wins over Retry-After, which wins over the body’s retryAfterSeconds. A wait above 120 seconds is not retried. Never retried: a 402 insufficient_credits, daily_cap_exceeded, any other 4xx, and anything the server marks retryable: false.

Idempotency

Each charged call sends one generated Idempotency-Key, reused on every retry of that call. When the server honours the key it replays the stored response instead of charging again, and the response reports idempotent_replayed / idempotentReplayed. Pass idempotency_key="..." (Python) or idempotencyKey: "..." (TypeScript) to choose your own key.
If you turn automatic keys off (idempotency_keys=False in Python, idempotencyKey: false in TypeScript), a charged call is no longer retried after a timeout, a connection error or a 5xx, because the first attempt may already have been billed. A 429 is still retried, since it is refused before any work. Free POSTs without a key (watches.create, watches.test) follow the same rule, so a retry cannot create a second watch.

Errors

Every error derives from VaquillError. Status errors carry the HTTP status, the request id, the parsed body, and code, retryable and a retry hint when the server sends them. The code is checked first, then the status, so an unknown code still gives the status class. A 422 message ends with the first validation reasons from the response’s errors list, so you can read what was rejected without opening the body. See Errors for the wire format.

Pagination

Python iter_* helpers and TypeScript *All methods hide the offset, cursor and sinceId/beforeId styles behind one iterator, with a way to read whole pages.
On a charged endpoint every page spends credits. Iterating a whole result set can cost far more than one call. Set max_pages / maxPages or max_items / maxItems, or use the spend guard. Without a limit a TypeScript iterator runs until the data ends. The Python pager reports truncated when its guard stopped it with more data available.
Listing watches, changes and boards is free.

Batch helpers

Three helpers wrap the batch endpoints and accept any number of inputs: resolve_batch_all / resolveBatchAll (500 citations per request), get_sections_all / getSectionsAll (50 section ids) and session_laws.get_batch_all / sessionLaws.getBatchAll (200 ids). Each splits the input at the per-call cap, sends exact repeats once, returns the members of every response as one flat list in input order, and sends nothing for an empty input. The spend guard is checked before every chunk, so a guard reached part way stops the remaining chunks. A caller’s idempotency key is kept for the first chunk and suffixed with -<chunk number> for later ones. These helpers are charged per item. The batch helpers are available in the Python, TypeScript, Go, Java and Kotlin clients.

Spend guard

Pass max_credits (Python) or maxCredits (TypeScript) when you create the client. Once responses on that client have reported that many credits, charged calls raise SpendGuardExceeded / throw SpendGuardExceededError before sending anything. It checks what is already spent, not the cost of the next call. client.credits_spent / client.creditsSpent shows the running total, shared with derived clients. While a guard is set, charged calls on the client run one at a time, from the check to the moment their credits are counted, so concurrent calls cannot all pass the check and overshoot the cap. Without a guard, calls keep full concurrency.

Logging

Python logs through the standard logging module under the vaquill logger. TypeScript takes a logger option (any subset of debug, info, warn and error, default console) and a logLevel option (default warn). The API key is always redacted, and idempotency keys are logged by their first 8 characters only.

Raw responses

Python: client.with_raw_response.request(...) returns the parsed body with request_id, rate_limit and credits_charged_this_call. TypeScript: .withResponse() on any call returns { data, response, meta }. Both clients also have raw_request / rawRequest for endpoints newer than the SDK. Python’s raw_request returns an APIResponse, so call .parse() for the JSON body. TypeScript’s rawRequest returns the parsed value directly.

Webhook verification

Both SDKs verify the raw request body against the Standard Webhooks headers (webhook-id, webhook-timestamp, webhook-signature) with a 300 second tolerance, accept several signatures and a list of secrets for rotation, and treat a whsec_ secret as base64. A whsec_ secret must be valid base64. Go, Java and Kotlin reject one that is not. Python and TypeScript reject it from the first release after 0.2.0; version 0.2.0 of both still uses the text as the key, so check that your secret is copied in full. Every client rejects an empty secret. They can also read the legacy X-Vaquill-Signature: sha256=<hex> header, but only when you opt in.
The legacy header signs only the body, so it has no replay protection: a captured delivery verifies forever. Both SDKs reject it unless you set allow_legacy=True (Python) or allowLegacy: true (TypeScript).

Types

Python responses are Pydantic v2 models and the package ships py.typed. TypeScript types are generated from the OpenAPI document. Unknown enum values and extra response fields do not raise, so a new corpus type or field will not break an older SDK. Python uses snake_case names and TypeScript uses camelCase. The SDK maps them to the wire names for you.

Versioning and support

  • SDKs follow semantic versioning. Before 1.0, the API surface may change in minor versions.
  • The SDK major version tracks the major version of the API contract.
  • Python 0.2.0 and TypeScript 0.2.0 are the published versions. Go, Java and Kotlin are at 0.1.0 in source and unpublished.
  • Python 3.11 and later are supported. Node 20 and later are supported, and the TypeScript client is tested on Node 20, 22 and 24.
  • Breaking changes are listed in the release notes.
  • Report bugs on the issue tracker of the vaquill-sdks repository. For account or billing questions, email support.

Next steps

Python

Install, quickstart, async and error handling

TypeScript

Install, quickstart and error handling

Go, Java and Kotlin

Not yet published. Intended coordinates and build from source: Go, Java, Kotlin

Integrations

LangChain, LlamaIndex and Vercel AI SDK tools. Not yet published

CLI

Search and resolve from the shell

API Reference

Every endpoint and schema
Last modified on October 29, 2026