Skip to main content

How to Generate Documents using Corti's API

Generate structured, schema-controlled clinical documents from stored templates, section assemblies, or fully inline definitions using Corti's Guided Documents API.

Overview

Corti's Guided Documents API generates clinical documents from a single endpoint: POST /documents. Documents can be generated from:

  • Facts finalized during an interaction (including facts you add from your own systems)

  • Transcripts of a conversation

  • Existing documents or free-form text (e.g. referral letters, dictation)

  • Any combination of the above — or implicitly, by referencing an existing interaction

Generation is built on Templates and Sections — first-class, versioned, publishable resources that you can browse, create, and manage via the API. See Using Templates and Sections in the Corti API for the resource model.

⚠️ Already integrating with POST /interactions/{id}/documents and templateKey? That surface ("Documents Classic") is deprecated and will be shut down on January 18, 2027. It keeps working until then, but new integrations should build on Guided Documents. See the migration guide on docs.corti.ai.

💡 This feature requires human oversight of its outputs.

The Generate Document Endpoint

POST <https://api.eu.corti.app/v2/documents>

Every request needs three things:

Requirement

Field(s)

A template supply — exactly one of four ways to define the document structure

templateRef, assemblyTemplate, or dynamicTemplate

Input context — what the model reasons over

context (array) or interactionId

Output language — BCP-47 tag (e.g. en-US)

outputLanguage

Full API reference: Generate a structured document.

The Four Template-Supply Paths

Path

What you supply

Use when

Path 1 — templateRef

A stored template's UUID

Production traffic; the template already encodes everything you need. No side-effects.

Path 2 — templateRef • overrides

A stored template plus per-call tweaks

Keep your base template, but patch a section's heading, prompts, or output schema for a single call.

Path 3 — assemblyTemplate

A list of stored sections in your chosen order

Compose a document on the fly, e.g. EHR-field-driven notes.

Path 4 — dynamicTemplate

Fully inline section definitions

Prototyping and one-off generations; nothing is saved first.

Supply exactly one of the three template fields — passing zero, or more than one, returns a 422 error.

Path 1: Stored Templates

Corti maintains a curated library of standard templates (SOAP, H&P, nursing note, and more), each published per language. Retrieve available templates with LIST /documents/templates — filterable by lang, region, specialty, and label — and use the template's id (UUID) in your request.

curl --request POST \
--url <https://api.eu.corti.app/v2/documents> \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Tenant-Name: <tenant-name>' \
--data '{
"outputLanguage": "en-US",
"interactionId": "<your-interaction-id>",
"templateRef": {
"templateId": "<your-template-id>"
}
}'

By default the template's currently published version is used. To pin an exact version for reproducibility, also pass templateVersionId.

Path 2: Stored Template + Overrides

Keep the base template, but customize individual sections for a single call. Section-level overrides live under overrides.sections[].generation:

Field

Purpose

heading

Override the section heading (title)

instructions.contentPrompt

Guide what input content gets assigned to the section

instructions.writingStylePrompt

Prompt the writing style (e.g. telegraphic, plain language)

instructions.miscPrompt

Free-form additional instructions

outputSchema

Control the output's shape and format (typed schema — replaces the old formatRuleOverride)

Path 3: Assemble Stored Sections

If no template matches your need but the right sections exist, assemble them at request time. List sections with LIST /documents/sections (same filters), then reference them by UUID — the order of sectionRefs determines the order of sections in the document.

curl --request POST \
--url <https://api.eu.corti.app/v2/documents> \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Tenant-Name: <tenant-name>' \
--data '{
"outputLanguage": "en-US",
"interactionId": "<your-interaction-id>",
"assemblyTemplate": {
"name": "Allergy follow-up note",
"instructions": {
"prompt": "Produce a focused follow-up note for an allergy consultation."
},
"sectionRefs": [
{ "sectionId": "<your-section-id>" },
{ "sectionId": "<your-section-id>" },
{
"sectionId": "<your-section-id>",
"overrides": {
"generation": {
"heading": "Impression",
"instructions": { "writingStylePrompt": "Telegraphic; no narrative." }
}
}
}
]
}
}'

Path 4: Fully Inline (Dynamic Template)

Define the template and every section inline — headings, prompts, and output schemas — without saving anything. Ideal for iterating on prompt design before promoting sections to your stored library. See Path 4 — dynamicTemplate on docs.corti.ai.

Providing Input Context

Tell the model what to reason over — supply exactly one of:

Option

Behavior

context (array)

You pass the input explicitly. Items are combinable: mix text, transcript, and facts items in a single request.

interactionId

The API implicitly pulls all non-discarded facts and transcripts attached to the referenced interaction.

context and interactionId are currently mutually exclusive.

Context item types:

type

Required field

Use when

text

text

Pasting a referral letter, dictation, EHR field, or any free-form snippet

transcript

transcript

Feeding a conversation transcript directly

facts

facts — array of { text, group? }

Supplying clinical facts explicitly

Example — mixed context with a stored template and one override:

curl --request POST \
--url <https://api.eu.corti.app/v2/documents> \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Tenant-Name: <tenant-name>' \
--data '{
"outputLanguage": "en-US",
"context": [
{ "type": "text", "text": "Referral letter: Patient referred by GP for evaluation of a persistent rash." },
{
"type": "facts",
"facts": [
{ "text": "32 year-old female", "group": "demographics" },
{ "text": "itchy rash, started last week", "group": "history-of-present-illness" },
{ "text": "allergic to birch pollen since childhood", "group": "allergies" }
]
}
],
"templateRef": {
"templateId": "<your-template-id>",
"overrides": {
"sections": [
{
"sectionId": "<your-section-id>",
"generation": {
"heading": "Anamnesis",
"instructions": { "miscPrompt": "Refer to the patient as my case." }
}
}
]
}
}
}'

💡 Don't pass unnecessary metadata (timestamps, segment indices) in context items — it bloats input token usage without benefit.

The Response

A successful call returns 201 Created (the document is persisted) along with:

  • document.sections — every section in template order, with its sectionId and rendered heading

  • document.stringDocument — an object keyed by section UUID containing each section's Markdown output

  • document.structuredDocument — present when sections declare an outputSchema; values are typed to each schema

  • document.templateId / document.templateVersionId — the exact template version that produced the document, for full traceability

  • usageInfo.creditsConsumed — credits consumed by the request

Retention: if you do not want the generated document saved, add the header X-Corti-Retention-Policy: none. The document is generated and returned as usual (HTTP 200), but not persisted.

Good to Know

  • Drift-proof snapshots: every call except a plain templateRef (Path 1) auto-generates a template aggregate snapshotting the resolved template and sections. Aggregates are retained for 30 days — convert them into permanent project-owned resources if you need them longer.

  • All-or-nothing generation: if any step of generation fails, the entire request fails. You will never receive a partial document. If you need per-section resilience, generate sections in separate requests.

  • No duplicate sections: the same sectionId cannot be used twice in one request.

  • Migrating from Classic? The documentationMode and disableGuardrails parameters do not yet have equivalents on POST /documents. If your integration relies on them, reach out to support before cutting traffic over.

Where to Go Next

Did this answer your question?