Getting Started API

A hands-on tour of the FluidDocs REST API. Work through each section in order: spin up documents with AI, upload your own HTML, then explore the other AI endpoints. Click Run to try anything live (sign in when prompted), or copy the curl snippets for scripts and CI. Your API token is filled in automatically.

For the browser SDK (window.__fluiddocs) see the UI SDK docs. For the terminal client see the CLI guide (fld).

Setup

The Run buttons call the API using your signed-in FluidDocs session (credentials: include). If you are not signed in, Run sends you through sign-up / sign-in and returns you here. For scripts, CLI, and CI you use an API token instead. Tokens start with lit_live_; this page loads yours automatically (from the same cache the dashboard uses via Get Token, or by minting one via POST /api/v1/tokens) and drops it into every curl snippet.

Run uses your signed-in session (credentials: include). Not signed in? Run opens sign-up / sign-in, then returns you to this page. The API token above is for curl, CLI, and CI only.

Verify token

GET /api/v1/me

Verify your token works. Returns your URL prefix, plan, and org info.

Create and update documents

Use the builder chat to create any HTML document from the dashboard, run a dedicated deck-build job when you need a presentation deck, copy and personalize existing documents, or have the agent tweak a document on your behalf. Each step below returns a projectId you can reuse in the next one.

Step 1 Create a document → POST /jobs/chat (dashboard context) → poll /jobs/:jobId/result Step 2 Or build a deck → POST /jobs/deck-build → poll /jobs/:jobId/result Step 3 Save as org template → PATCH .../projects/:id (templateSettings) Step 4 Or start from a template → GET /docs/templates?scope=org → POST .../copy Step 5 Tweak with AI → POST /jobs/chat (with projectId) or POST /jobs/agent-task

Document creation

The unified builder is POST /api/v1/jobs/chat. Omit projectId (or pass "dashboard") to run in dashboard context — the same agent as the dashboard AI assistant. Describe the site or page you want; the agent writes files and deploys a new private document. Poll until status is done; the result includes the new projectId.

POST /api/v1/jobs/chat

No projectId in the body — dashboard mode. The agent creates a new document and deploys HTML. Can take a minute or two. When done, use Open document in the response (or parse projectId from the result text).

Dashboard context (default when projectId is omitted):
{ "message": "Create a landing page for …" }
With an open document, pass projectId to edit that document instead — see Update with builder chat.
Poll when done:
curl -s '$BASE/api/v1/jobs/JOB_ID/result' -H 'Authorization: Bearer $TOKEN'

Deck from scratch

Describe the deck you want and we spin up a document plus a background build job. Pass autoconfirm: true for fully automated API flows (skips the interactive outline step). You can also attach branding files (logos, screenshots, PDFs) as base64 in the attachments array. The build agent reads them from its workspace and weaves them into the deck. Up to 5 files, 10 MB each.

POST /api/v1/jobs/deck-build

Creates a placeholder document, starts a deck-build job, and polls until the agent deploys index.html. Can take a few minutes. When done, use Open deck in the response to preview the deck in a new tab.

Attachment shape (send raw base64 in data, or a data:image/png;base64,… data URL):
{
  "attachments": [{
    "name": "logo.png",
    "type": "image",
    "mimeType": "image/png",
    "data": "<base64 bytes>"
  }]
}
In your shell: base64 -i logo.png (macOS/Linux) or pipe into the JSON body.
Poll when done:
curl -s '$BASE/api/v1/jobs/JOB_ID/result' -H 'Authorization: Bearer $TOKEN'
Tip: After the job finishes, the projectId is copied into every field below automatically.

Templates

Org templates are reusable documents shared with everyone in your organization. After you create a document, mark it as a template so teammates can copy it from the gallery. To start from an existing template, list org templates and copy one into your workspace.

Mark as template

Turn any document you can edit into an org template. Visibility is set to org automatically.

PATCH /api/v1/docs/projects/:projectId

Pass templateSettings: null to remove template status. Response is the updated document.

List org templates

GET /api/v1/docs/templates?scope=org

Returns org templates for your organization with projectId, name, description, and preview URL. Use an ID in the copy step below.

Copy

