Skip to content

Builder Guide

The management side of the public API lets form owners manage forms and submissions programmatically with an API key. All management endpoints live under /papi/v1/management and authenticate with the x-api-key header.

Read the Overview first if you have not — every response uses the standard envelope.

Authentication

Builder requests use an API key sent in the x-api-key header. Create a key in the app under Settings > API Keys (see API Keys).

Scopes:

  • forms:read — read forms (GET endpoints).
  • forms:write — create and modify forms (POST and PATCH endpoints).

Grant the smallest scope set the integration needs.

List Forms

bash
curl https://dash.kinoforms.com/papi/v1/management/forms \
  -H "x-api-key: $KINOFORMS_API_KEY"
json
{
  "data": [
    { "id": "f4d3a2e1-8b7c-4d6e-9a1f-2c3b4d5e6f70", "title": "Contact us", "version": 4 }
  ],
  "apiVersion": "v1",
  "_docs": "https://docs.kinoforms.com/developer/api-reference"
}

Get a Form

bash
curl https://dash.kinoforms.com/papi/v1/management/forms/f4d3a2e1-8b7c-4d6e-9a1f-2c3b4d5e6f70 \
  -H "x-api-key: $KINOFORMS_API_KEY"

The data object includes the form's metadata, its current version, and its fields. Hold on to version if you intend to use optimistic concurrency on a later PATCH.

Create a Form

bash
curl -X POST https://dash.kinoforms.com/papi/v1/management/forms \
  -H "x-api-key: $KINOFORMS_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "title": "Contact us",
    "fields": [
      { "key": "email", "type": "email", "label": "Email", "required": true }
    ]
  }'

Requires forms:write. The response data is the created form, including its new id.

Edit a Form (Diffs-Only PATCH)

You do not replace a whole form to edit it. PATCH /papi/v1/management/forms/{form_id} takes a diffs-only ops array — a list of operations applied in order. This keeps edits small, intent-revealing, and concurrency-safe.

Requires forms:write.

bash
curl -X PATCH https://dash.kinoforms.com/papi/v1/management/forms/f4d3a2e1-8b7c-4d6e-9a1f-2c3b4d5e6f70 \
  -H "x-api-key: $KINOFORMS_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "expectedVersion": 4,
    "ops": [
      { "op": "setMeta", "title": "Contact our team" },
      { "op": "addField", "field": { "key": "phone", "type": "tel", "label": "Phone" } }
    ]
  }'

Request Shape

FieldRequiredDescription
opsyesAn ordered array of operations to apply.
expectedVersionnoIf set, the PATCH only applies when the form's current version matches. See Optimistic concurrency.

Operations Reference

Each op object has an op field naming the operation, plus its arguments.

setMeta

Update form-level metadata (title, description, settings).

json
{ "op": "setMeta", "title": "Contact our team", "description": "We reply within a day." }

addField

Append a new field to the form.

json
{ "op": "addField", "field": { "key": "phone", "type": "tel", "label": "Phone", "required": false } }

updateField

Change properties of an existing field, identified by its key.

json
{ "op": "updateField", "key": "phone", "patch": { "required": true, "label": "Mobile phone" } }

removeField

Delete a field by key.

json
{ "op": "removeField", "key": "phone" }

moveField

Reorder a field to a new position (zero-based index).

json
{ "op": "moveField", "key": "email", "index": 0 }

How Ops Apply

  • Ops apply in array order. Later ops see the result of earlier ops in the same request.
  • The whole array is applied atomically: if any op is invalid, the form is left unchanged and you get a validation_failed error describing the bad op.
  • A successful PATCH returns the updated form (including a bumped version) in data.

Optimistic Concurrency

To avoid clobbering a concurrent edit, send expectedVersion with the version you last read:

json
{ "expectedVersion": 4, "ops": [ /* ... */ ] }
  • If the form's current version is still 4, the PATCH applies and the version becomes 5.
  • If someone else already edited the form (current version is 5), the PATCH is rejected. Re-fetch the form, rebase your ops on the new state, and retry with the new expectedVersion.

Omit expectedVersion for last-write-wins behavior.

Submission Management

Submission management stays inside the form-owner management plane:

  • GET /papi/v1/management/forms/{form_id}/submissions requires submissions:read.
  • GET /papi/v1/management/forms/{form_id}/submissions/{submission_id} requires submissions:read.
  • PATCH /papi/v1/management/forms/{form_id}/submissions/{submission_id} requires submissions:update.
  • DELETE /papi/v1/management/forms/{form_id}/submissions/{submission_id} requires submissions:delete.

Editing uses optimistic concurrency and field-level changes:

bash
curl -X PATCH \
  https://dash.kinoforms.com/papi/v1/management/forms/$FORM_ID/submissions/$SUBMISSION_ID \
  -H "x-api-key: $API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "expectedUpdatedAt": "2026-08-15T10:00:00.000000",
    "edits": [{ "fieldId": "email", "value": "[email protected]" }]
  }'

Every successful change is recorded in the append-only submission edit audit with the API key responsible. submissions:write remains limited to creating submissions and does not authorize editing or deletion.

Errors

Builder errors use the standard envelope. Common codes:

  • unauthorized — missing or invalid API key.
  • missing_scope — the key lacks forms:read / forms:write for this call.
  • validation_failed — a bad op or invalid field definition; see the errors array.
  • rate_limited — slow down and retry after a short delay.

See the Validation reference for the full code list and per-field codes.

KinoForms documentation