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": {
    "forms": [
      { "id": "f4d3a2e1-8b7c-4d6e-9a1f-2c3b4d5e6f70", "name": "Contact us", "currentVersion": 4 }
    ],
    "pagination": { "page": 1, "limit": 20, "total": 1 }
  },
  "apiVersion": "v1",
  "_docs": "https://docs.kinoforms.com/developer/api-reference",
  "_guide": "https://docs.kinoforms.com/developer/overview"
}

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.form object includes the form's metadata, its currentVersion, and its schema.fields. Use currentVersion for the optional expected version check 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 '{
    "name": "Contact us",
    "schema": {
      "fields": [
        { "id": "email", "type": "email", "label": "Email", "required": true }
      ]
    }
  }'

Requires forms:write. The response data.form is the created draft form, including its new id. Field identifiers live in schema.fields[].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 operations array — a list of operations applied in order. This keeps edits small and intent-revealing.

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,
    "operations": [
      { "op": "setMeta", "name": "Contact our team" },
      { "op": "addField", "field": { "id": "phone", "type": "phone", "label": "Phone" } }
    ]
  }'

Request Shape ​

FieldRequiredDescription
operationsyesAn ordered array of operations to apply.
expectedVersionnoIf set, the PATCH only applies when the form's currentVersion matches. See Expected version check for its limits.

Operations Reference ​

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

setMeta ​

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

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

addField ​

Append a new field to the form.

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

updateField ​

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

json
{ "op": "updateField", "fieldId": "phone", "set": { "required": true, "label": "Mobile phone" } }

removeField ​

Delete a field by fieldId (the field's id).

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

moveField ​

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

json
{ "op": "moveField", "fieldId": "email", "toIndex": 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 an op is rejected, the form is left unchanged. See Errors for rejection codes.
  • A successful PATCH returns the updated form in data.form.

Expected Version Check ​

Send expectedVersion to require a match with the currentVersion you last read:

json
{ "expectedVersion": 4, "operations": [{ "op": "setMeta", "name": "Contact our team" }] }
  • If currentVersion is still 4, the PATCH can apply; it does not increment currentVersion.
  • If currentVersion no longer matches, the PATCH is rejected with a conflict. Re-fetch the form and review its current state before retrying.

Publishing advances currentVersion. Draft PATCH edits do not, so expectedVersion does not detect another draft edit. Two PATCH requests with the same expectedVersion can both succeed.

Omitting expectedVersion skips this check.

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.
  • invalid_body — invalid JSON or a body that does not match the PATCH request shape, such as an unknown op or missing required operation arguments.
  • invalid_content_type — missing or unsupported JSON content type; send content-type: application/json.
  • bad_request — an empty operations array or a rejected operation argument, such as an empty setMeta.name or an attempt to change a field's id through updateField.
  • not_found — the form is not found, or the target field for updateField, removeField, or moveField is not found.
  • conflict — an expectedVersion mismatch or an addField identifier that already exists.
  • rate_limited — slow down and retry after a short delay.

PATCH checks operation arguments and field identifiers; it does not fully validate every field definition. PATCH failures do not necessarily include an errors array. Submission validation failures can return validation_failed with per-field errors.

See the Validation reference for top-level API codes and per-field response validation codes.

KinoForms documentation