This release is a pre-release and may not be stable for production use.
vaquill
Python SDK for the Vaquill US primary law Data API: statutes, regulations, court rules, constitutions, session laws and law-change alerts.
Server-side use only: an API key (vq_key_...) must never ship to a browser.
Python 3.11 or newer. Sync and async clients with the same methods.
from vaquill import Vaquill
client = Vaquill() # reads VAQUILL_API_KEY; VAQUILL_BASE_URL overrides the host
# 2 credits. Even an unresolved citation is charged: the answer is what you pay for.
result = client.statutes.resolve("42 U.S.C. 1983")
if result.resolved and result.section:
body = client.statutes.get_section_body(result.section.act_id) # 6 credits
print(body.plain)
hits = client.statutes.search(
"statute of limitations for medical malpractice", state="ca"
) # 4 credits
for hit in hits.results:
print(hit.citation, hit.section_title)
print(hits.credits_consumed, client.credits_spent)
Async is the same with AsyncVaquill and await:
import asyncio
from vaquill import AsyncVaquill
async def main() -> None:
async with AsyncVaquill() as client:
balance = await client.credits.balance()
print(balance.credits_remaining)
asyncio.run(main())
Namespaces
| Namespace | What it does |
|---|---|
client.statutes |
search, resolve, sections and their text, browse, changes, enactments, rulemaking, cross-references, citation extraction |
client.session_laws |
acts as enacted: search, list, record, text, versions, changes |
client.watches |
law-change alerts by webhook or email |
client.boards |
the sources a watch can follow |
client.credits |
balance() |
client.pricing |
get() the credit price of every endpoint |
All 36 operations, their method names and which ones cost credits are in docs/OPERATIONS.md.
Required arguments come first and may be positional; optional ones are keyword-only snake_case (sent to the API as camelCase).
Errors
Every failure is a VaquillError. Status errors carry status_code, request_id and the parsed body.
import vaquill
try:
client.statutes.resolve("42 U.S.C. 1983")
except vaquill.InsufficientCreditsError:
... # never retried; top up credits
except vaquill.RateLimitError as err:
print(err.retry_after_seconds) # seconds; the client already retried with backoff
except vaquill.APIStatusError as err:
print(err.status_code, err.request_id)
Pagination and the credit warning
iter_* helpers hide the offset, cursor and sinceId/beforeId styles behind one iterator.
On a charged endpoint every page spends credits. Iterating a whole result set can cost far more than one call, so always set max_pages or max_items.
pager = client.statutes.iter_search(
"negligence", state="ny", limit=10, max_pages=3
) # at most 12 credits
for hit in pager:
print(hit.citation)
print(pager.truncated) # True when the guard stopped it with more available
for page in client.statutes.iter_divisions("STATE", state="wa", max_items=100).pages():
... # whole pages, to control cost yourself
Spend guard
client = Vaquill(
max_credits=500
) # charged calls raise SpendGuardExceeded once 500 credits are used
client.credits_spent # running total across this client and any with_options() copy
client.pricing.get() # free: the live price list
Charged calls send an Idempotency-Key automatically and are only retried when that is safe.
Pass idempotency_key="..." to any call to supply your own.
Raw responses
raw = client.with_raw_response.request(
"GET",
"/api/v1/us/statutes/resolve",
cast_to=dict,
params={"cite": "42 U.S.C. 1983"},
charged=True,
)
raw.request_id, raw.rate_limit.remaining, raw.credits_charged_this_call, raw.parse()
client.raw_request(method, path, ...) reaches endpoints newer than this SDK and returns plain JSON.
Webhooks
Verify the raw request body, never re-serialised JSON.
from vaquill import verify_webhook, WebhookVerificationError
try:
event = verify_webhook(raw_body, request_headers, WEBHOOK_SECRET, allow_legacy=False)
except WebhookVerificationError:
... # respond 400
A watch is created with client.watches.create("state", state="wa", webhook_url=..., webhook_secret=...).
See examples/ for runnable versions (resolve_citation.py, search_and_paginate.py, watch_and_verify_webhook.py); the test suite runs them against a fake server.
Command line
Installing the package also installs a vaquill command (standard library only, no extra dependencies).
export VAQUILL_API_KEY=vq_key_...
vaquill resolve "42 U.S.C. 1983" # 2 credits
vaquill search "medical malpractice limitations" --state ca --limit 5 --json
vaquill section USC_42_1983 --body # 6 credits
vaquill credits # free
vaquill webhook verify --secret "$SECRET" --id "$ID" --timestamp "$TS" --signature "$SIG" < body.json
Charged commands print credits used: N on stderr, so stdout stays pipeable.
Exit codes: 0 ok, 1 error, 2 usage, 3 auth, 4 no credits, 5 rate limited, 6 not found, 7 network.
Every command, flag and the JSON shape are in docs/CLI.md.
Types
Responses are Pydantic v2 models in vaquill.types, generated from openapi/vaquill-us.json by scripts/gen_models.py.
Unknown fields are kept and unknown enum values never raise: a field typed Status | str holds the enum member for values this SDK knows and the plain string for new ones.
Every top-level response has credits_consumed, request_id and idempotent_replayed.
Development
.venv/bin/python scripts/gen_models.py # regenerate src/vaquill/types after changing the spec
.venv/bin/python scripts/gen_async.py # regenerate src/vaquill/resources/_async after editing a sync resource
.venv/bin/python -m pytest -q
The sync resources in src/vaquill/resources/ are the one hand-written definition; the async ones are derived from them mechanically and a test fails on drift.
Metadata
Release files for vaquill 0.1.0a1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| vaquill-0.1.0a1.tar.gz | 175.3 kB | With provenance | Details for vaquill-0.1.0a1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| vaquill-0.1.0a1-py3-none-any.whl | Python 3 | none | any | Details for vaquill-0.1.0a1-py3-none-any.whl |
Total release size: 362.3 kB
Release files / vaquill-0.1.0a1.tar.gz
| Download URL | vaquill-0.1.0a1.tar.gz |
|---|---|
| Size | 175.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ab301f941dff0e6c5eb1d01af9460b5979d2b5a64d01485219a0e50050c0d4a7
|
|
BLAKE2b-256 checksum How to use checksums |
075e1c8c7b384ac7850fb01d200568593f7ac3e8249808c567d7fe519736e6af
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logRelease files / vaquill-0.1.0a1-py3-none-any.whl
| Download URL | vaquill-0.1.0a1-py3-none-any.whl |
|---|---|
| Size | 187.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
09bb24368e03768f8bc43c98e0790ffe81da4cc6724cff06df757a52b28b88c9
|
|
BLAKE2b-256 checksum How to use checksums |
2937a240e8578e1e6ace0d8c77e63f2efc70dee7a09e7bff9aed909176b1c891
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logSecurity for vaquill 0.1.0a1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for vaquill-0.1.0a1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.