Edit Mode API
What this is
Four HTTP endpoints for managing draft documents through a web editor: open a draft, read a specific draft, save changes, and discard. All require a Firebase ID Token with manager or admin role.
Route prefix: POST /api/projects/:projectId/docs/edit
How it works
Edit Mode is the web portal’s in-browser editing surface. Drafts are created from live pages (clone) or from scratch. Only documents with visibility: "draft" can be edited or discarded — live documents are cloned on open.
The workflow:
- open — find or create a draft for a given slug + language. Returns the draft ID and full document plus the resolved template (for rendering metadata form fields).
- save — persist changes. Called on explicit save and auto-save. Merges metadata (fields not sent are preserved). New draft: pass
draftId: "new". - discard — permanently delete the draft and its version subcollection.
When to use it
- Building a web editing interface for ComStack documents
- Resuming an in-progress edit session for a known draft ID
- Auto-saving editor changes on a timer
- Discarding a draft that should not be published
Parameters / fields / inputs
POST /edit/open
| Field | Type | Required | Description |
|---|---|---|---|
slug | string | Yes | URL slug of the page to open. |
language | string | Yes | BCP-47 language code. |
Response:
| Field | Description |
|---|---|
draftId | Firestore doc ID of the draft. |
doc | Document — metadata, content, doc_template_id, language. |
template | Full template document — used to render metadata form fields. |
action | "existing_draft" or "cloned_from_live". |
POST /edit/save
| Field | Type | Required | Description |
|---|---|---|---|
draftId | string | Yes | Draft ID. Use "new" to create a brand-new draft. |
metadata | object | Yes | Merged with existing — fields not sent are preserved. |
content | string | Yes | Full markdown body. |
language | string | Yes | BCP-47 language code. |
doc_template_id | string | Only for "new" | Template ID. Cannot be changed after creation. |
Response: { "success": true, "draftId": "abc123" }
POST /edit/discard
| Field | Type | Required | Description |
|---|---|---|---|
draftId | string | Yes | Draft ID to permanently delete. |
Response: { "success": true, "draftId": "abc123" }
GET /edit/:draftId
Returns an existing draft by ID. Same response shape as open.
Example
Open a page for editing:
curl -X POST https://api.comstack.ai/api/projects/your-project-id/docs/edit/open \ -H "Authorization: Bearer <firebase-id-token>" \ -H "Content-Type: application/json" \ -d '{"slug": "guides/intro", "language": "en"}'Save a change:
curl -X POST https://api.comstack.ai/api/projects/your-project-id/docs/edit/save \ -H "Authorization: Bearer <firebase-id-token>" \ -H "Content-Type: application/json" \ -d '{ "draftId": "abc123", "metadata": {"title": "Updated Title"}, "content": "## Section\n\nBody text.", "language": "en" }'Common errors
400 — non-draft document — attempting to save or discard a live document. Use open first to clone it to a draft.
400 — missing required fields — slug and language required for open; draftId, metadata, content, language required for save.
401 Unauthorized — missing or expired Firebase ID Token.
403 Forbidden — caller doesn’t have manager or admin role on the project.
404 Not found — no live or draft exists for the given slug/language (for open), or the draft ID doesn’t exist.
Related
- Publish API — how drafts are promoted to live
- API overview — full endpoint index
- Authentication — Firebase token and role requirements