Guides

Sessions

A session takes your user from what they typed to a finished document: it finds the form, asks its questions, then offers to generate it.

Why sessions

Every document starts as a session. Your user starts from their own words (“lease for my condo in Miami”), and the API decides what to ask next. You don't build a form per document or name one: forms are ours, and the session picks one. When none fits, an AI interview drafts a custom document.

Start a session

Send the user's first message. Name the user in Docgen-Subject, set from your own login; every later call on the session sends the same value. See Subjects.

curl https://api.129.212.147.181.sslip.io/v1/sessions \  -H "Authorization: Bearer $DOCGEN_API_KEY" \  -H "Docgen-Subject: wp_user:48213" \  -H "Content-Type: application/json" \  -d '{  "message": "I need a residential lease for my condo in Miami, Florida"}'

The response is a turn: input is the user's message, reply the assistant's answer and session the session after both. Show reply.text; when reply.question is set, render a control for its type.

reply
{  "id": "msg_01JBA2M8K3Q4R5S6T7V8W9X0YB",  "object": "message",  "role": "assistant",  "status": "completed",  "text": "It sounds like you need a Residential Lease Agreement. Is that right?",  "question": {    "id": "form",    "type": "form",    "section": "Document",    "title": "It sounds like you need a Residential Lease Agreement. Is that right?",    "help": "Pick the document, or tell us more if it's something else.",    "options": [      {        "value": "tpl_01JAZ7RKQ3M8D2X5V9T4N6P0CE",        "label": "Residential Lease Agreement"      },      {        "value": "other",        "label": "Something else"      }    ],    "allow_unknown": false  },  "answer": null,  "created_at": "2026-10-09T10:41:02Z"}

Choices come as options: objects with a value to send back and a label to show.

Phases

session.phase says where the session is:

  1. discovery: finding the form. form is null.
  2. intake: asking the form's questions. progress counts them.
  3. ready: every question is answered or skipped. actions lists what the user can do.

The user can keep chatting in every phase. A question about a clause, or “actually, it's a sublease”, is just another message.

Finding the form

The session searches the catalog with the user's message, then:

  • One confident match: it asks the user to confirm it, as a question of type form. Turn this off with settings.confirm_form: false to start its questions straight away.
  • Several matches: the same form question, with one option per candidate.
  • No match: the assistant asks clarifying questions. If no form fits, it settles on a custom form and interviews the user for what the document needs, in the same question shape.

A form question's option values are form IDs (tpl_…), plus other for “something else”. Send the chosen value back as the answer. Once a form is found, session.form names it, with its id and title.

Answering questions

Answer pending_question with a typed answer: the question's id and a value of its type (an option value for select, radio and form).

curl https://api.129.212.147.181.sslip.io/v1/sessions/ses_01JBA2M8K3Q4R5S6T7V8W9X0YZ/messages \  -H "Authorization: Bearer $DOCGEN_API_KEY" \  -H "Docgen-Subject: wp_user:48213" \  -H "Content-Type: application/json" \  -d '{  "answer": {    "question": "form",    "value": "tpl_01JAZ7RKQ3M8D2X5V9T4N6P0CE"  }}'

Or send what the user typed as text, in any phase:

curl https://api.129.212.147.181.sslip.io/v1/sessions/ses_01JBA2M8K3Q4R5S6T7V8W9X0YZ/messages \  -H "Authorization: Bearer $DOCGEN_API_KEY" \  -H "Docgen-Subject: wp_user:48213" \  -H "Content-Type: application/json" \  -d '{  "text": "Can I add a clause about parking?"}'
  • Follow-ups appear only when an earlier answer calls for them (their show_if).
  • Answer an earlier question again to change it. Send null to skip one: the document leaves that field empty.
  • The state is one of the questions; see Jurisdictions.
  • If the model fails, reply.status is failed with an error. The session is unchanged; send the message again.
  • One message at a time: a second one while a turn runs gets 409 turn_in_progress.

GET /v1/sessions/{session}/answers shows what has been collected so far.

Several questions per screen

Forms group their questions into steps, a screen each. pending_step holds the step's section and its open questions; show them together and send them back in one message as answers, a list of { question, value }. All are checked first: one bad answer returns 422 answers_invalid listing each problem, and nothing is saved.

  • A follow-up to a question on the same screen comes with the next step, so you never evaluate show_if.
  • For a chat-style app, start the session with settings.question_grouping: "single"; then pending_step always holds one question.
  • An AI interview (a custom form) asks one question at a time either way.

Actions

When phase is ready, actions lists what the user can do next. Each action carries the ready-made request that runs it. Ignore action types you don't know; more will be added.

session.actions
[  {    "type": "document.generate",    "status": "available",    "title": "Create your Residential Lease Agreement",    "description": "Drafted from your answers, as PDF or HTML.",    "options": {      "modes": [        "basic",        "advanced"      ],      "formats": [        "pdf",        "html"      ]    },    "request": {      "method": "POST",      "path": "/v1/documents",      "body": {        "session": "ses_01JBA2M8K3Q4R5S6T7V8W9X0YZ"      }    }  }]

Run it from your server, with the same Docgen-Subject:

curl https://api.129.212.147.181.sslip.io/v1/documents \  -H "Authorization: Bearer $DOCGEN_API_KEY" \  -H "Docgen-Subject: wp_user:48213" \  -H "Idempotency-Key: lease-0001" \  -H "Content-Type: application/json" \  -d '{  "session": "ses_01JBA2M8K3Q4R5S6T7V8W9X0YZ"}'

A session can make any number of documents (another mode, another format). Each appears in session.outputs. Generating before the session is ready returns 409 session_not_ready.

Listing and closing