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
/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.
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.
/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).
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.
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.
/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.
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.
curl -s '$BASE/api/v1/jobs/JOB_ID/result' -H 'Authorization: Bearer $TOKEN'
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.
/api/v1/docs/projects/:projectId
Pass templateSettings: null to remove template status. Response is the updated document.
List org templates
/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.
/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.
/api/v1/jobs/chat
Ask the builder to edit your document. Verify with GET .../draft afterward.
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.
/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.
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
/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.
/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.
/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.
/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.
- Request body:
{ "patch": "..." }onPATCH .../draft/lines. The patch string contains one or more operations, separated by newlines. - Operation syntax:
LINE[op:'OP']CONTENT, orSTART-END[op:'OP']CONTENTfor ranges. Valid ops:replace,insert-before,insert-after,delete. - Line numbers: always refer to the original document before any op in the patch runs. You do not renumber after each edit.
- Single-line replace:
5[op:'replace'] <h1>Updated</h1>replaces line 5 only. - Insert:
6[op:'insert-after'] <p>New</p>adds content after line 6;insert-beforeinserts before the given line. - Delete:
10-12[op:'delete']removes lines 10 through 12 (inclusive). A single line is4[op:'delete']. - Multiline content: use heredoc markers on the same line as the op, then content, then a closing line with
>>>:12[op:'replace']<<< ... >>>. - Workflow: call
GET .../draftfirst to inspect stored HTML and pick line numbers. Out-of-range or malformed patches return 422. - Ops documents: if the document is in ops mode, a line patch re-baselines ops state (fresh
data-fe-ids). Preferops/applyfor targeted node edits on ops-enabled documents.
5[op:'replace'] <h1>Hello World</h1> 6[op:'insert-after'] <p>New paragraph</p> 10-12[op:'delete']
5-8[op:'replace']<<<
<section class="hero">
<h1>Replaced block</h1>
</section>
>>>
/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.
{
"path": "index.html",
"find": "Hello from the API",
"replace": "Hi from patch"
}
/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
/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.
/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": [ ... ] }.
data-fe-id: stable node ID on each editable block (e.g.fe-3,fe-12). The server assigns these when a document first enters ops mode (firstGET /draftwith ops enabled, or anyPOST .../ops/apply). IDs are monotonic per document and survive edits. Use them in ops, not CSS selectors.data-fe-run/<edit-run>: wrapper around an inline text neighborhood inside a block. Ops likesetRunHtmltarget the run'sdata-fe-id; inner tags (<strong>,<a>, etc.) are opaque HTML.- Blocks vs runs: structural containers (sections, headings, divs) are blocks; editable inline text regions are runs. Each op names exactly one
nodeId. - API-friendly ops: send
kind,nodeId, and payload fields only. The server fills in versioning and rebases against the current tree. Browser editors may sendbaseContentVersion, but API callers do not need it. - Confirmed ops: the server assigns a monotonic
seqper op and streams confirmations to open editors (no full reload).
/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
/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
/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.
shareUrl (includes ?t=…)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.
| Visibility | Who can open the URL | Share 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.
/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.
/p/s/<projectId>?t=….
Published unlisted → /<slug>?t=… (or /p/<slug>?t=… for normal accounts).
/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>).
/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.
/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.
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.
/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.
/api/v1/docs/analytics/events
Query visit stats
Aggregated main-page visit totals for a document (section / custom events are excluded from these counts).
/api/v1/docs/projects/:projectId/analytics
Query visitors
Recent unique sessions for a document, with geo and optional email when captured.
/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.
/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).
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.
/api/v1/jobs/agent-task
Example: extract page metadata as JSON without write access.
Run polls GET /jobs/:jobId/result until the job completes.
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.
/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.
/p/_view/:projectId/jobs/chat
Run uses your browser session cookie, same as a visitor on the published page.
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.
/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.