Vol. II·Issue 09·The Product Desk·Jul 2026·5 min read

§ Product

Official SDKs:
Python and TypeScript.

Every LexAPI integration so far started with somebody hand-rolling auth, retries, and error handling. As of today that’s over: pip install lexapi-client and npm install @lexapi/client give you the whole API — typed, retried, and honest about credits — in two lines.


Two lines to your first document.

# Python — sync and async clients, dependency-light (httpx only)
from lexapi import LexAPI

client = LexAPI()  # reads LEXAPI_API_KEY from the environment
doc = client.get_document("32016R0679")
print(doc.content.metadata.title)
// TypeScript — zero runtime dependencies, strict types, server-side
import { LexAPI } from "@lexapi/client";

const client = new LexAPI(); // reads LEXAPI_API_KEY
const doc = await client.getDocument({ celexNumber: "32016R0679" });
console.log(doc.content?.metadata?.title);

Full surface in both: keyword search, parsed document content (single and batch), recent documents, identifier resolution, the complete citation graph, semantic search including HyDE query rewriting, webhooks, streaming bulk export, and the new point-in-time version history.


What “official” buys you.

These are hand-written thin clients, not generated blobs — small enough to read in one sitting, opinionated where it counts:

  • Retries that respect the server. 429s and transient 5xx are retried with exponential backoff and full jitter; the server’s Retry-After always wins (clamped, so a pathological value can’t stall you); non-idempotent calls are never blindly replayed.
  • Typed errors you can branch on. CreditsExhaustedError carries resets_at; RateLimitedError carries retry_after. Both the typed error envelope and the legacy bare shape parse correctly, so nothing surprises your handler.
  • Credit visibility everywhere. Every response exposes what the call cost and what remains in your pool — no more guessing why a 402 arrived.
  • Nothing hidden, nothing silent. Tier clamping, truncation, and partial results surface as fields on the response, exactly as the API reports them.

The parts that are genuinely new.

Point-in-time retrieval. The corpus keeps an immutable snapshot every time a document’s content changes. The SDKs expose the history directly:

as_of = client.get_document_at_date("32016R0679", "2026-03-20")
print(as_of.document.version, as_of.document.content_hash)

Streaming export (Business tier) arrives as a real iterator — the NDJSON envelope lines are parsed off the stream for you, and stream.truncated tells you if the row cap cut in:

with client.export(document_type="regulation") as stream:
    for row in stream:
        index(row)
print(stream.done)  # {"written": ..., "truncated": ...}

HyDE is one flag away in both languages — and the response tells you whether it actually ran, because that’s what you were billed for.


Where this goes next.

Kotlin and Swift SDKs exist as scaffolds with the same contract and will graduate when demand shows. The Python and TypeScript clients follow semver from 0.x; the endpoint matrix and the shared SDK contract — retry policy, error taxonomy, credit visibility — are documented in each repo’s PLAN.md, so behaviour is identical wherever you integrate from.

Grab a free key (500 credits to start, then 150 a month, no card), install, and your first parsed regulation is one call away. Found a rough edge? Issues are open on both repos — thin clients mean fixes ship in hours, not quarters.