SDKs
The wayid-verify SDK lets a gateway, reverse proxy, or API backend answer “what kind of
agent is calling me?” in one call — no user flow, and no crypto to stand up. Each package wraps
the public GET /api/v1/agent/{did} lookup behind a resolver, an
in-memory TTL cache, and a policy helper, with adapters for common frameworks.
| Package | Language | Adapters | Repo |
|---|---|---|---|
@lineagelabs/wayid-verify | TypeScript (Node 18+, Bun, Cloudflare Workers) | Express, Fetch/Worker | wayid-verify (js/) |
wayid-verify | Python 3.9+ | FastAPI / Starlette, Flask | wayid-verify (python/) |
wayid-nginx | NGINX (njs) | js_content edge handler | wayid-nginx |
Both language packages are dependency-free. The NGINX integration has its own page — see NGINX edge verification.
How it works
Section titled “How it works”An agent declares its identity with a request header:
WayID: wayid:agent:{24-char-base58} # full DID or the bare 24-char tailThe SDK extracts the header, resolves it against the issuer, caches the result, and produces a
decision — allow, deny, or flag. By default it fails open: a verifier outage, an
unknown DID, or a missing header never blocks traffic (the request is tagged, not rejected). This
is identification, not authentication — the v1 header is self-asserted. See the
Verified Agent Gateway page for the trust model.
Install
Section titled “Install”npm install @lineagelabs/wayid-verify # Node / Bun / Cloudflare Workerspip install wayid-verify # Python 3.9+Not on the registries yet. Until the packages are published to npm / PyPI, install them straight from GitHub:
Terminal window # Python — installs from the repo subdirectory in one steppip install "git+https://github.com/LineageLabs/wayid-verify.git#subdirectory=python"# JavaScript — install the tarball attached to a tagged releasenpm install https://github.com/LineageLabs/wayid-verify/releases/download/js-v0.1.0/lineagelabs-wayid-verify-0.1.0.tgz
TypeScript / JavaScript
Section titled “TypeScript / JavaScript”Express
Section titled “Express”import express from "express";import { wayIdMiddleware } from "@lineagelabs/wayid-verify/express";
const app = express();app.use(wayIdMiddleware({ issuer: "https://way.je" }));
app.get("/", (req, res) => { // req.wayid.decision -> "allow" | "deny" | "flag" // req.wayid.resolution.identityLevel, .did, .status res.json({ agent: req.wayid?.resolution.did ?? null });});By default the middleware tags the request (attaches req.wayid, forwards X-WayID-*
headers) but does not block. Pass enforce: true to return 403 on a deny decision.
Cloudflare Workers / Fetch
Section titled “Cloudflare Workers / Fetch”import { withWayId } from "@lineagelabs/wayid-verify/worker";
export default { fetch: withWayId( async (request, result) => { // result.decision, result.resolution return new Response(`Hello, ${result.resolution.did ?? "unknown agent"}`); }, { issuer: "https://way.je", enforce: false }, ),};Core resolver (framework-agnostic)
Section titled “Core resolver (framework-agnostic)”import { WayIDClient, decide } from "@lineagelabs/wayid-verify";
const client = new WayIDClient({ issuer: "https://way.je" });const resolution = await client.resolve("wayid:agent:7f3aB9cDe2FgHjKmNpQrSt4U");const decision = decide(resolution, { requireVerified: true }); // "allow" | "deny" | "flag"Python
Section titled “Python”FastAPI / Starlette
Section titled “FastAPI / Starlette”from wayid_verify.asgi import WayIDMiddleware
app.add_middleware(WayIDMiddleware, issuer="https://way.je")
@app.get("/")def root(request): # request.state.wayid.decision -> "allow" | "deny" | "flag" return {"agent": request.state.wayid.resolution.did}from wayid_verify.flask_ext import wayid_before_request
app.before_request(wayid_before_request(issuer="https://way.je"))# then read flask.g.wayid in a viewCore resolver
Section titled “Core resolver”from wayid_verify import WayIDClient, verify_headers, Policy
client = WayIDClient(issuer="https://way.je")result = verify_headers(request.headers, client, Policy(require_verified=False))# result.resolution.identity_level, result.decisionSet enforce=True on the middleware (or Policy(fail_closed=True)) to deny instead of tag.
Configuration
Section titled “Configuration”| Option | Default | Meaning |
|---|---|---|
issuer | https://way.je | Origin that minted the DIDs |
timeoutMs / timeout | 2000 | Per-lookup timeout |
cacheTtlMs | 60000 | TTL for found results |
negativeCacheTtlMs | 10000 | TTL for 404 (not-found) results |
policy.requireVerified | false | Require the owner identity to be verified |
policy.allowStatuses | ["active"] | Certificate statuses that may pass |
policy.failClosed | false | Deny (instead of fail open) when the lookup can’t complete |
Decision semantics
Section titled “Decision semantics”allow— registered, active, and meets the identity bar.deny— present but fails policy (wrong status, or unverified when required), or absent/failed under a strict (failClosed/requireVerified) policy.flag— present-but-unknown, or a fail-open outage: serve the request but tag it for logging.
Forwarded headers
Section titled “Forwarded headers”When tagging, the SDK forwards these to your upstream so the app can read the verified identity without repeating the lookup:
X-WayID-Decision allow | deny | flagX-WayID-Verified true | falseX-WayID-DID wayid:agent:...X-WayID-Identity-Level verified | unverifiedX-WayID-Status active | suspended | revokedStatus
Section titled “Status”Prototype for WayID issue #373. The canonical
wire contract lives in the way-id repo (.specs/product-spec.md §4.6 / .specs/tech-spec.md §5.5).
Cryptographic proof-of-possession (v2) is a planned layer built on Web Bot Auth / RFC 9421 — see
Verified Agent Gateway.