Documents API guide

Create a document, embed the editor in your own page, change it with AI, then publish and share it, all over the REST API. Each step uses what the previous one returned, and the editor you embed in step 2 shows every change as it happens.

Click Run to call the API live with your signed-in session, or copy the curl snippets, which carry your API token and the ids this guide creates. The complete endpoint list is in the REST API docs.

1 Create POST /docs/create → poll GET /workflows/runs/:runId 2 Embed <iframe src="/p/_iframe/:projectId/?embed=native&features=…"> 3 Update POST /jobs/chat { projectId } → poll GET /jobs/:jobId/result 4 Publish POST …/commit → POST …/publish { slug } → POST …/set-visibility

Setup

Run uses your FluidDocs session (credentials: include); if you are not signed in it sends you to sign in and back here. Scripts, servers and CI use an API token instead (Authorization: Bearer lit_live_…). This page loads yours and puts it in every curl snippet. Every endpoint accepts either.

Keep the token on your server: it acts as you. The embedded editor in step 2 never uses it; it runs on the session of whoever is viewing the page.

1Create a document

One endpoint creates every document type. Send the type and a description of what you want; the document exists as soon as the call returns (run.projectId), and AI fills it in the background. The response is a run, which you poll until it is done.

Send an Idempotency-Key header so a retried request (a timeout, a crashed worker) never creates a second document: the same key returns the same run with 200.

POST /api/v1/docs/create

A page or a text document takes one to three minutes; a deck a few minutes. Run keeps polling the run for you and shows its step and run.result as they change. The second button repeats the request with the same Idempotency-Key: you get the same runId back, and no second document.

Check the run

Poll every couple of seconds until run.status is done, error or cancelled. run.currentStep names the stage in progress, and run.result carries what the stages report so far (a deck's slideCount counts up as slides are saved). Prefer a push? GET …/stream sends the same run as server-sent events.

GET /api/v1/workflows/runs/:runId

Needs a runId: run step 1 first, or paste one below.

In a script:
while :; do
  RUN=$(curl -s "$BASE/api/v1/workflows/runs/$RUN_ID" -H "Authorization: Bearer $TOKEN")
  STATUS=$(echo "$RUN" | jq -r .run.status)
  case "$STATUS" in done|error|cancelled) break;; esac
  sleep 2