Copy duplicates any document you can access—your own documents, org-shared documents, public or unlisted documents, and templates. The source does not need to be a template. Optionally pass a prompt to launch an AI job that personalizes the copy for your use case (consumes credits). Without a prompt, you get an instant static duplicate.

POST /api/v1/docs/projects/:projectId/copy

Returns { projectId } immediately. With prompt, also returns jobId; poll GET /jobs/:jobId/result until the agent finishes. Use Open document in the response to preview the copy in a new tab.

Update with builder chat

Same agent as the dashboard builder: multi-turn, full write access. Point it at your projectId and describe the change. Run polls GET /jobs/:jobId/result when the job completes.

POST /api/v1/jobs/chat

Ask the builder to edit your document. Verify with GET .../draft afterward.

Stream live (SSE):
curl -N '$BASE/api/v1/jobs/JOB_ID/stream?afterSeq=-1' \
  -H 'Authorization: Bearer $TOKEN'

Update with agent task (one-shot)

Fire a single agent run with the builder toolset (read and write files). Handy for scripted edits: pass a clear prompt and poll for the result.

POST /api/v1/jobs/agent-task

Example: tweak the main headline in one shot. The agent can write files; set readOnly: true only when you want analysis without edits.

Upload your own documents

Already have HTML from Figma, Cursor, or your favorite editor? Upload it here and patch it with the REST API. Zip deploy bootstraps a document; draft, commit, and partial-update endpoints let you refine without re-uploading the whole file.

Create POST /api/v1/deploy (name + base64 zip) Update POST .../draft?path=… (raw file body) Surgical PATCH .../draft/lines · POST /fs/.../patch · POST .../ops/apply
When to use which: POST /deploy for a new document or full replacement. POST /draft for one file on an existing document. Partial updates when you only need a substring swap or a single DOM node changed.

Zip deploy

Create a new document or replace an entire document from a base64-encoded zip. Returns projectId.

Create a new document

POST /api/v1/deploy

Deploy a minimal HTML page as a new document. The zip contains <h1>Hello from the API</h1>.

Redeploy an existing document

Replace all files by passing existingProjectId instead of name.

POST /api/v1/deploy (redeploy)

Redeploys a zip containing <h1>Redeployed HTML</h1>.

Write a file

The primary update method. Send the raw file body for any document path. Defaults to index.html; use ?path= for CSS, JS, etc. Add ?autocommit=true to publish immediately.

POST /api/v1/docs/projects/:id/draft

Try path=styles.css with CSS content. Response includes path and committed.

Commit draft

When autocommit is off, changes sit in the draft working copy until you commit. Commit promotes all draft files to live.

POST /api/v1/docs/projects/:id/commit

Partial updates

When you don't need to replace a whole file, use targeted edits: line-number patches, find/replace on raw bytes, or node ops on the DOM tree.

Line-number patch

Apply surgical edits to the stored draft HTML by line number. Line numbers are 0-based and refer to the document exactly as stored (split on newlines). This is the same compact patch format LLM agents use for scripted edits.

Line patch protocol: short guide
Example patch (multiple ops in one string):
5[op:'replace']  <h1>Hello World</h1>
6[op:'insert-after']  <p>New paragraph</p>
10-12[op:'delete']
Multiline range replace:
5-8[op:'replace']<<<
  <section class="hero">
    <h1>Replaced block</h1>
  </section>
>>>
PATCH /api/v1/docs/projects/:id/draft/lines

Replaces line 0 (the whole single-line demo document). For multiline drafts, split the GET draft response on newlines to pick line numbers, then compose a patch using the syntax above.

Find/replace & append

Replace a substring or append bytes inside an existing file. Content is base64-encoded in JSON (max 200 KB).

Patch (find & replace)

Both find and replace are required and must be base64-encoded UTF-8 strings.

Request body (values shown decoded for clarity; send base64 in the API):
{
  "path": "index.html",
  "find": "Hello from the API",
  "replace": "Hi from patch"
}
POST /api/v1/fs/:projectId/patch

Finds the first occurrence of find in the file and substitutes replace. Both fields are sent as base64 in JSON.

Append to a file

POST /api/v1/fs/:projectId/append

