Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.corti.ai/llms.txt

Use this file to discover all available pages before exploring further.

Beta. The POST /documents endpoint is available in beta. Feedback welcome at help@corti.ai or via your Corti contact.

What is guided synthesis?

Guided synthesis is a single endpoint, POST /documents, that generates a structured document from one of four template-supply paths. Where the classic generation flow requires an interaction and a templateKey, guided synthesis is interaction-optional and consumes the new Sections & Templates authoring API directly — or accepts a fully inline template you’ve never persisted. It is designed for the following needs:
  • Repeatable, governed generation — reference a stored, versioned template by UUID.
  • Light-touch overrides — keep your base template, but patch a section’s title, instructions or output schema for a single call.
  • Compose at runtime — pick stored sections out of your library and assemble them on the fly.
  • Try something new — define everything inline without saving anything first.
Whichever path you pick, the response is a structured document mapped to the resolved template’s section keys, plus the templateId and templateVersionId that were used.

The four template-supply paths

You pick one path per call. The four behave differently with respect to whether a new template aggregate is persisted as a side-effect of the call.
PathTop-level fieldResolves toPersists a new template?
1. Plain templateReftemplateRef (no overrides)Stored template’s published (or pinned) versionNo — the referenced template is used as-is
2. templateRef + overridestemplateRef.overridesStored template with runtime patchesYes — a new auto-generated template aggregate is saved with inheritedFromId pointing at the base
3. Assembly from stored sectionsassemblyTemplateA new template built from referenced section IDs in declaration orderYes — auto-generated template aggregate is persisted
4. Fully inline dynamic templatedynamicTemplateSections and template defined inline in the request bodyYes — sections and template are persisted as auto-generated resources, immediately published
Drift-proof snapshots. For every path except plain templateRef, the auto-generated template aggregate snapshots the fully resolved content at request time. Subsequent edits to base templates or sections do not affect previously generated documents. You can also reuse that auto-generated template in future calls by reading its ID from the response.
Each path has its own page so you can land directly on the one that fits your scenario.

Path 1 — Plain templateRef

Reference a stored template by UUID. No overrides, no side-effects. The lightest path for production traffic.

Path 2 — templateRef + overrides

Keep your base template, patch instructions / heading / schema for a single call. Auto-generates a drift-proof aggregate.

Path 3 — assemblyTemplate

Build a template on the fly from existing stored sections. Useful for EHR-field-driven note composition.

Path 4 — dynamicTemplate

Define the template and every section inline. Ideal for prototyping and one-off generations.

Input context

Every call needs to tell the model what to reason over. Supply exactly one of:
  • context — an ordered array of explicit context items. Each item is one of three discriminated types (see below).
  • interactionId — when supplied, all non-discarded facts and transcripts already attached to the referenced interaction are passed implicitly as input context.
context and interactionId are currently mutually exclusive — supply one or the other, never both. Combining them to extend the implicit interaction context with extra explicit items is on the roadmap; see the release notes for status.

Context item types

typeRequired fieldUse when
texttext (string)Pasting a referral letter, dictation, EHR field, or any free-form snippet
transcripttranscript (minimal shape — transcripts[] of segments, optional metadata.participantsRoles)Feeding a conversation transcript directly without going through /streams
factsfact.text (string, required); fact.group (string, optional)Passing a single fact derived elsewhere (one fact per item — repeat the item to pass many). group is optional metadata you can carry over (e.g. "history-of-present-illness", "allergies") when migrating from Classic facts or grouping facts by category.
Mixed context array
"context": [
  { "type": "text", "text": "Referral letter:\nPatient referred by GP for evaluation of …" },
  {
    "type": "transcript",
    "transcript": {
      "metadata": {
        "participantsRoles": [
          { "channel": 0, "role": "clinician" },
          { "channel": 1, "role": "patient" }
        ]
      },
      "transcripts": [
        { "channel": 1, "text": "I've had this itchy rash for a week.", "start": 1200, "end": 4100 },
        { "channel": 0, "text": "Any new soaps or detergents?", "start": 4500, "end": 6300 }
      ]
    }
  },
  { "type": "facts", "fact": { "text": "Allergic to birch pollen since childhood", "group": "allergies" } }
]
If transcript segments include start/end timestamps, the model interleaves them with other context items by time where possible. Otherwise array order is honored.

Common request shape

All four paths share three top-level fields and differ only in which template-supply field they carry:
Shared shape
{
  "context":        [ /* OR omit and use interactionId */ ],
  "interactionId":  "<uuid, optional>",
  "outputLanguage": "en-US",

  // Exactly one of:
  "templateRef":      { /* Path 1 or 2 */ },
  "assemblyTemplate": { /* Path 3 */ },
  "dynamicTemplate":  { /* Path 4 */ }
}
outputLanguage is required and uses a BCP-47 tag.

Auto-generated template aggregates — 30-day retention

Paths 2, 3 and 4 persist an auto-generated template aggregate as a side-effect of generation — a drift-proof snapshot of the resolved template + sections that were actually used. Path 1 (plain templateRef) is the exception: it uses the referenced template as-is and persists nothing new.
Auto-generated aggregates are retained for 30 days, then automatically cleaned up.A scheduled job deletes auto-generated templates (and their versions) 30 days after they were created. After cleanup, the templateId returned in the response will no longer resolve — GET /documents/templates/{templateId} and the version reads will return 404.If you need the aggregate to outlive the 30-day window — for traceability, audit, or to keep it as a reusable template — convert it into a permanent project-owned resource before the window expires:
  1. GET /documents/templates/{templateId}/versions/{templateVersionId} to read the version raw — its sections[] array carries the resolved section IDs in request order.
  2. For each sectionId referenced, GET /documents/sections/{sectionId}/versions/{versionId} to read each section’s resolved configuration.
  3. Re-create the configuration via fresh POST /documents/sections and POST /documents/templates requests in your project — without inheritFromId pointing at the auto-generated aggregate (since the parent will be deleted). The new resources are source: user, fully owned by your project, and stay live until you delete them.
