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.
{ "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:
- discovery: finding the form. form is null.
- intake: asking the form's questions. progress counts them.
- 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.
[ { "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
- GET /v1/sessions lists one subject's sessions, newest first: a “your documents” page.
- GET /v1/sessions/{session}/messages returns the conversation, to show it again later.
- POST /v1/sessions/{session}/close stops new messages; history and answers stay readable.
- DELETE /v1/sessions/{session} erases the conversation, the answers and the session's documents. See Data lifetime.