Node ops

Target individual DOM nodes by stable ID. Read the draft to discover data-fe-id values, then apply ops via POST .../ops/apply. Enables ops mode on first call (stamps IDs on editable elements). No baseSeq or baseContentVersion required: the server rebases ops automatically. Prefer /ops/apply over POST .../ops for scripts and agents.

Read draft

Fetch the current draft HTML before crafting ops. Once a document enters ops mode, every editable HTML element carries a stable data-fe-id attribute (for example fe-3, fe-12). Use these IDs in ops to update individual nodes without rewriting the whole file.

GET /api/v1/docs/projects/:id/draft

Returns draft HTML with data-fe-id on each editable element when in ops mode.

OPS apply

Apply one or more editor ops against the server's canonical DOM tree. The request body is simply { "ops": [ ... ] }.

Ops protocol: short guide
POST /api/v1/docs/projects/:id/ops/apply

Run enables ops mode if needed, then applies setRunHtml to nodeId. Leave nodeId blank to use the first data-fe-id from GET draft.

List documents

Look up projectIds for the files you just uploaded. Publishing and visibility are covered in Permissions & visibility.

List all documents

GET /api/v1/docs

List your documents. Use flat=true for a flat project list (default: direct children only). Add rec=true to include projects in nested subfolders. Filter with name (contains, case-insensitive) or nameMatch=exact. Scope to a folder with folderId (Mongo id or root).

Get one document

GET /api/v1/docs/projects/:projectId

Full details: name, visibility, published slug, url, and shareUrl when unlisted.

Permissions & visibility

Deploy creates a private, unpublished project. The owner can always open it via /app/preview/:projectId. Making it reachable for others is two separate steps — publish a slug, then choose who can open the URL.

Step 1 Publish a slug → POST /docs/projects/:id/publish Step 2 Set who can access → POST /docs/projects/:id/set-visibility Unlisted Share the returned shareUrl (includes ?t=…)
Deploy does not set slug or visibility. Fields like slug / visibility on POST /api/v1/deploy are ignored. Always use the endpoints below after you have a projectId. General PATCH /docs/projects/:id also ignores visibility — use set-visibility only.
VisibilityWho can open the URLShare link?
public Anyone (may be indexed) No special link — use the published url
unlisted Anyone with the signed share link Yes — shareUrl with ?t=<token>
org Signed-in members of your organization No
private Owner only (preview URL) No

Set visibility

Change who can access the document. Switching to unlisted creates (or keeps) a shareToken and returns shareUrl. Switching away from unlisted clears the token — old share links stop working immediately.

POST /api/v1/docs/projects/:id/set-visibility

Prefer unlisted first so the response shows a shareUrl you can copy. Works even before the document has a published slug (share links route via /p/s/:projectId?t=…).

Unlisted share link

Distribute the full shareUrl from set-visibility or GET /docs/projects/:id — including the ?t= query param. Sharing only the bare path returns 403. Unlisted responses also send X-Robots-Tag: noindex.

URL shapes: Unpublished unlisted → /p/s/<projectId>?t=…. Published unlisted → /<slug>?t=… (or /p/<slug>?t=… for normal accounts).
GET /api/v1/docs/projects/:projectId

Read back visibility, url, and shareUrl after changing access.

Publish a slug

Assign a public path for the document. Until this succeeds, there is no slug URL — only the owner preview. Slugs must be unique per account prefix (super-admin pages live at /<slug>; everyone else at /p/<slug>).

POST /api/v1/docs/projects/:id/publish

Sets publishedSlug. Returns the public url (and shareUrl if the project is already unlisted). Returns 409 if the slug is taken.

Unpublish

Clear the published slug. The document stays in your library; visitors lose the public path. Visibility is unchanged — set private separately if you also want to revoke share access.

DELETE /api/v1/docs/projects/:id/publish

Analytics

Track how people use your documents, push your own events, and pull the data back through the API. Page opens are recorded automatically when someone loads a published or unlisted URL (owners are excluded). You can also push custom events yourself.

