# Drafts, files and corrections

The [hosted page](/forms/hosted-page) does all of this for you. These routes are for your own front
end when a form is too long for one sitting.

## Drafts

A draft is a scratchpad its holder owns. It validates nothing, tells the workspace nothing until it is
filed, and **expires after 30 days**.

| Route | Does |
| --- | --- |
| `POST /v1/public/forms/<slug>/drafts` | Start one → `{draft, url}`; keep the short key |
| `GET /v1/public/forms/drafts/<key>` | The questions and what has been typed so far |
| `PUT /v1/public/forms/drafts/<key>` | Replace the saved answers — the whole form, not a merge |
| `POST /v1/public/forms/drafts/<key>/submit` | File it — the same checks as a direct submit |

A draft files **once**: a second submit is `409`. An expired draft is `410`, not `404`, so you
can tell someone their link ran out rather than that it never existed.

## Files

A file question is answered by declaring the file on the draft, then sending the bytes straight to
storage:

```bash
curl -X POST https://neo-app-api-prod-836053680024.us-central1.run.app/v1/public/forms/drafts/<key>/files \
  -H "Content-Type: application/json" \
  -d '{"fieldId": "<file field id>", "name": "June statement.pdf", "contentType": "application/pdf", "sizeBytes": 291044}'
```

The answer carries a signed upload URL — `PUT` the file to it. When the draft is filed, its files are
pinned to the record it made. The file question decides what kind of document it is, not the upload.

## Corrections

When a form allows it, the submit receipt carries an `editUrl`. Its token opens that one submission:

| Route | Does |
| --- | --- |
| `GET /v1/public/forms/submissions/edit/<token>` | The answers that currently stand |
| `PUT /v1/public/forms/submissions/edit/<token>` | File a correction |
