suspend function, every paginated endpoint is a Flow, and every model is a kotlinx.serialization data class.
It covers all 36 operations of the US Data API.
It targets JVM 11 and newer, and depends on kotlinx-serialization-json and kotlinx-coroutines-core.
Transport is the JDK java.net.http.HttpClient, so there is no HTTP engine to choose.
For the options shared by all SDKs, see the SDKs overview.
Install
Once the artifact is on Maven Central, the dependency will be:kotlin/ directory of the repository.
Vaquill-AI/vaquill-sdks, kotlin/ on GitHub.
Quickstart
close() (or use use {}) to release its threads.
Configuration
RequestOptions(timeout, maxRetries, idempotencyKey, headers), the last parameter of every method.
client.withOptions { ... } makes a copy that shares the transport and the spend total.
Authorization and Idempotency-Key cannot be overridden by default or per-call headers.
timeout is the total time for one HTTP attempt, from sending the request until the whole response body has been read.
Each retry gets a fresh budget. Connecting has its own fixed 5 s limit.
This is stricter than the Python SDK for very large bodies, so raise timeout for them or use Duration.ZERO.
The logger receives every line after API key redaction, and idempotency keys are logged by their first 8 characters only.
Read the status, request id and credits of a call with withResponse.
Errors
Everything the SDK throws extendsVaquillException.
code first, then by status, so an unknown future code still gives the status class.
Retries and idempotency
- Up to
maxRetries(default 2) retries with exponential backoff from 0.5 s to 8 s, scaled down by 0 to 25 percent jitter. retry-after-ms,Retry-Afterseconds andRetry-AfterHTTP dates are honoured. A wait longer than 120 s raises the error immediately.- Retried: 408, 429, 5xx (except 501) and the codes the server marks retryable. Never retried:
insufficient_credits,daily_cap_exceededand any response withretryable: false. - Connect failures never reached the server, so they are always retried.
- Other transport failures are ambiguous. They are retried only for GET and HEAD, or when the call carries an idempotency key.
- A 5xx on a charged call is not retried unless the call has an idempotency key, because it may already have been billed.
Idempotency-Key automatically, reused on every retry of that call.
Pass your own for a retry that spans processes.
VaquillException before any request.
ApiResponse.idempotentReplayed is true when the server replayed a stored answer. A replay is not charged again and not counted by the spend guard.
The batch helpers suffix a caller key with -1, -2 and so on for chunks after the first, because each chunk has a different body.
Spend guard
maxCredits caps what this client, and clients derived from it, will spend.
Charged calls are serialised by a coroutine Mutex while the cap is set, so the check, the call and the accounting are one step and the cap is exact even under heavy concurrency.
When the cap is reached the call throws SpendGuardExceededException and nothing is sent.
Free calls are never blocked. client.creditsSpent shows the running total.
Pagination and batch helpers
Every paginated endpoint has aniter... method returning a Paginator<T>, a cold set of Flows.
truncated is true when a guard cut the result short.
stuck is true when the server repeated the position it was just sent, or answered an empty page with hasMore: true. The loop stops instead of paying for the same page forever.
Batch helpers de-duplicate, chunk and join the results.
statutes.resolveBatchAll(citations)sends 500 per call.statutes.getSectionsAll(actIds)sends 50 per call.sessionLaws.getBatchAll(ids)sends 200 per call.
Webhooks
Verify the raw request body, never re-serialised JSON.- Standard Webhooks signatures with a
whsec_base64 secret (or a plain UTF-8 secret), and a timestamp tolerance of 300 s by default. - Pass several secrets (
secrets = listOf(new, old)) to accept both during a rotation. - An empty or blank secret, or a
whsec_secret that is not valid base64, throwsIllegalArgumentException. A misconfigured environment can never accept a forged event. Webhooks.verifychecks the signature only.unwrapalso parses the event.- The legacy
X-Vaquill-Signatureheader is rejected unless you passallowLegacy = true. It has no replay protection.
Versioning
An operation is charged when the contract declares theIdempotency-Key header on it. That is 25 operations.
Read the live prices with client.pricing.get(), which is free.
The User-Agent is vaquill-kotlin/0.1.0 kotlin/<version> java/<version> <os>.
A dedicated Java SDK also exists. For an endpoint newer than the SDK, use client.rawRequest(method, path, query, body, charged).
The release workflow, which signs the artifacts and uploads them to the Sonatype Central Portal, has never run.
The first release may need fixes, and a release candidate tag is planned first.