done
Or follow it live: GET …/stream sends server-sent events: run whenever the run changes (its steps, and the plan's sections once planned), log for each progress line of a step, and end when it finishes. The panel below is built from this stream.
curl -N '$BASE/api/v1/workflows/runs/$RUN_ID/stream' -H 'Authorization: Bearer $TOKEN'
Starting…
Sections
  • Planning the document…
Log

    2Embed the editor

    Put the document inside your own product with one <iframe> pointing at /p/_iframe/:projectId/?embed=native. This is a native embed: the document runs its own editing UI (a text document's toolbar and A4 pages, a spreadsheet's grid, a deck's slide bar), with no FluidDocs app around it. Editing, undo/redo and saving are always there; ?features= adds Edit with AI (edit-ai) and Export PDF (export). Changes made through the API show up in it live.

    The editor runs as the person viewing it. Here the iframe uses your FluidDocs session, because this guide runs on FluidDocs and the document is yours. On your own site, the session doesn't reach a cross-site iframe reliably, so your server adds a short-lived delegate token: ?del=lit_del_… from POST /docs/projects/:id/delegate-ownership. Never put your API token in the iframe. Only allowed sites can frame the editor; see Embedding options.
    IFRAME /p/_iframe/:projectId/?embed=native

    Needs a projectId: wait for step 1 to finish, or paste one below.

    Embed loads the editor in the panel below. Click into the document and type: your edits save to its draft. We publish them in step 4. Steps 3 and 5 reload it when they change the document.

    Your document not created yet Create a document in step 1, then click Embed. Open ↗
    Click Embed above to load the editor here.

    3Update it with AI

    The builder chat edits a document from a plain-language request: the same agent as Edit with AI in the editor. Send the projectId and a message; you get a jobId back at once, then poll the job until it is done. Watch the editor above: Run reloads it when the job finishes.

    POST /api/v1/jobs/chat

    Needs a projectId: run step 1 first, or paste one below.

    A new chat job for the same document cancels the one still running. To continue a conversation, send the earlier turns in history.

    Poll the job, or stream it live (server-sent events):
    curl -s '$BASE/api/v1/jobs/$JOB_ID/result' -H 'Authorization: Bearer $TOKEN'
    curl -N '$BASE/api/v1/jobs/$JOB_ID/stream?afterSeq=-1' -H 'Authorization: Bearer $TOKEN'
    Every document type, open or not. Text documents, spreadsheets and notes are changed with their own operations on the server, so the chat API edits them whether or not anyone has them open; the embedded editor shows each change as it lands. You can call those operations yourself too: see Drafts & other ways to edit.
    Changes land in the draft. AI edits and edits made in the editor are saved to the document's draft. Whoever opens the document in the editor sees them right away; people opening its public link keep seeing the last committed version until you commit, in step 4.

    4Publish & share

    A new document is private, and only you can open it. Sharing it takes three calls: commit the draft so it becomes the live version, give the document a public address (a slug), and choose who may open that address.

    4.1 Commit the draft

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

    Needs a projectId from step 1.

    Promotes the draft to the live version; the editor's DRAFT badge goes away. Commit again after every later change you want people to see.

    4.2 Publish at a slug

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

    Needs a projectId from step 1.

    Returns the public url. Store it as returned rather than building it yourself: its shape depends on your plan and domain, and the slug may be cleaned up. A slug already in use returns 409.

    4.3 Choose who can open it

    unlisted is the usual choice for sharing: anyone with the returned shareUrl can open the document, it isn't listed or indexed, and switching away from unlisted turns the link off at once. public opens the plain url to everyone.

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

    Needs a projectId from step 1.

    4.4 Read back the links

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

    Needs a projectId from step 1.

    The document's current state: visibility, url, shareUrl (when unlisted) and hasPendingDraft (uncommitted changes waiting).

    5Download a PDF

    A PDF export is a job, like the AI edit in step 3: start it, poll it until it is done, then download its file. No AI runs and it costs no credits. You export the version you can edit: the draft, with any changes not yet committed. Someone who can only read the document exports the published one.

    Text documents print on A4 sheets, page by page as in the editor; pages and spreadsheets print the way Chrome prints them. Decks have their own route, /jobs/export-deck-pdf, with one 1440×810 page per slide; the guide picks it when your document is a deck. It is the same export as the editor's Export PDF button (the export embed feature).

    POST /api/v1/jobs/export-pdf

    Needs a projectId from step 1.

    Run starts the job, polls GET /jobs/:jobId every couple of seconds, then downloads GET /jobs/:jobId/artifact (application/pdf). A document takes 10–30 seconds.

    Then poll the job and download the file:
    curl -s '$BASE/api/v1/jobs/$PDF_JOB_ID' -H 'Authorization: Bearer $TOKEN' | jq .status
    curl -s '$BASE/api/v1/jobs/$PDF_JOB_ID/artifact' -H 'Authorization: Bearer $TOKEN' -o document.pdf

    That's the whole loop. From here, repeat steps 3 and 4.1 for each change: the slug and the share link stay the same and show the newest committed version.

    Reference

    The details behind the steps above, and the calls the guide didn't need. The snippets use the ids from your run of the guide. Base path: /api/v1. Every endpoint accepts a session or Authorization: Bearer lit_live_….

    Creation runs

    CallWhat it does
    POST /docs/createCreate a document of any type. 201 { run }; with a repeated Idempotency-Key (up to 200 characters), 200 and the original run.
    GET /workflows/runs/:runIdThe run: status (running, done, error, cancelled), currentStep, steps, result, projectId, error.
    GET /workflows/runs/:runId/streamThe same run as server-sent events, until it finishes.
    POST /workflows/runs/:runId/cancelStop a running run. The document stays as far as it got.
    POST /workflows/runs/:runId/retryResume a failed run (status: "error") on the same document, from the step that failed. Finished work is not redone or charged again.
    POST /workflows/runs/:runId/restartRun a stopped run again (failed, cancelled or done), from the start or from { "fromStep": "…" }. A running run must be cancelled first.
    GET /workflows/runs?projectId=…The runs of one document. Without projectId: your own runs, newest first (status, workflow, page, limit).
    GET /workflowsEvery workflow with its documentType and input JSON Schema.

    Document types & inputs

    Every type takes description (3–2000 characters), name (kept as the document's name; otherwise it is named from the plan), folderId, and blank: true (or the description "Empty doc") for the type's empty document, with no AI.

    typeCreatesExtra inputrun.result
    text-documentA paginated A4 document with headings, tables and imagesimages: "stock" or "both" (stock, then AI-generated){ sectionCount, pageCount }
    pageA web page in sections——
    deckA slide decksee below{ templateReference, slideCount }
    spreadsheet-documentA spreadsheet with sheets and formulas—{ sheetCount }
    notes-appA notes notebook—{ noteCount }

    Deck input:

    FieldDescription
    outlineThe slides in order, [{ title, body? }] (1–40). With an outline, description is optional and no outline is written for you.
    templateReferenceA design family to use, or "custom" (default) for a design composed for this deck.
    stylePresetA colour palette for a custom design. Not combinable with a design family.
    creativeBriefArt direction for every slide (up to 2000 characters).
    tonecasual, professional, funny, educational or sales_pitch.
    detailconcise, balanced or text-heavy.

    Read, rename, delete

    CallWhat it does
    GET /docs?flat=trueYour documents (name, folderId, page, limit up to 100, sort=updatedAt|name). GET /docs/org lists your organization's.
    GET /docs/projects/:projectIdOne document: name, type, visibility, perms, url, shareUrl, hasPendingDraft, dates.
    PATCH /docs/projects/:projectIdRename or move: { name?, folderId? } (folderId: null = top level).
    POST /docs/projects/:projectId/copyDuplicate a document ({ name }); add remix with a prompt to have AI rewrite the copy.
    GET /docs/projects/:projectId/thumbnailA JPEG of the first screen (?source=draft|published).
    DELETE /docs/projects/:projectIdDeletes the document and all its files. Cannot be undone. Its public and share links stop working.

    Remove the document this guide created:

    Drafts & other ways to edit

    CallWhat it does
    POST /docs/projects/:id/commitMake the draft the live version.
    POST /docs/projects/:id/discardThrow the draft away and go back to the live version.
    POST /docs/projects/:id/draft?path=…Write a whole file to the draft (raw body; &autocommit=true commits too).
    POST /jobs/chatBuilder chat, as in step 3. model: "flash" for a faster, cheaper model.
    POST /jobs/agent-taskOne-shot agent run with a prompt; readOnly: true to only read and answer.
    POST /jobs/:jobId/cancelStop a running job.
    POST /docs/projects/:id/ops/applyPrecise edits to single elements, without AI.
    GET /docs/projects/:id/ops/actionsA text document's, spreadsheet's or notebook's own operations (client "server"): text_insert_blocks, sheet_write_range, notes_create… with their input schemas.
    POST /docs/projects/:id/ops/actions/:nameRun one of them, without AI and without an editor open: { "input": { … } }. The change shows up live in open editors.

    Examples for each are in the REST API docs: write a file, partial updates, agent task.

    Visibility & permissions

    VisibilityWho can open itLink to share
    privateOnly younone
    orgSigned-in members of your organizationurl
    unlistedAnyone with the link; not indexedshareUrl (includes ?t=…; the bare url returns 403)
    publicAnyoneurl

    Embedding options

    Two ways to embed a document. The guide uses the first.

    EmbedWhat the viewer gets
    /p/_iframe/:id/?embed=native&features=edit-ai|exportNative: the document's own editing UI in one iframe. features: edit-ai (the builder chat), export (Export PDF). No theme or toolbar messages.
    /app/embed/:id?features=a|b|c&theme=light|dark&edit-bar=on|offWrapper: the FluidDocs app's editor without its logo and breadcrumb, with the features below and postMessage control of the toolbar.
    Wrapper featuresAdds
    edit-aiThe "Edit with AI" chat
    jobsRunning AI jobs and their history
    exportExport to PDF / HTML
    publishPublish, share and discard-draft controls
    commentsComments
    codeSource code editor
    filesThe document's files
    dbThe document's data collection
    fluidifyApply libraries to the document
    block-kit, insert-blocksInsert blocks into pages and slides
    Wrapper message to the iframeEffect
    { _fdEmbed: true, type: "setTheme", theme: "dark" }Switch the toolbar theme (light / dark).
    { _fdEmbed: true, type: "setEditBar", editBar: "off" }Hide or show the toolbar (on / off).

    MCP tools

    The FluidDocs MCP server exposes the same calls to agents:

    ToolSame as
    create_documentPOST /docs/create (type, input, idempotencyKey)
    get_workflow_runGET /workflows/runs/:runId

    Errors

    StatusWhen
    400Missing or unknown type (details.types lists the valid ones), or invalid input (details has the problems), or a bad folderId.
    401No session or token, or an expired one.
    402Your plan's AI credits are used up.
    403Not allowed on this document (or a lit_del_ token on /docs/create).
    404No such document, run or job, or not yours.
    409The slug is taken, or the Idempotency-Key is being used by another request at the same moment.