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 (GETendpoints).forms:write— create and modify forms (POSTandPATCHendpoints).
Grant the smallest scope set the integration needs.
List Forms
curl https://dash.kinoforms.com/papi/v1/management/forms \
-H "x-api-key: $KINOFORMS_API_KEY"{
"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
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
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.
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
| Field | Required | Description |
|---|---|---|
operations | yes | An ordered array of operations to apply. |
expectedVersion | no | If 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).
{ "op": "setMeta", "name": "Contact our team", "description": "We reply within a day." }addField
Append a new field to the form.
{ "op": "addField", "field": { "id": "phone", "type": "phone", "label": "Phone", "required": false } }updateField
Change properties of an existing field, identified by its id.
{ "op": "updateField", "fieldId": "phone", "set": { "required": true, "label": "Mobile phone" } }removeField
Delete a field by fieldId (the field's id).
{ "op": "removeField", "fieldId": "phone" }moveField
Reorder a field to a new position (zero-based toIndex).
{ "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:
{ "expectedVersion": 4, "operations": [{ "op": "setMeta", "name": "Contact our team" }] }- If
currentVersionis still4, the PATCH can apply; it does not incrementcurrentVersion. - If
currentVersionno 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}/submissionsrequiressubmissions:read.GET /papi/v1/management/forms/{form_id}/submissions/{submission_id}requiressubmissions:read.PATCH /papi/v1/management/forms/{form_id}/submissions/{submission_id}requiressubmissions:update.DELETE /papi/v1/management/forms/{form_id}/submissions/{submission_id}requiressubmissions:delete.
Editing uses optimistic concurrency and field-level changes:
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 lacksforms:read/forms:writefor this call.invalid_body— invalid JSON or a body that does not match the PATCH request shape, such as an unknownopor missing required operation arguments.invalid_content_type— missing or unsupported JSON content type; sendcontent-type: application/json.bad_request— an emptyoperationsarray or a rejected operation argument, such as an emptysetMeta.nameor an attempt to change a field'sidthroughupdateField.not_found— the form is not found, or the target field forupdateField,removeField, ormoveFieldis not found.conflict— anexpectedVersionmismatch or anaddFieldidentifier 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.
