# Update a form

`PATCH /v1/forms/{id}`

Requires an API key with the `forms:write` scope. [About keys and scopes](/docs/api/authentication)

Changes a form's fields, consent text or success behaviour. Existing submissions are not revisited.

## Path parameters

- `id` (string, required, uuid)

## Request body

- `name` (string, optional, 1–255 characters)
- `heading` (string | null, optional, 1–200 characters) — What visitors see above the fields; `null` clears it.
- `intro` (string | null, optional, 1–1000 characters) — A line or two under the heading; `null` clears it.
- `source` (string, optional, 1–80 characters) — Recorded on each contact the form creates.
- `status` (string, optional, one of `draft`, `published`) — Whether the form accepts submissions.
- `groupId` (string, optional, uuid) — The group every submitter is added to.
- `fields` (FormFieldInput[], optional, at least 1 item, at most 20 items) — The fields, top to bottom. One must be a required `email` field.
  - `key` (string, required, up to 80 characters) — Where the answer goes: `email`, `firstName`, `lastName`, `phone`, `attributes.<name>`, `dates.<name>` (a named date that date-triggered journeys read), `groups` or `topics`. Each type accepts only some keys.
  - `type` (string, required, one of `email`, `text`, `textarea`, `select`, `checkbox`, `date`, `phone`) — The input the visitor sees.
  - `label` (string, required, 1–120 characters) — The text shown beside the field.
  - `placeholder` (string, optional, up to 160 characters) — Hint text shown inside the empty field.
  - `required` (boolean, optional, default `false`) — Whether the visitor must fill it in.
  - `options` (object[], optional, at least 1 item, at most 50 items) — Required for `select` and `checkbox`, refused for other types. For the `groups` key each value is a group id, for `topics` a topic id; the label is what the visitor sees beside its box.
    - `value` (string, required, 1–100 characters) — What is stored when chosen.
    - `label` (string, required, 1–120 characters) — What the visitor sees.
- `hiddenFields` (object, optional) — Fixed values saved on each submitter with no field shown.
- `allowedOrigins` (string[], optional, at most 20 items) — Site origins (scheme and host, no path) the embed may load from.
- `doubleOptIn` (boolean, optional) — Ask submitters to confirm by email before they are subscribed.
- `theme` (FormThemeInput, optional)
  - `accentColor` (string, optional) — Colour of the button and focus outlines, as `#RRGGBB`.
  - `fontFamily` (string, optional, one of `system`, `sans`, `serif`, `mono`) — The font style of the form.
  - `borderRadius` (integer, optional, min 0, max 24) — Corner rounding of inputs and the button, in px.
  - `buttonLabel` (string, optional, 1–40 characters) — Text on the submit button.
- `display` (object, optional)
  - One of: **Inline**
    - `mode` ("inline", required)
  - One of: **Popup**
    - `mode` ("popup", required)
    - `delaySeconds` (integer, optional, min 0, max 600) — Seconds after the page loads before it opens. Defaults to 5.
    - `scrollPercent` (integer, optional, min 1, max 100) — Opens once the visitor has scrolled this far down the page.
    - `exitIntent` (boolean, optional) — Opens when the visitor moves to leave the page (desktop only).
    - `urlMatch` (object, optional) — Limits which pages the popup opens on.
      - `contains` (string[], optional, at most 20 items) — Show only on pages whose URL contains one of these.
      - `excludes` (string[], optional, at most 20 items) — Never show on pages whose URL contains one of these.
    - `hideForDays` (integer, optional, min 0, max 365) — Days it stays away once closed. Defaults to 7.
    - `hideAfterSubmit` (boolean, optional) — Whether it stays away after a signup. Defaults to true.
- `captcha` (object | null, optional) — CAPTCHA for submissions: `{ mode: "kirora" }` (the default on a new form), `{ mode: "own", siteKey, secretKey }` for your Cloudflare Turnstile widget, or `null` for none.
  - One of: **KiroraCaptchaInput**
    - `mode` ("kirora", required)
  - One of: **OwnCaptchaInput**
    - `mode` ("own", required)
    - `siteKey` (string, required, 1–200 characters) — The widget's public site key.
    - `secretKey` (string, optional, 1–200 characters) — The widget's secret key. Write-only: omit it to keep the stored one.
- `consent` (object, optional) — The consent box every submitter must tick.
  - `required` (true, required) — Always `true`: the visitor must tick the consent box.
  - `label` (string, required, 1–500 characters) — The consent text shown beside the box.
- `success` (object, optional) — What happens after a submission.
  - One of: **Show a message**
    - `type` ("message", required)
    - `message` (string, required, 1–1000 characters) — Shown in place of the form.
  - One of: **Redirect**
    - `type` ("redirect", required)
    - `redirectUrl` (string, required, uri, up to 2048 characters) — An http(s) address the visitor is sent to.

## Returns

Returns `200 OK` with a `Form` in `data`. Otherwise returns an error; [Errors](/docs/api/errors) lists every code and which to retry.

- `id` (string, required, uuid)
- `publicId` (string, required) — The id the public embed and hosted page use.
- `name` (string, required)
- `heading` (string | null, required) — What visitors see above the fields; `null` shows none.
- `intro` (string | null, required) — A line or two under the heading; `null` shows none.
- `source` (string, required) — Recorded on each contact the form creates.
- `status` (string, required, one of `draft`, `published`) — Whether the form accepts submissions.
- `groupId` (string | null, required, uuid) — The group every submitter is added to.
- `fields` (object[], required) — The fields, top to bottom.
  - `key` (string, required) — Where the answer goes, such as `email` or `attributes.plan`.
  - `type` (string, required, one of `email`, `text`, `textarea`, `select`, `checkbox`, `date`, `phone`) — The input the visitor sees.
  - `label` (string, required) — The text shown beside the field.
  - `placeholder` (string, optional) — Hint text shown inside the empty field.
  - `required` (boolean, required) — Whether the visitor must fill it in.
  - `options` (object[], optional) — The choices of a `select` or `checkbox` field.
    - `value` (string, required)
    - `label` (string, required)
