# 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 `