Skip to content

Builder Guide

The builder side of the public API lets you create and edit forms programmatically with an API key. All builder endpoints live under /papi/v1/forms 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://api.kinoforms.com/papi/v1/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://api.kinoforms.com/papi/v1/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://api.kinoforms.com/papi/v1/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/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://api.kinoforms.com/papi/v1/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.

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