Custom Fields API
Custom fields allow you to extend Kordon resources with additional attributes specific to your organisation’s needs. All major object types support custom fields: Assets, Business Processes, Controls, Findings, Requirements, Risks, Tasks, and Vendors.
Field Types
Section titled “Field Types”Each custom field has a kind that determines its data type and available configuration options:
| Kind | Display name | Description |
|---|---|---|
string | Short text | Single-line text input |
text | Long text | Multi-line text area |
integer | Number | Whole number with optional min/max range |
boolean | Yes/No | True or false |
date | Date | Date picker with optional past/future restriction |
single_select | Single select | Dropdown with predefined options |
multi_select | Multi select | Multiple selection from predefined options |
url | Link | URL with optional display text |
percentage | Percentage | Number in a configurable range (default 0–100) |
monetary | Currency | Amount with a fixed currency |
file | File upload | File attachment, single or multiple files |
Field Configuration
Section titled “Field Configuration”The configuration object holds type-specific settings. Most types use an empty {}. Types that accept configuration:
integer
{ "min_value": 0, "max_value": 1000}percentage
{ "min_value": 0, "max_value": 100}date
{ "restriction": "past_only"}Accepted values: "past_only", "future_only", or omit the key to allow any date.
single_select and multi_select
Options are managed after creation via the option endpoints. The configuration reflects the current state:
{ "options": [ { "id": "uuid", "label": "Active", "position": 1 }, { "id": "uuid", "label": "Inactive", "position": 2 } ]}url
{ "allowed_protocols": ["http", "https"]}monetary
{ "currency": "EUR"}The currency cannot be changed after the field is created.
file
{ "max_file_size_mb": 25, "allowed_content_types": ["image/*", "application/pdf"], "allow_multiple": false}Visibility and Form Options
Section titled “Visibility and Form Options”| Field | Type | Description |
|---|---|---|
is_shown_in_forms | boolean | Display the field in create and edit forms. Default: false. |
is_shown_in_detail_view | boolean | Display the field in detail and list views. Default: false. |
is_required | boolean | Require the field to be filled before saving. Requires is_shown_in_forms: true. Not supported for boolean fields. Default: false. |
public | boolean | Whether the field appears in public API responses. Default: true. |
Permissions
Section titled “Permissions”Admin and Manager roles can create, update, delete, and reorder custom fields. All authenticated users can read fields and download files attached to file fields.
GET /custom_fields/
Section titled “GET /custom_fields/”List all custom fields in your organisation.
Response Fields
| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier for the custom field |
name | string | Internal field name (lowercase with underscores) |
label | string | Display name shown to users |
description | string | Optional description of the field’s purpose |
kind | string | Field type — see field types |
attribute_of | string | Resource type this field belongs to (e.g. "Asset", "Risk") |
field_has_usage | boolean | Whether any records currently have a value for this field |
is_required | boolean | Whether the field must be filled in |
is_shown_in_forms | boolean | Whether the field appears in create/edit forms |
is_shown_in_detail_view | boolean | Whether the field appears in detail/list views |
public | boolean | Whether the field is visible in public API responses |
configuration | object | Type-specific settings and options |
created_at | timestamp | ISO 8601 creation timestamp |
updated_at | timestamp | ISO 8601 last-updated timestamp |
curl --location GET \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/" \--header "Authorization: Bearer YOUR-TOKEN"Example Response
Status: 200
{ "data": [ { "id": "83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f", "name": "vendor_tier", "label": "Vendor Tier", "description": "", "kind": "single_select", "attribute_of": "Vendor", "field_has_usage": true, "is_required": false, "is_shown_in_forms": true, "is_shown_in_detail_view": true, "public": true, "configuration": { "options": [ { "id": "c1d2e3f4-0000-0000-0000-000000000001", "label": "Gold", "position": 1 }, { "id": "c1d2e3f4-0000-0000-0000-000000000002", "label": "Silver", "position": 2 } ] }, "created_at": "2026-02-20T11:19:53+00:00", "updated_at": "2026-02-20T11:19:53+00:00" } ], "meta": { "total_count": 1, "page": 1, "permissions": { "create": true } }}GET /custom_fields/:id
Section titled “GET /custom_fields/:id”Retrieve a specific custom field. The response includes position, permissions, and for select fields, option_usage_counts — a map of option ID to the number of records currently using that option.
curl --location GET \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f" \--header "Authorization: Bearer YOUR-TOKEN"Example Response
Status: 200
{ "data": { "id": "83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f", "name": "vendor_tier", "label": "Vendor Tier", "description": "", "kind": "single_select", "attribute_of": "Vendor", "field_has_usage": true, "is_required": false, "is_shown_in_forms": true, "is_shown_in_detail_view": true, "public": true, "configuration": { "options": [ { "id": "c1d2e3f4-0000-0000-0000-000000000001", "label": "Gold", "position": 1 }, { "id": "c1d2e3f4-0000-0000-0000-000000000002", "label": "Silver", "position": 2 } ] }, "option_usage_counts": { "c1d2e3f4-0000-0000-0000-000000000001": 42, "c1d2e3f4-0000-0000-0000-000000000002": 15 }, "position": 1, "permissions": { "update": true, "destroy": true }, "created_at": "2026-02-20T11:19:53+00:00", "updated_at": "2026-02-20T11:19:53+00:00" }}POST /custom_fields/
Section titled “POST /custom_fields/”Create a new custom field.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Internal field name (lowercase, underscores only). Auto-generated from label if omitted. Must be unique per resource type. |
label | string | Yes | Display name shown to users. |
kind | string | Yes | Field type — see field types. Cannot be changed once the field has data. |
attribute_of | string | Yes | Resource type: Asset, BusinessProcess, Control, Finding, Requirement, Risk, Task, or Vendor. |
description | string | No | Optional description of the field’s purpose. |
is_required | boolean | No | Whether the field must be filled. Requires is_shown_in_forms: true. Default: false. |
is_shown_in_forms | boolean | No | Display in create/edit forms. Default: false. |
is_shown_in_detail_view | boolean | No | Display in detail/list views. Default: false. |
public | boolean | No | Visible in public API responses. Default: true. |
configuration | object | No | Type-specific settings — see field configuration. |
Example: Creating a single_select field
curl --location POST \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "custom_field": { "label": "Vendor Tier", "kind": "single_select", "attribute_of": "Vendor", "description": "Classification tier for vendor management", "is_shown_in_forms": true, "is_shown_in_detail_view": true }}'Example: Creating a monetary field
curl --location POST \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "custom_field": { "label": "Contract Value", "kind": "monetary", "attribute_of": "Vendor", "is_shown_in_forms": true, "configuration": { "currency": "EUR" } }}'Example Response
Status: 201
{ "data": { "id": "a1b2c3d4-e5f6-7890-a1b2-c3d4e5f67890", "name": "vendor_tier", "label": "Vendor Tier", "description": "Classification tier for vendor management", "kind": "single_select", "attribute_of": "Vendor", "field_has_usage": false, "is_required": false, "is_shown_in_forms": true, "is_shown_in_detail_view": true, "public": true, "configuration": { "options": [] }, "position": 1, "permissions": { "update": true, "destroy": true }, "created_at": "2026-06-01T12:30:45+00:00", "updated_at": "2026-06-01T12:30:45+00:00" }}PATCH /custom_fields/:id
Section titled “PATCH /custom_fields/:id”Update an existing custom field. Only include the fields you want to change.
curl --location PATCH \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "custom_field": { "label": "Vendor Classification", "is_required": true, "is_shown_in_forms": true, "is_shown_in_detail_view": true }}'Example Response
Status: 200
Returns the full custom field object (same shape as the GET single field response).
DELETE /custom_fields/:id
Section titled “DELETE /custom_fields/:id”Delete a custom field. The field is soft-deleted — it is removed from the API but existing record data is retained internally.
curl --location DELETE \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f" \--header "Authorization: Bearer YOUR-TOKEN"Response
Status: 204 No Content
PATCH /custom_fields/:id/reorder
Section titled “PATCH /custom_fields/:id/reorder”Change the display position of a custom field within its resource type. Position is 1-based and is scoped per attribute_of.
curl --location PATCH \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f/reorder" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "position": 3}'Example Response
Status: 200
{ "data": { "id": "83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f", "position": 3 }}Managing Select Options
Section titled “Managing Select Options”single_select and multi_select fields manage their options through dedicated endpoints. Each option has a UUID, a label, and a position within the field.
POST /custom_fields/:id/options
Section titled “POST /custom_fields/:id/options”Add a new option to a select field.
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Display text for the option |
value | string | No | Internal value mapping. Defaults to the label if omitted. |
curl --location POST \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f/options" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "option": { "label": "Gold" }}'Example Response
Status: 201
{ "data": { "option_id": "c1d2e3f4-0000-0000-0000-000000000001", "configuration": { "options": [ { "id": "c1d2e3f4-0000-0000-0000-000000000001", "label": "Gold", "position": 1 } ] } }}PATCH /custom_fields/:id/options/:option_id
Section titled “PATCH /custom_fields/:id/options/:option_id”Rename an existing option. Record values that reference this option are not affected.
curl --location PATCH \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f/options/c1d2e3f4-0000-0000-0000-000000000001" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "option": { "label": "Platinum" }}'Example Response
Status: 200
{ "data": { "option_id": "c1d2e3f4-0000-0000-0000-000000000001", "configuration": { "options": [ { "id": "c1d2e3f4-0000-0000-0000-000000000001", "label": "Platinum", "position": 1 }, { "id": "c1d2e3f4-0000-0000-0000-000000000002", "label": "Silver", "position": 2 } ] } }}DELETE /custom_fields/:id/options/:option_id
Section titled “DELETE /custom_fields/:id/options/:option_id”Delete an option. If any records currently use this option, you must supply a replacement_option_id — those records are updated to the replacement. Deleting an option that is in use without a replacement returns a 422 error.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
replacement_option_id | UUID | Required when records reference this option. Those records are migrated to the replacement. |
curl --location DELETE \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f/options/c1d2e3f4-0000-0000-0000-000000000002?replacement_option_id=c1d2e3f4-0000-0000-0000-000000000001" \--header "Authorization: Bearer YOUR-TOKEN"Example Response
Status: 200
{ "data": { "affected_count": 15, "async": false, "configuration": { "options": [ { "id": "c1d2e3f4-0000-0000-0000-000000000001", "label": "Gold", "position": 1 } ] } }}When affected_count is 100 or more, the migration runs as a background job and "async": true is returned. The option is removed from the field immediately; record updates follow asynchronously.
GET /custom_fields/:id/options/:option_id/usage
Section titled “GET /custom_fields/:id/options/:option_id/usage”Check how many records are currently using a specific option — useful before deleting one.
curl --location GET \--url "https://YOUR_KORDON_DOMAIN/api/v1/custom_fields/83d028c1-9ce1-4f29-ad2b-994c2d0ebd4f/options/c1d2e3f4-0000-0000-0000-000000000001/usage" \--header "Authorization: Bearer YOUR-TOKEN"Example Response
Status: 200
{ "data": { "option_id": "c1d2e3f4-0000-0000-0000-000000000001", "usage_count": 42 }}File Download
Section titled “File Download”For file type fields, files are attached per record. Use these endpoints to retrieve them.
GET /custom_fields/:id/file/:attachment_id
Section titled “GET /custom_fields/:id/file/:attachment_id”Returns a download URL and filename for a specific attachment.
Example Response
Status: 200
{ "data": { "url": "/api/v1/custom_fields/83d028c1.../file/att-uuid/download", "filename": "contract.pdf" }}GET /custom_fields/:id/file/:attachment_id/download
Section titled “GET /custom_fields/:id/file/:attachment_id/download”Streams the file directly. Accepts an optional disposition query parameter: inline (default) or attachment.
Setting Custom Field Values on Resources
Section titled “Setting Custom Field Values on Resources”Once a custom field exists, set its value by including the field’s name as a key in a PATCH request to the corresponding resource endpoint.
Value format by field type
Section titled “Value format by field type”| Kind | Expected value | Example |
|---|---|---|
string | string | "Acme Corp" |
text | string | "Multi-line\ntext here" |
integer | integer | 42 |
boolean | boolean | true |
date | ISO 8601 date string | "2026-12-31" |
single_select | option UUID | "c1d2e3f4-0000-0000-0000-000000000001" |
multi_select | array of option UUIDs | ["c1d2e3f4-...", "c1d2e3f4-..."] |
url | object with url and optional display_text | {"url": "https://example.com", "display_text": "Website"} |
percentage | number | 75.5 |
monetary | number | 12500.00 |
Example: Setting a single_select value on a Risk
curl --location PATCH \--url "https://YOUR_KORDON_DOMAIN/api/v1/risks/RISK_ID" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "risk": { "risk_category": "c1d2e3f4-0000-0000-0000-000000000001" }}'Example: Setting a url field
curl --location PATCH \--url "https://YOUR_KORDON_DOMAIN/api/v1/vendors/VENDOR_ID" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "vendor": { "contract_link": { "url": "https://contracts.example.com/vendor-123", "display_text": "Master Agreement" } }}'Example: Setting multiple custom fields at once
curl --location PATCH \--url "https://YOUR_KORDON_DOMAIN/api/v1/assets/ASSET_ID" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "asset": { "department": "Engineering", "replacement_cost": 15000.00, "last_reviewed": "2026-05-15" }}'Clearing a custom field value
Section titled “Clearing a custom field value”Set the field to null to clear it:
curl --location PATCH \--url "https://YOUR_KORDON_DOMAIN/api/v1/risks/RISK_ID" \--header "Content-Type: application/json" \--header "Authorization: Bearer YOUR-TOKEN" \--data '{ "risk": { "risk_category": null }}'