# Novence — full agent / LLM briefing > Complete API brief for shipping static sites with Novence. Live API: https://api.novence.ai > Start with the curated index at https://novence.ai/llms.txt. OpenAPI: https://novence.ai/openapi.yaml (also via redirects from api.novence.ai). ## Product Novence hosts static HTML/CSS/JS sites. Agents bootstrap an API key, upload files, deploy on the unverified trial if needed, get a live URL at `https://{suffix}.novence.ai/`, then verify email OTP to unlock Free. Do not wait for OTP before the first deploy. Static-only is not a dead end. Improve hosted sites with **third-party widgets** (paste a Cal.com / Snipcart / Shopify Buy Button / GA script or iframe — HTML is served as-is) and **baked-in data files** (`/data/menu.json` fetched same-origin). There is no plugin marketplace and no per-site server. Details: https://novence.ai/site-data ## Auth - Demo (no email): `POST /v1/demo` `{}` → `{ apiKey, accountId, anonymous: true }`. Same unverified caps. Claim later. - Bootstrap: `POST /v1/bootstrap` `{ "email": "…" }` → `{ apiKey, accountId, emailVerificationRequired }` — save `apiKey` and continue; unverified trial still publishes - Claim: `POST /v1/auth/claim` `{ "email" }` with `Authorization: Bearer nv_…` (anonymous key) → OTP emailed - Verify (after live URL): `POST /v1/auth/verify-email` `{ "email", "code" }` — OTP expires in **15 minutes**; unlocks Free - Resend OTP: `POST /v1/auth/resend-verification` `{ "email" }` → `{ sent: true, alreadyVerified?, emailVerificationRequired? }`. Sends even when already verified (`sent: true` is the signal). Needed for lost-key recovery. - Lost key: `POST /v1/auth/reissue-key` `{ "email", "code" }` with that OTP. **One OTP is enough** — reissue also verifies the email and revokes the old account key. Do not also call verify-email. Own rate limit (not bootstrap); 429 includes `Retry-After`. - All project APIs: `Authorization: Bearer nv_live_…` (or `nv_test_…`) - **Never** put `nv_` keys in browser HTML, URLs, or git. For a local account console: 1. `GET /v1/account/console-kit` (or MCP `get_account_console_kit`) 2. `POST /v1/account/sessions` → short-lived `mgmt_` token (scopes: `account:read`, `billing:portal`, `project:members`) 3. Write `novence-console.html` from **`htmlTemplate` as-is** (inject only snapshot + `mgmt_` — do not redesign). Serve on `http://127.0.0.1`; store `mgmt_` in sessionStorage only 4. Click a project in the kit for `GET /v1/projects/{id}/usage` and `GET /v1/projects/{id}/analytics` 5. Humans without the agent: `POST /v1/account/sessions/request` + `/verify` with email OTP ## Team seats (Pro / Scale only) - Owner invites: `POST /v1/projects/{id}/members` `{ email, role: viewer|editor|admin }` or MCP `invite_project_member` - Free/unverified owners get HTTP 402. Pro: 5 extra seats/project. Scale: 20. Gate is the **owner's** plan. - Invitee accepts at https://novence.ai/invite (`POST /v1/invites/accept` `{ token, otp? }`). Returns a **project-scoped** `nv_` key once — never email it, never share the owner's key - `create_project` always creates on the **caller's** account. Collaborators pass `project_id` to upload/deploy. Usage (deploys, storage) bills the owner - Only the owner can grant `admin`. Members may `DELETE /v1/projects/{id}/members/me` (`leave_project`) - Console-kit `mgmt_` scope includes `project:members` ## Account & billing UI (local only — no hosted dashboard) Product page: https://novence.ai/dashboard - Snapshot: `GET /v1/account` (nv_ or mgmt_) - Quotas alias: `GET /v1/billing/quotas` - Stripe Customer Portal: `POST /v1/billing/portal` `{ "returnUrl"? }` - Prefer `usage.storage_bytes` over `storage_gb` for exact accounting - `quotas.checkRuns` = included **check minutes** / month (same unit as `usage.check_minutes`) ## Analytics Product page: https://novence.ai/analytics - **Off by default.** Enable per project: `PATCH /v1/projects/{id}` `{ "analyticsEnabled": true }` or MCP `update_project_settings` `analytics_enabled: true`. Disable with `false`. - Cookieless HTML pageviews, 404s, top paths, referrer hosts, countries. No JS. 90-day retention. - `GET /v1/projects/{id}/analytics` or MCP `get_project_analytics`. If off, response has `enabled: false`. - Prefetch/prerender and known crawlers are skipped. Included on every plan (not metered). ## Core loop 1. `POST /v1/projects` → `{ project: { id, suffix, url, … }, url }` — project `status` is lifecycle (`active`), **not** deploy state 2. **One HTML file:** `POST /v1/publish-html` `{ "html": "…", "title": "…" }` (or MCP `publish_html`). Creates a project if `projectId` is omitted, writes `/index.html`, deploys. Then poll as in step 5. CLI: `npx novence deploy report.html`. Re-call with the same `projectId` to replace the page. Multi-file sites skip this and use steps 3–4. 3. Upload files (confirm is required; safe to retry): - Batch (preferred): `POST …/uploads/batch` → PUT each → `POST …/uploads/confirm-batch` - `confirm-batch` 200 body: `{ "files": [ { id, path, s3Key, sizeBytes, contentType, … } ], "errors": [ { "path", "error" } ] }`. `errors` is always an array (empty on full success). Resume by retrying failed paths only. - Single: `POST …/uploads` → PUT → `POST …/uploads/confirm` → `{ "file": { … } }` - `contentType` optional — inferred from extension when omitted 4. `POST /v1/projects/{id}/deployments` → returns `phase`, `checksUrl`, `checksResults` when ready 5. **Poll** `GET /v1/projects/{id}/deployments/latest` until `deployment.status` is `live` or `failed` (do **not** poll project `status`) 6. Read checks: response field `checksResults` or `GET /v1/projects/{id}/checks`. If `skipped: true`, quality gates did **not** run — `passed` is `null` (do not treat as green). Unverified accounts always skip. 7. Open `https://{suffix}.novence.ai/` (also returned as `project.url`) ## Uploads & video - Allowlist includes HTML/CSS/JS, images, fonts, and **Pro/Scale video**: `.mp4`, `.webm`, `.mov` - **Free / unverified:** video rejected; max **10 MB**/file - **Pro:** max **50 MB**/file · **Scale:** max **100 MB**/file - Prefer H.264 MP4 with faststart. Compress before upload: ```bash ffmpeg -i in.mov -an -vf "scale='min(1920,iw)':-2" -c:v libx264 -pix_fmt yuv420p -movflags +faststart -crf 26 out.mp4 ``` - Bandwidth is metered from edge bytes served (cache hits count). Free hard-blocks past quota (HTTP 402 on the live site); Pro/Scale soft overage **$0.08/GB** on the Stripe invoice. ## robots.txt `{suffix}.novence.ai` and `api.novence.ai` send `X-Robots-Tag: noindex, nofollow` (share/control-plane URLs — they do not rank). Tenant sitemaps on platform hosts are ignored. On a **custom domain**, uploaded `/robots.txt` is authoritative; Novence does not inject Cloudflare managed AI-crawler blocks. ## Custom domains Verified Free includes **1** domain; Pro/Scale include more (soft overage **$1**/domain-mo). `POST /v1/projects/{id}/domains` with hostname. Required DNS: 1. CNAME `www` → `fallback.novence.ai` 2. Registrar URL redirect apex → `https://www.{domain}/` ## Forms (optional) Contact/lead forms are **optional**. Choose one: ### Novence Forms 1. `POST /v1/projects/{id}/forms` `{ "name", "fields": [{ "name", "type", "required"? }] }` (email must be verified) 2. Point the site form at same-origin `POST /__forms/{formId}` **or** `POST https://api.novence.ai/v1/public/forms/{formId}/submissions` (JSON or urlencoded) 3. Include honeypot field `_gotcha` (hidden). Submissions stored + emailed to `notifyEmail` (default account email) 4. List: `GET …/forms/{formId}/submissions` (also in local console-kit project view) 5. Quotas: Free **50**/mo (hard); Pro **2,000** / Scale **20,000** included; Pro/Scale soft overage **$0.005**/submission ### BYO (Formspree, Web3forms, custom) Wire `
` (or similar) in static HTML. Novence only hosts the page — no platform submissions or form quota. ## Widgets and owner data (optional) Static sites can still be useful business sites. Two patterns work today — **no platform plugin**: ### Third-party widgets Paste a script or iframe in HTML (Cal.com, Snipcart, Shopify Buy Button, Stripe Payment Links, GA, Formspree). Novence serves HTML as-is and does **not** strip tags. CSP is report-only, so CDN widgets load. Never put `nv_` keys in the page. Public widget keys are fine. ### Baked-in data files Upload `/data/{collection}.json` (`.json` is allowlisted). Page JS fetches it same-origin: ```html ``` Use for hours, menus, team, services, FAQ, inventory lists. Free: update that file and deploy. Pro/Scale: `PUT /v1/projects/{id}/data/{name}` or MCP `put_site_data` writes it live (keep the file in the project). Do not store secrets — the URL is public. Bookings/payments: BYO widget. Contact leads: Novence Forms. Private CRM / PHP plugins / secrets in the browser: out of scope. Product page: https://novence.ai/site-data ## Billing - Quotas: `GET /v1/billing/quotas` or `GET /v1/account` - Checkout: `POST /v1/billing/checkout` `{ "plan": "pro"|"scale" }` - Portal: `POST /v1/billing/portal` - MPP: `GET|POST /v1/billing/mpp` → HTTP 402 SPT; retry with `Authorization: Payment …` ### Plans - **Unverified** (bootstrap before email OTP — **not** Free): 1 project, **50 MB** storage, **0.5 GB** bandwidth/mo, **3** deploys/mo, **0** check minutes (deploys skip Lighthouse/axe and still publish), **0** custom domains, **0** form submissions, no video, 10 MB/file. Hard-block (HTTP 402). Account deleted after **30 days** unless verified. `GET /v1/billing/quotas` returns these caps until `emailVerified` is true. - Free: $0/mo — 1 project, 1 GB storage, 10 GB bandwidth/mo (hard-block), 20 deploys/mo, 30 check minutes/mo, **1 custom domain**, **50 form submissions/mo** (after email verify). **No video uploads.** Other overages blocked (HTTP 402). - Pro: $29/mo — 20 projects, 50 GB storage, 200 GB bandwidth/mo, 2,000 deploys/mo, 4,000 check minutes/mo, 10 custom domains, 2,000 form submissions/mo. Video up to **50 MB**/file (`.mp4` `.webm` `.mov`). - Scale: $149/mo — 125 projects, 250 GB storage, 1.5 TB bandwidth/mo, 20,000 deploys/mo, 40,000 check minutes/mo, 100 custom domains, 20,000 form submissions/mo. Video up to **100 MB**/file. ### Overage rates (Pro / Scale only) | Meter | Unit | Price | | --- | --- | --- | | Storage | GB-month | $0.05 | | Bandwidth | GB | $0.08 | | Deploys | deploy | $0.05 | | Check minutes | minute | $0.04 | | Custom domains | domain-month | $1.00 | | Form submissions | submission | $0.005 | ## Surfaces - REST `/v1` (JSON errors on all paths) - GraphQL `/graphql` - MCP `/mcp` — connect without a key; `bootstrap(email)` then authenticated tools. Guide: https://novence.ai/mcp - OpenAPI https://novence.ai/openapi.yaml - Docs https://novence.ai/docs - Framework how-tos https://novence.ai/guides (Next.js, Astro, Gatsby, Nuxt, Eleventy, Hugo, HTML, Vite, SvelteKit, Jekyll, VitePress, Remix — static export only; Nuxt `.output/public`, VitePress `.vitepress/dist`, Remix `build/client` are not auto-detected) - Agent how-tos: Claude Code https://novence.ai/guides/claude-code · Cursor https://novence.ai/guides/cursor · Grok Build https://novence.ai/guides/grok-build - Analytics https://novence.ai/analytics - Widgets and data https://novence.ai/site-data - Pricing https://novence.ai/pricing - Examples playbook https://novence.ai/examples - Compare https://novence.ai/compare - Health https://api.novence.ai/health ## API keys `GET /v1/api-keys` — list keys on the account. Never returns the key or its hash; `keyPrefix` (first 12 chars) identifies a row. Each entry has `scope` (`account` when `projectId` is null, else `project`) and `current`, true for the key authenticating the request. Query: `?projectId=` to filter, `?includeRevoked=true` to include revoked rows (hidden by default — rows are never deleted). Readable with a `mgmt_` session (`account:read`) too. `DELETE /v1/api-keys/{id}` — idempotent. Returns **409** when `id` is the key authenticating the request; pass `?force=true` to override, after which recovery needs `POST /v1/auth/reissue-key` with an email OTP. Requires an `nv_` key — management sessions cannot revoke. SDKs: `client.apiKeys.list()` / `client.apiKeys.revoke(id, { force })` in TypeScript, `list_api_keys()` / `revoke_api_key(id, force=)` in Python. ## CLI `npx novence deploy ./dist` — uploads a directory, runs checks, publishes, and prints the live URL as the last line on stdout (progress goes to stderr, so `URL=$(npx novence deploy ./dist)` captures just the URL). - Install: `npx novence` (no install) or `npm install -g novence` - `novence deploy [dir|file.html]` — auto-detects dist, build, out, public, _site; or publish one HTML file - `novence open [project]` — open the live URL - `novence checks [project]` — Lighthouse / axe / link results for the last deploy - `novence domains add ` — attach a custom domain, prints the DNS records - `novence domains status` — custom domain state - `novence keys list` — API keys (marks the one in use; never prints secrets) - `novence keys revoke ` — revoke a key (`--force` for the key in use) - `novence projects` — list projects and URLs - `novence login` — sign in, verify email, or `--recover` a lost key - `novence claim` — attach an email to an anonymous deploy - `novence whoami` — plan, verification, usage vs quota - Unknown flags are rejected and the valid ones listed — typos fail loudly - Guide: https://novence.ai/cli - `--json` — machine-readable envelope, implies `--no-input`; exits non-zero on deploy failure. Use with `NOVENCE_API_KEY` in CI. - Key lookup order: `NOVENCE_API_KEY`, `./.novence-key`, `~/.novence/credentials` ## SDKs Guide: https://novence.ai/sdk - TypeScript: `npm install @novence/sdk` — dual ESM/CommonJS, fully typed responses (`Project`, `Deployment`, `ChecksResults`, `Form`, `Quotas`, …). Defaults to https://api.novence.ai; override with `NOVENCE_BASE_URL`. Prefer `isNovenceClient(x)` over `instanceof Novence`. - Python: `pip install novence` — Python 3.10+, standard library only. `wait_for_deployment(project_id)` blocks until live; `upload_dir(project_id, dir)` walks a directory; `publish_html(html, title=)` writes index.html and deploys. Same base-URL rules as the TypeScript SDK.