# Protocol (https://form.dimah.dev/docs/protocol)



Route paths, payloads, and response shapes live in `@dimah-form/core`. Default base path: `/api/form`.

***

## Form Management Endpoints [#form-management-endpoints]

| Method | Path           | Client Method                             | `form.api` Method      | Description                                      |
| :----- | :------------- | :---------------------------------------- | :--------------------- | :----------------------------------------------- |
| `GET`  | `/form`        | `getForm({ formId })`                     | `getForm({ query })`   | Retrieve form definition snapshot by ID or slug. |
| `POST` | `/form`        | `saveForm(form)`                          | `saveForm({ body })`   | Upsert dynamic form definition in database.      |
| `POST` | `/form/delete` | `deleteForm({ formId })`                  | `deleteForm({ body })` | Delete form (rejected if responses exist).       |
| `GET`  | `/forms`       | `listForms({ status?, limit?, offset? })` | `listForms({ query })` | List forms (default limit: 50, max: 100).        |

***

## Response Lifecycle Endpoints [#response-lifecycle-endpoints]

| Method | Path                | Client Method                                                         | `form.api` Method           | Description                                                 |
| :----- | :------------------ | :-------------------------------------------------------------------- | :-------------------------- | :---------------------------------------------------------- |
| `POST` | `/response/start`   | `startResponse({ formId, respondentId?, resume? })`                   | `startResponse({ body })`   | Start fill session and freeze definition snapshot.          |
| `GET`  | `/response`         | `getResponse({ responseId })`                                         | `getResponse({ query })`    | Retrieve a full response record by ID.                      |
| `GET`  | `/responses`        | `listResponses({ formId?, respondentId?, status?, limit?, offset? })` | `listResponses({ query })`  | List response summaries (or full rows with `include=full`). |
| `POST` | `/response/draft`   | `saveDraft({ responseId, answers, updatedAt? })`                      | `saveDraft({ body })`       | Save partial answers patch on active draft.                 |
| `POST` | `/response/submit`  | `submitResponse({ responseId, answers?, updatedAt? })`                | `submitResponse({ body })`  | Validate answers vs snapshot and finalize submission.       |
| `POST` | `/response/abandon` | `abandonResponse({ responseId, updatedAt? })`                         | `abandonResponse({ body })` | Lock draft response as abandoned.                           |
| `POST` | `/response/reopen`  | `reopenResponse({ responseId, updatedAt? })`                          | `reopenResponse({ body })`  | Unlock submitted/abandoned response back to draft.          |
| `POST` | `/response/delete`  | `deleteResponse({ responseId })`                                      | `deleteResponse({ body })`  | Delete a response record.                                   |

***

## Endpoint Details & Payloads [#endpoint-details--payloads]

### 1. `POST /response/start` [#1-post-responsestart]

Starts a new fill session for a questionnaire.

* **Request Body**:
  ```json
  {
    "formId": "feedback",
    "respondentId": "user-123",
    "resume": true
  }
  ```
* **Response Body (`200 OK`)**:
  ```json
  {
    "id": "resp_01h8x...",
    "formId": "feedback",
    "status": "draft",
    "definition": {
      "id": "feedback",
      "slug": "feedback",
      "title": "Product Feedback",
      "fields": [...]
    },
    "answers": {},
    "respondentId": "user-123",
    "submittedAt": null,
    "createdAt": "2026-09-19T10:00:00.000Z",
    "updatedAt": "2026-09-19T10:00:00.000Z"
  }
  ```

***

### 2. `POST /response/draft` [#2-post-responsedraft]

Saves a partial patch of answers. Setting a key to `null` deletes that answer.

* **Request Body**:
  ```json
  {
    "responseId": "resp_01h8x...",
    "answers": {
      "fullName": "Jane Doe",
      "rating": "great"
    },
    "updatedAt": "2026-09-19T10:00:00.000Z"
  }
  ```
* **Response Body (`200 OK`)**: Updated `ResponseRecord`.

***

### 3. `POST /response/submit` [#3-post-responsesubmit]

Validates all visible required answers against the snapshot schema and locks the response to `"submitted"`.

* **Request Body**:
  ```json
  {
    "responseId": "resp_01h8x...",
    "answers": {
      "fullName": "Jane Doe",
      "rating": "poor",
      "improvements": "Please improve loading speed."
    },
    "updatedAt": "2026-09-19T10:05:00.000Z"
  }
  ```
* **Response Body (`200 OK`)**: Updated `ResponseRecord` with `status: "submitted"`.

***

## Next Steps [#next-steps]

<Cards>
  <Card title="Errors" href="/docs/errors" description="Inspect machine-readable error codes returned on failed requests." />

  <Card title="Snapshots" href="/docs/snapshots" description="Learn how snapshots ensure safe draft lifecycles." />

  <Card title="Configuration" href="/docs/configuration" description="View full client and server options." />
</Cards>
