Skip to main content
Isometric panels showing draggable attributes, grouped record details, and repeatable entries connected by mint lines.
These endpoints are part of the upcoming record-sections release. Deploy the API with migrations 0135 and 0136 before using them.
Sections are shared object configuration. Integrations define their own business fields; Kato does not infer sections from workspace names or field prefixes. Paths are relative to https://api.getkato.io/v1 and require a developer access key.

Read and save a layout

:object accepts an object ID or slug. GET returns { "data": { "sections": [], "revision": 0 } } for an unconfigured object. PUT replaces the layout and requires the most recently read revision. Preserve sections you want to keep; removing a section retains its saved answers. Successful PUT returns the saved sections and incremented revision. Stale or simultaneous saves return 409; reload and reconcile before retrying. Record-scoped keys cannot write object layouts. A field section uses ordinary object field IDs in display order:
A repeatable section defines child fields once. Child IDs are UUIDs, independent of ordinary object field IDs. Its fieldIds must be empty:
Layouts support up to 50 sections, 200 ordinary fields per field section, and 50 child fields per repeatable section. Titles are required (100 characters maximum); entry names are required (60 maximum). Duplicate fields within a section are invalid, but an ordinary field can appear in multiple sections. Saved section and child-field types cannot be changed in place. Layout bodies are limited to 256 KiB. Child types: text, number, date, email, phone, url, checkbox, select. Select fields define options: [{id, label, color}]; values use option IDs. Fields are optional; null represents an empty value on a new entry. Reimporting an existing ID does not change its values. Dates use YYYY-MM-DD. Values must match the configured type.

Import entries

Configure the repeatable section first, then import source entries using stable IDs:
Use UUID entry IDs. Imported entries belong to exactly one workspace, record and section. A batch accepts up to 100 unique IDs and a 2 MiB body. Values are keyed by child-field ID, never names or slugs. Unknown children or invalid values return 400. Success returns { "data": { "imported": 1 } }. The count means accepted submissions, including previously accepted IDs. This is an insert-only source import: retrying an ID preserves staff edits and removal tombstones. It does not replace all entries or delete entries omitted from a batch. A conflicting ID owned by another record or section returns 409 and rolls back the batch. Record-scoped keys may import only into their pinned record. Missing/deleted records and missing sections return 404. Legacy integrations can explicitly configure repeatable.legacyGroups: [{id, bindings}], where bindings map child UUIDs to object-local scalar field IDs. Populated legacy answers are projected until materialized. Legacy source IDs must be exactly recordId:groupId. This compatibility mechanism is explicit; new integrations should use ordinary UUID entry IDs.

Errors and retries

Route validation, permission, lookup and conflict errors use { "error": { "code": "invalid_request|insufficient_scope|not_found|conflict", "message": "..." } }. Authentication, body-size and rate-limit handling follow the shared API conventions. Retry transient transport errors, 408, 429 and 5xx with the same entry IDs and payload. Treat an incomplete or malformed success response as unacknowledged. Fix 400/403/404/409 causes before retrying. Never regenerate source IDs on a retry.