Push POST /api/v1/t (no auth) Query GET /docs/analytics/events — filter by eventType / subType / dates Stats Visit totals · Visitors · Viewer chats
Filtering is required for event queries. Activity volume can be large, so GET /docs/analytics/events always needs projectId plus at least one of eventType, subType, startDate, or endDate. Responses include dataRange for the filtered set (90-day retention).

Push events

Best-effort tracking endpoint. Returns 202 immediately. Use any eventType string (built-ins: resource_visit, cta_click, cta_email_capture), an optional subType label, and flat extra primitives.

POST /api/v1/t

No auth. projectId is preferred (resourceId still works). subType aliases subResource. Main visits (resource_visit with no subType) upsert per session; everything else inserts.

Query events

General-purpose query for activity you pushed (or that the viewer tracked). Returns full extra payloads, pagination, and a dataRange for the filtered result set.

GET /api/v1/docs/analytics/events

Query visit stats

Aggregated main-page visit totals for a document (section / custom events are excluded from these counts).

GET /api/v1/docs/projects/:projectId/analytics

Query visitors

Recent unique sessions for a document, with geo and optional email when captured.

GET /api/v1/docs/analytics/visitors

Query viewer chats

List Ask-AI conversations from document viewers (not builder chat). Same auth as the rest of the docs API. Use GET /viewer-chats/:jobId for a full transcript.

GET /api/v1/viewer-chats

Other AI endpoints

Beyond document creation and updates, FluidDocs exposes a few more AI surfaces: a read-only one-shot agent for extraction and analysis, plus visitor chat on published pages (with optional grounded RAG).

Analyze POST /jobs/agent-task (readOnly: true) → poll /result Ask visitors enable chat → POST /p/_view/:id/jobs/chat → poll visitor /result

One-shot agent (read-only)

Fire-and-forget agent for scripts and automation. With readOnly: true the agent gets the viewer toolset only (list, read, grep). It sees your owner draft but cannot write files. Perfect for extracting metadata or summarizing content.

POST /api/v1/jobs/agent-task

Example: extract page metadata as JSON without write access. Run polls GET /jobs/:jobId/result until the job completes.

Poll when done:
curl -s '$BASE/api/v1/jobs/JOB_ID/result' -H 'Authorization: Bearer $TOKEN'

Enable viewer chat

Viewer chat is disabled by default on new documents. Turn it on programmatically before visitors can use the chat widget on a published page. You can also configure labels, suggested questions, and other options in the dashboard Libraries panel.

PATCH /api/v1/docs/projects/:projectId

Sets libs["viewer-chat-settings"].enabled to true. Merges with any existing library config on the document.

Viewer chat (visitor Q&A)

Public endpoint on published documents (no API token). Visitors get a session cookie (_lt_sid). The agent is read-only and cannot edit the document. The document must be published and viewer chat must be enabled (see above).

Ungrounded (default)

Without indexing, the agent answers from the live page HTML and read-only file tools. Good for quick Q&A on what visitors can already see. Try it below before setting up grounded mode.

POST /p/_view/:projectId/jobs/chat

Run uses your browser session cookie, same as a visitor on the published page.

Poll visitor result:
curl -s '$BASE/p/_view/PROJECT_ID/jobs/JOB_ID/result'

Grounded viewer chat

Grounded mode uses a vector index of your document files so visitor questions are answered with retrieval-augmented generation (RAG) instead of only browsing files at question time. The flow is: enable viewer chat, publish, index content, turn on groundedAnswers, then visitors can query via the same chat endpoint.

Indexing

Indexing uploads document files to an OpenAI vector store and records vectorStoreId on the document. Run an index job after deploys or major content changes so grounded answers stay in sync. While indexing runs, the server sets indexingJobId on viewer-chat settings; when complete it stores lastIndexedAt and clears the in-flight job id.

POST /api/v1/jobs/viewer-chat-index

Returns jobId. When done, result includes vectorStoreId and fileCount.

After a successful index, enable grounded answers on the same document:

PATCH /api/v1/docs/projects/:projectId
{ "libs": { "viewer-chat-settings": { "enabled": true, "groundedAnswers": true } } }

With groundedAnswers: true and a completed index, use the same POST /p/_view/:projectId/jobs/chat endpoint above. Answers are RAG-backed from your vector store.