# Responses (https://form.dimah.dev/docs/responses)



`startResponse` copies the active form into `response.definition`. Drafts,
visibility rules, and submit validation use that snapshot—not the current live
questionnaire.

<Callout>
  Editing a form never changes an in-flight draft or a submitted response.
</Callout>

## Lifecycle [#lifecycle]

| Status      | Meaning                         | Available transitions |
| ----------- | ------------------------------- | --------------------- |
| `draft`     | Answers may be incomplete       | Save, submit, abandon |
| `submitted` | Visible required answers passed | Reopen or delete      |
| `abandoned` | Closed without submitting       | Reopen or delete      |

| Call              | Effect                                                                             |
| ----------------- | ---------------------------------------------------------------------------------- |
| `startResponse`   | Freezes the definition and applies `defaultValue` values                           |
| `saveDraft`       | Applies an answer patch; `null` removes a key                                      |
| `submitResponse`  | Replaces answers when provided, validates visible fields, then locks the response  |
| `abandonResponse` | Locks an unfinished response                                                       |
| `reopenResponse`  | Returns a submitted or abandoned response to `draft` without changing its snapshot |

`saveDraft({ answers })` is a patch. `submitResponse({ answers })` treats
`answers` as the complete replacement; omit it to submit the stored draft as
is. Submit strips hidden values before validation and persistence.

Pass `{ resume: true, respondentId }` to `startResponse` to reuse the latest
draft for that respondent. The server rejects `resume: true` without a
`respondentId`. In authenticated applications, resolve that id on the server
rather than accepting it from browser input. See [Security](https://form.dimah.dev/docs/security.md).

## Concurrent edits [#concurrent-edits]

Draft writes and submits accept the `updatedAt` token from the last read. The
store writes only if it still matches; otherwise the request fails with
`STALE_UPDATE`. `useFormResponse` refreshes a session on that conflict.

Do not omit `updatedAt` unless an intentional last-write-wins update is the
desired behavior.

## Stored record [#stored-record]

```ts
import type { ResponseRecord } from "@dimah-form/react";
```

<AutoTypeTable path="packages/core/src/schema/protocol.ts" name="ResponseRecord" />

List routes can omit the definition and answers:

```ts
import type { ResponseSummary } from "@dimah-form/react";
```

<AutoTypeTable path="packages/core/src/schema/protocol.ts" name="ResponseSummary" />

Set `respondentId` on the server in `onStart`; never trust a browser-supplied
owner id. See [Security](https://form.dimah.dev/docs/security.md).

## Next [#next]

<Cards>
  <Card title="React" href="/docs/react" description="Use the response lifecycle in a fill session." />

  <Card title="Protocol" href="/docs/protocol" description="Call the same lifecycle over HTTP or form.api." />
</Cards>
