POST /api/v1/audit
Audit a single URL through the WCAG, privacy, or AI-governance branch. Authentication is via X-API-Key. The endpoint is the entry point for Lexinode's first product slice — it returns machine-readable findings you can pipe into your tracker or CI gate.
Authentication
AUDIT_SEED_API_KEY before deploy to create the first-customer key; the server stores only its SHA-256 hash.-H "X-API-Key: $LEX_KEY"Rate limits
Each API key gets 10 requests per 60-second fixed window. Reservations happen before the target URL is crawled or analyzed. On exhaustion, the endpoint returns 429 with Retry-After and the RateLimit-* headers.
Branches and scope
- Consent before non-essential cookies: Consent must be visible before confirmed marketing or analytics evidence.
- Marketing and analytics cookies: Known non-essential cookies must not appear in the initial response or before consent.
- Consent banner structure: A visible static banner must expose category controls plus separate accept and reject/decline affordances.
- Do Not Sell or Share / opt-out: The scanned page must contain a linked opt-out or privacy-choices control.
- Linked privacy policy: The scanned page must link to a privacy policy or privacy notice.
- Privacy-policy accessibility: The selected policy link must resolve to a reachable, non-empty 2xx response.
It does not execute JavaScript or follow linked scripts. It follows at most one selected privacy-policy link with the same HTTPS, DNS, redirect, timeout, and size protections as the homepage crawl. Dynamic behavior that static HTML cannot prove is returned as an inconclusive warning.
- AI disclosure notice
ai-governance.ai-disclosure-notice: Govern: the page should disclose AI use, AI-generated content, or automated decisions. - Model card or system description
ai-governance.model-card-or-system-description: Measure: the page should link to a model card, system card, system description, or technical documentation. - Training-data provenance
ai-governance.training-data-provenance: Map: the page should disclose training-data, dataset-source, data-origin, or dataset-provenance information. - Human-oversight contact
ai-governance.human-oversight-contact: Manage: an oversight, review, appeal, or escalation statement should be paired with a contact mechanism. - Model provider and version
ai-governance.model-provider-and-version: Govern: visible text or a named documentation link should identify both the model provider and a concrete model/version. - System purpose and role
ai-governance.system-purpose-and-role: Map: visible text or a named documentation link should state the system purpose, intended use, or model/system role. - Training-data categories and sources
ai-governance.training-data-categories-and-sources: Map / Measure: the page should disclose both training-data categories and a data-source or provenance statement. - Model-governance artifacts
ai-governance.model-governance-artifacts: Measure: the page should expose a model-governance artifact such as a risk assessment, evaluation, monitoring record, or governance policy.
It scans only bounded initial HTML. It does not execute JavaScript, follow linked model cards or documentation, or make extra network requests, so a pass means a visible signal was found rather than legal certification or proof of compliance.
Request
| Field | Required | Type | Notes |
|---|---|---|---|
| branch | no | "wcag" | "privacy" | "ai-governance" | Default: "wcag". Use "privacy" for GDPR/CCPA/CPRA checks or "ai-governance" for static EU AI Act / NIST AI RMF disclosure checks. |
| url | yes | string (https URL) | The publicly crawlable page to audit. Loopback / private hosts are rejected. |
| standard | no | "WCAG21A" | "WCAG21AA" | "WCAG22AA" | Used only when branch is "wcag". Default: "WCAG21AA"; omit it for "privacy" and "ai-governance". |
| includeWarnings | no | boolean | When false, only error-severity findings are returned. Default: true. |
Example calls
curl -X POST https://lexinode.polsia.app/api/v1/audit \
-H "X-API-Key: $LEX_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"branch": "ai-governance",
"includeWarnings": true
}'GET /api/v1/audit/report
Download a one-page vendor-questionnaire summary from persisted audit snapshots. Send exactly one domain or url query parameter; both normalize to the HTTPS origin before matching. The request must carry a better-auth session for an admin user.
curl -G https://lexinode.polsia.app/api/v1/audit/report \
-H "Cookie: $LEX_ADMIN_SESSION_COOKIE" \
--data-urlencode "domain=example.com"curl -G https://lexinode.polsia.app/api/v1/audit/report \
-H "Cookie: $LEX_ADMIN_SESSION_COOKIE" \
--data-urlencode "url=https://example.com/pricing"200withContent-Type: application/pdfContent-Dispositionis an attachment namedlexinode-audit-example.com.pdf.Cache-Control: no-storeprevents cached private reports.
For the normalized origin, Lexinode selects the newest wcag, privacy, and ai-governance snapshot belonging to that origin. All three snapshots are required; a missing pillar returns JSON 404 instead of an incomplete PDF.
Each pillar contributes Pass: 1 only when its findings list is empty; otherwise it contributes Fail: 1. Persisted error and warning totals plus inconclusive review counts are shown separately, and no control-level passes are inferred.
The PDF lists up to two open failed controls per pillar from the remediation-ticket projection, ordered by error before warning. Empty pillars say No open failed controls.
Invalid or ambiguous targets return 400. Missing or non-admin sessions return 403. Missing pillar data returns 404. Unexpected server failures return 500.
Error codes
| Code | Meaning | Body |
|---|---|---|
| 201 | Audit recorded. | AuditResponse JSON — see shape below. |
| 400 | Body failed contract validation. | { "errors": { "<field>": "<message>" } } |
| 401 | API key missing or invalid. | { "error": "invalid api key" } |
| 429 | This API key exceeded the 10-request, 60-second fixed window. | { "error": "rate limit exceeded", "retryAfterSeconds": 17 } |
| 422 | Target URL is unreachable, blocked by the crawler, or returns 4xx/5xx. | { "error": "unreachable or blocked" } |
| 502 | AI returned non-conformant structured output after retry for the WCAG branch. | { "error": "analysis failed" } |
Keys are stored as SHA-256 hashes; the raw value is never persisted. To rotate the seeded key, set a new AUDIT_SEED_API_KEY and deploy. Older hashes are not revoked automatically, so revoke them through your operational key-management process.