Document Generation API

The Document Generation API powers Ema's long-form document workflows — proposals, RFP responses, and other structured documents an AI Employee writes and a person edits. It stores documents and their full version history, generates content by triggering a workflow run, supports an inline chat assistant for editing and Q&A, and manages a reusable template library. The docgen service is mounted at /api/v1/docgen, so every path below is that prefix plus the path shown.

All requests require a JWT or tenant API key. Examples use https://your-tenant.ema.co as the host.

Documents are scoped to the caller. Each document belongs to the user and tenant that created it. A document that belongs to another tenant returns 404 — there is no existence leak across tenants.

Documents

A document holds a title, HTML content, and JSON metadata, and tracks a current version number.

  • List: GET /api/v1/docgen/documents — ordered by updated_at descending, paginated with limit and offset. Filter by metadata with type and parent_document_id. Pass include_content=true to include content_html in each item; omit it for lightweight poll responses.
  • Create: POST /api/v1/docgen/documents — requires title; optionally seed content_html, bind a workflow_id, attach a session_id, and set metadata.
  • Get / update / delete: GET, PATCH, DELETE /api/v1/docgen/documents/{id}. PATCH updates the title and/or shallow-merges a metadata patch; DELETE is a soft delete.
POST https://your-tenant.ema.co/api/v1/docgen/documents
Authorization: Bearer eyJhbGciOiJSUzI1Ni...
Content-Type: application/json

{
  "title": "Acme RFP response",
  "workflow_id": "3f7a...",
  "metadata": { "type": "rfp_section" }
}

Bulk create

POST /api/v1/docgen/documents/bulk creates a parent document plus N child sections in one transaction. Provide title and children to create a new parent; provide parent_document_id instead to add children to an existing parent (a missing or cross-tenant parent returns 404).

Versions

Every change to a document is recorded as a version, so you can review history and roll back.

  • List versions: GET /api/v1/docgen/documents/{id}/versions (without content).
  • Get one version: GET /api/v1/docgen/documents/{id}/versions/{versionNumber} (with content_html).
  • Save a manual version: POST /api/v1/docgen/documents/{id}/versions. If the document changed since you loaded it, the save returns 409 Conflict so you don't overwrite a newer edit.
  • Restore: POST /api/v1/docgen/documents/{id}/restore/{versionNumber} writes the chosen version's content back as the latest version.

Each Version records a source (ai_create, ai_edit, manual_save, or restore) and a change_description, plus the user or workflow run that produced it.

Generate content

POST /api/v1/docgen/documents/{id}/generate starts a workflow run scoped to a document and returns immediately — the workflow writes content back as a new version.

POST https://your-tenant.ema.co/api/v1/docgen/documents/a1b2.../generate
Authorization: Bearer eyJhbGciOiJSUzI1Ni...
Content-Type: application/json

{
  "section_title": "Executive summary",
  "instructions": "Summarize our proposed approach in two paragraphs.",
  "knowledge_base_ids": ["9b2c..."]
}

The body is optional. The workflow to run is resolved in order: the request body's workflow_id, then the document's bound workflow_id, otherwise a 422. Your JWT or API key is forwarded to the workflow service, so the run inherits your tenant and role. The response is 202 Accepted:

{
  "run_id": "5e6f...",
  "workflow_id": "3f7a...",
  "stream_url": "/runs/5e6f.../stream"
}

Tail progress on the Workflow API SSE stream at the returned stream_url.

Outlines. POST /api/v1/docgen/generate-document-outline turns a user-supplied HTML outline (input_type: MANUAL) or the markdown of an uploaded document (input_type: UPLOAD) into a structured list of sections you can then create with bulk create. The AI-generated outline path is not yet available in this platform.

Export

POST /api/v1/docgen/export enqueues an export job for an ordered list of document IDs, then you poll for the result.

POST https://your-tenant.ema.co/api/v1/docgen/export
Authorization: Bearer eyJhbGciOiJSUzI1Ni...
Content-Type: application/json

{
  "document_ids": ["a1b2...", "c3d4..."],
  "format": "html"
}

The response is 202 Accepted with a job. Poll GET /api/v1/docgen/export/{jobId} until status is complete (then read download_url) or error. The format field currently supports html; pdf and pptx return 501.

Chat assistant

Each document has an inline assistant for editing and questions. There is also a document-less Q&A assistant scoped to a tenant's knowledge bases.

  • Document sessions: GET, POST /api/v1/docgen/documents/{docId}/chat/sessions, plus GET, PATCH, DELETE .../chat/sessions/{id}.
  • Document messages: GET, POST /api/v1/docgen/documents/{docId}/chat/sessions/{id}/messages. Sending a message returns the assistant's reply synchronously.
  • Tenant-KB Q&A sessions: the same shapes under /api/v1/docgen/chat/sessions and .../chat/sessions/{id}/messages, with no document context.
POST https://your-tenant.ema.co/api/v1/docgen/documents/a1b2.../chat/sessions/7d1e.../messages
Authorization: Bearer eyJhbGciOiJSUzI1Ni...
Content-Type: application/json

{
  "content": "Tighten this paragraph and remove the jargon.",
  "mode": "edit",
  "selected_html": "<p>...</p>"
}

mode is edit (the default in-document writing assistant) or qa (knowledge-base Q&A, no rewrite). For an edit request that rewrites a selection, the assistant message carries a replacement_text. On the document-less Q&A path, set mode: qa and a workflow_id to scope the knowledge-base search.

Comments

Documents support threaded comments for review.

  • Threads: POST, GET /api/v1/docgen/documents/{docId}/comments/threads; resolve or reopen with PATCH .../comments/threads/{threadId}, and delete a thread (and its replies) with DELETE.
  • Replies: POST .../comments/threads/{threadId}/replies; edit with PATCH and soft-delete with DELETE .../replies/{commentId}.
  • Across documents: GET /api/v1/docgen/comments/threads batch-lists threads across several documents.

Template library

Templates standardize the look of generated documents. A template is DOCX or PPTX and carries a generation mode (slot_fill or html_rewrite).

  • List / create: GET, POST /api/v1/docgen/templates; upload a source file with POST /api/v1/docgen/templates/upload.
  • Get / update / delete: GET, PATCH, DELETE /api/v1/docgen/templates/{id}.
  • Render assets: GET /api/v1/docgen/templates/{id}/html and .../thumbnail.
  • Manage: set the tenant default with PUT .../templates/{id}/set-default, duplicate with POST .../duplicate, and re-run extraction with POST .../re-extract.
  • PPTX slides: list, reorder, fetch, edit, and delete slides under /api/v1/docgen/templates/{id}/slides.

Section profiles describe how a tenant labels document sections. Manage them with GET, POST /api/v1/docgen/section-profiles (and GET, PATCH, DELETE .../section-profiles/{id}), and classify a set of section titles against them with POST /api/v1/docgen/section-profiles/classify.

What's next

Last updated: Jul 3, 2026