The auto-generated aggregate is a convenience snapshot for the request that produced it, not a long-term storage tier. Treat it as ephemeral.

Response shape

All four paths return the same response shape: a document object plus a usageInfo block. When the request uses the default retention policy, the document is also persisted with its own id, createdAt and updatedAt. With X-Corti-Retention-Policy: none, the response is the ephemeral variant — the same document body without the persisted-resource fields.
Response (default retention)
{
  "document": {
    "id":                "<your-document-id>",
    "name":              "Allergy follow-up note",
    "templateId":        "<your-template-id>",
    "templateVersionId": "<your-version-id>",
    "language":          "en-US",
    "stringDocument": {
      "<your-section-id>": "32-year-old female presenting with an itchy rash that began last week …",
      "<your-section-id>": "- Initiate corticosteroid cream\n- Follow up in 4 weeks"
    },
    "structuredDocument": null,
    "createdAt": "2026-05-20T10:00:00Z",
    "updatedAt": "2026-05-20T10:00:00Z"
  },
  "usageInfo": {
    "creditsConsumed": 0.029016
  }
}
The keys in stringDocument (and structuredDocument) are section UUIDs, not slugs or section keys. The slug-looking placeholders above stand in for the actual UUIDs. See Mapping response section IDs back to your sections below for how to correlate them to the sections in your request.
  • document.id — the persisted document UUID. Only present on the default-retention response; omitted when the request sets X-Corti-Retention-Policy: none.
  • document.templateId / document.templateVersionId — the template (and version) that was actually used. For Path 1 this is the referenced template; for Paths 2–4 it is the newly persisted auto-generated aggregate. Store these if you want full traceability of what produced each document.
  • document.stringDocument — an object keyed by section ID containing the rendered string output for each section. Always present.
  • document.structuredDocument — present when one or more sections use a non-string outputSchema (object, array, etc.). Keyed by section ID; each entry holds the structured object/array as the schema declared.
  • usageInfo.creditsConsumed — credits consumed for this request. Same shape as every other Corti endpoint that returns usage information.

Mapping response section IDs back to your sections

Both stringDocument and structuredDocument are keyed by section ID. For Path 1 (plain templateRef) and Path 2 (templateRef + overrides) those IDs match the sections of the referenced template — you can map them straight back. For Path 3 (assemblyTemplate) and Path 4 (dynamicTemplate) the keys are IDs Corti generates for the auto-saved aggregate. Path 3 carries explicit sectionRefs[].sectionId you can correlate by, but Path 4 is the gotcha: your request supplies an ordered list of SectionGeneration objects with no IDs of your own, so the response keys arrive as opaque server-side IDs with no obvious mapping back to your inline section definitions — meaning you can’t reliably attach the right heading to each rendered section just from the response. Workaround until this is improved. Use the returned templateVersionId to read the saved aggregate:
GET /documents/templates/{templateId}/versions/{templateVersionId}
The version’s sections[] array preserves your request order and carries the resolved section IDs. Build a position → sectionId → heading mapping from that response, then key the rendered output against it.
This is a known DX gap for Path 4 specifically. The roadmap includes returning client-supplied identifiers (or section ordering) directly on the response so the follow-up GET isn’t needed.
The auto-generated aggregate the follow-up GET reads is itself subject to the 30-day retention window. Do the mapping read soon after generation (typically in the same processing pass), or persist the mapping in your service. Don’t rely on the aggregate still being there weeks later.

When to use which path

Use Path 1 (plain templateRef) with a pinned templateVersionId for reproducibility. No side-effects, fastest path, easiest to audit.

Errors and validation

StatusWhen it happens
400 Bad RequestRequest body fails basic validation (e.g. missing outputLanguage, malformed JSON).
404 Not FoundA referenced templateId, templateVersionId or sectionId does not exist.
422 Unprocessable EntityRequest is structurally valid but semantically rejected — e.g. none of templateRef/assemblyTemplate/dynamicTemplate supplied, the referenced template has no published version, an override targets a section not linked to the base template version, or you supplied more than one of the three.
502 Bad GatewayDocument generation failed downstream.
Provide exactly one of templateRef, assemblyTemplate, dynamicTemplate. Supplying zero or more than one yields a 422.

How guided synthesis relates to other endpoints

  • It is separate from POST /interactions/{id}/documents (Documents Classic). The classic endpoint continues to work and is the right choice if you’re still using templateKey-based generation. See Standard Document Generation.
  • It consumes the new resources authored via the Sections and Templates APIs.
  • The outputSchema reference is shared with section authoring — see the section-creation guide.

Next steps

Create a Section

Author and version the sections you’ll reference in Paths 1–3.

Create a Template

Compose sections into versioned templates ready for Path 1.

Corti Standards

Reference the Corti-curated section and template library from any of the four paths.

Migrate from Classic

Field-by-field mapping from POST /interactions/{id}/documents to POST /documents.