- `hiddenFields` (object, required) — Fixed values saved on each submitter with no field shown.
- `allowedOrigins` (string[], required) — Site origins the embed may load from.
- `refusedOrigins` (object[], required) — Origins an embed was refused from lately, newest first, not counting any since added to `allowedOrigins`; add one there to approve it.
  - `origin` (string, required) — The origin that was refused.
  - `lastRefusedAt` (string, required, date-time) — When it was last refused.
- `doubleOptIn` (boolean, required) — Whether submitters must confirm by email before they are subscribed.
- `theme` (FormTheme, required)
  - `accentColor` (string, optional) — Colour of the button and focus outlines, as `#RRGGBB`.
  - `fontFamily` (string, optional, one of `system`, `sans`, `serif`, `mono`) — The font style of the form.
  - `borderRadius` (integer, optional, min 0, max 24) — Corner rounding of inputs and the button, in px.
  - `buttonLabel` (string, optional, 1–40 characters) — Text on the submit button.
- `display` (object, required)
  - One of: **Inline**
    - `mode` ("inline", required)
  - One of: **Popup**
    - `mode` ("popup", required)
    - `delaySeconds` (integer, optional, min 0, max 600) — Seconds after the page loads before it opens. Defaults to 5.
    - `scrollPercent` (integer, optional, min 1, max 100) — Opens once the visitor has scrolled this far down the page.
    - `exitIntent` (boolean, optional) — Opens when the visitor moves to leave the page (desktop only).
    - `urlMatch` (object, optional) — Limits which pages the popup opens on.
      - `contains` (string[], optional, at most 20 items) — Show only on pages whose URL contains one of these.
      - `excludes` (string[], optional, at most 20 items) — Never show on pages whose URL contains one of these.
    - `hideForDays` (integer, optional, min 0, max 365) — Days it stays away once closed. Defaults to 7.
    - `hideAfterSubmit` (boolean, optional) — Whether it stays away after a signup. Defaults to true.
- `captcha` (object | null, required) — Where the CAPTCHA comes from; `null` while it is off. Secrets never show.
  - One of: **KiroraCaptchaSetting**
    - `mode` ("kirora", required)
  - One of: **OwnCaptchaSetting**
    - `mode` ("own", required)
    - `siteKey` (string, required)
- `consent` (object, required)
  - `required` (true, required) — Always `true`: the visitor must tick the consent box.
  - `label` (string, required) — The consent text shown beside the box.
- `success` (object, required)
  - One of: **Show a message**
    - `type` ("message", required)
    - `message` (string, required) — Shown in place of the form.
  - One of: **Redirect**
    - `type` ("redirect", required)
    - `redirectUrl` (string, required, uri) — An http(s) address the visitor is sent to.
- `archivedAt` (string | null, required, date-time) — When it was archived; an archived form is left out of the list and stops serving.
- `createdAt` (string, required, date-time)
- `updatedAt` (string, required, date-time)

## Example

```bash
curl -X PATCH https://api.kirora.io/v1/forms/018f2a4e-6b1c-7d3e-9f40-37386ae05a6b \
  -H "Authorization: Bearer $KIRORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Weekend specials",
    "heading": "heading_example",
    "intro": "intro_example",
    "source": "source_example",
    "status": "draft",
    "groupId": "018f2a4e-6b1c-7d3e-9f40-532211a15a6b",
    "fields": [
      {
        "key": "key_example",
        "type": "email",
        "label": "label_example"
      }
    ],
    "hiddenFields": {},
    "allowedOrigins": [
      "https://example.com"
    ],
    "doubleOptIn": true,
    "theme": {},
    "display": {
      "mode": "inline"
    },
    "captcha": {
      "mode": "kirora"
    },
    "consent": {
      "required": true,
      "label": "label_example"
    },
    "success": {
      "type": "message",
      "message": "message_example"
    }
  }'
```

Response `200`:

```json
{
  "data": {
    "id": "018f2a4e-6b1c-7d3e-9f40-37386ae05a6b",
    "publicId": "publicId_example",
    "name": "Weekend specials",
    "heading": "heading_example",
    "intro": "intro_example",
    "source": "source_example",
    "status": "draft",
    "groupId": "018f2a4e-6b1c-7d3e-9f40-532211a15a6b",
    "fields": [
      {
        "key": "key_example",
        "type": "email",
        "label": "label_example",
        "required": true
      }
    ],
    "hiddenFields": {},
    "allowedOrigins": [
      "https://example.com"
    ],
    "refusedOrigins": [
      {
        "origin": "origin_example",
        "lastRefusedAt": "2030-03-14T09:30:00Z"
      }
    ],
    "doubleOptIn": true,
    "theme": {},
    "display": {
      "mode": "inline"
    },
    "captcha": {
      "mode": "kirora"
    },
    "consent": {
      "required": true,
      "label": "label_example"
    },
    "success": {
      "type": "message",
      "message": "message_example"
    },
    "archivedAt": "2030-03-14T09:30:00Z",
    "createdAt": "2030-03-14T09:30:00Z",
    "updatedAt": "2030-03-14T09:30:00Z"
  }
}
```
