{"openapi":"3.1.0","info":{"title":"Nocturn Quality API","version":"0.1.0","description":"One base URL and one key for three services: **Audit** (security), **Smoke** (release, accessibility, visual, load) and **SEO** (technical SEO and AI visibility).\n\nAuthenticate with `Authorization: Bearer <key>` or `X-Nocturn-Api-Key: <key>`. Every response carries an `x-request-id`.\n\nNamespaced routes map onto each service's own `/v1` API: `POST /v1/smoke/smoke-runs` reaches the Smoke service's `POST /v1/smoke-runs`. The full per-service contracts are served at `/v1/seo/openapi.json`, `/v1/audit/openapi.json` and `/v1/smoke/openapi.yaml`.\n\nLong-running work is asynchronous: create a run, receive `202` with a `Location` header, then poll it. `Idempotency-Key` is forwarded so CI retries never queue duplicates."},"servers":[{"url":"/quality"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}}},"paths":{"/healthz":{"get":{"security":[],"responses":{"200":{"description":"Gateway health"}}}},"/readyz":{"get":{"security":[],"responses":{"200":{"description":"Gateway ready"},"503":{"description":"Upstream unavailable"}}}},"/metrics":{"get":{"security":[],"responses":{"200":{"description":"Gateway metrics"}}}},"/openapi.json":{"get":{"security":[],"responses":{"200":{"description":"Unified API contract"}}}},"/v1/seo/openapi.json":{"get":{"responses":{"200":{"description":"SEO API contract"}}}},"/v1/audit/openapi.json":{"get":{"responses":{"200":{"description":"Audit API contract"}}}},"/v1/smoke/openapi.yaml":{"get":{"responses":{"200":{"description":"Smoke API contract"}}}},"/v1/usage":{"get":{"responses":{"200":{"description":"Unified gateway usage"}}}},"/v1/admin/customers":{"post":{"responses":{"201":{"description":"Customer and one-time API key"}}}},"/v1/admin/customers/{customerId}/rotate":{"post":{"responses":{"200":{"description":"Rotated customer API key"}}}},"/v1/admin/customers/{customerId}/keys/{keyId}":{"delete":{"responses":{"200":{"description":"Revoked customer API key"}}}},"/v1/capabilities":{"get":{"security":[],"summary":"Catalog of every check the gateway offers","description":"Lists each capability with its input plane (`url` = public/keyless, `repo` = repository access, `key` = external account/API key), tier (`free`/`paid`) and status (`live`/`planned`), grouped by plane. This is the 'A to Z' surface: what exists today and what is next.","responses":{"200":{"description":"Capability catalog with totals and planes"}}}},"/v1/pricing":{"get":{"security":[],"summary":"Public price list","responses":{"200":{"description":"Free surface plus self-serve tiers"}}}},"/v1/checkout":{"post":{"security":[],"summary":"Start a self-serve subscription checkout","description":"Body `{ \"plan\": \"solo\"|\"agency\"|\"studio\", \"email\": \"you@example.com\" }`. Returns a Stripe Checkout `url` and a `deliveryUrl`. Fails closed (503) when Stripe is not configured.","responses":{"201":{"description":"Checkout session created"},"400":{"description":"Invalid plan or email"},"503":{"description":"Checkout unconfigured"}}}},"/v1/checkout/{sessionId}":{"get":{"security":[],"summary":"Fetch the API key after payment","description":"GET with `?email=` (the email used at checkout). Returns the key once the customer exists, `404 not_ready` before the webhook lands.","responses":{"200":{"description":"Customer and one-time API key"},"404":{"description":"Payment not processed yet"}}}},"/v1/access-request":{"post":{"security":[],"summary":"Request an API key (no payment provider)","description":"Body `{ \"email\": \"you@example.com\", \"plan\": \"solo\" }`. Records a lead for manual key delivery while self-serve checkout is unconfigured. Returns `201`; `503` when the lead store is off.","responses":{"201":{"description":"Request received"},"400":{"description":"Invalid email or plan"},"503":{"description":"Lead store unconfigured"}}}},"/v1/admin/leads":{"get":{"summary":"List access requests (admin)","responses":{"200":{"description":"Leads"},"401":{"description":"Unauthorized"}}}},"/v1/scan":{"post":{"security":[],"summary":"Free scan of any public URL (no API key)","description":"Body `{ \"url\": \"https://example.com\" }`. Runs the Smoke service's passive security scan (availability, TLS, security headers, cookies) and the SEO service's deep audit (10-page crawl, on-page, technical, PageSpeed, server, coverage, backlinks) in parallel and merges them. Code audit needs repository access and is not part of the free scan. Uses only ordinary page requests; private and internal addresses are rejected. Limited to 5 scans per 10 minutes per IP.","responses":{"202":{"description":"Scan queued; poll statusUrl"},"400":{"description":"Invalid or non-public target"},"429":{"description":"Rate limited"}}}},"/v1/scan/{id}":{"get":{"security":[],"summary":"Passive scan status and findings","responses":{"200":{"description":"Scan status, summary and checks once finished"},"404":{"description":"Unknown scan"}}}},"/v1/billing/webhook":{"post":{"security":[],"responses":{"200":{"description":"Stripe event accepted"},"400":{"description":"Invalid signature or event"}}}},"/v1/seo/{path}":{"get":{"responses":{"200":{"description":"SEO API route"}}},"post":{"responses":{"200":{"description":"SEO API route"}}}},"/v1/audit/{path}":{"get":{"responses":{"200":{"description":"Audit API route"}}},"post":{"responses":{"200":{"description":"Audit API route"}}}},"/v1/smoke/{path}":{"get":{"responses":{"200":{"description":"Smoke API route"}}},"post":{"responses":{"200":{"description":"Smoke API route"}}}}}}