Skip to content

Custom fields

Custom fields have two halves:

  1. Definitions — a workspace-level catalog (GET /custom_fields) describing each field: its id, name and kind.
  2. Values — carried on a task, in its custom_fields[] array, when you create (POST /tasks), update (PATCH /tasks/{id}) or read (GET /tasks/{id}) a task.

You read the definition to learn a field’s kind, then send the matching value field on the task.

Where fields come from, and which ones a task can have

Section titled “Where fields come from, and which ones a task can have”

Custom fields are defined once at the workspace level and then linked into individual projects through project settings in the Bordio web app. The API is read-only here: you cannot create a field, edit its options, or link it to a project over the API — workspace admins do that in the web UI.

What this means when you work with tasks:

  • A task can only hold values for custom fields that are linked to its project.
  • The exact set of fields you may set on a given task is whatever GET /custom_fields?project_id=<the task's project_id> returns. Treat that list as the source of truth for “which fields can I update on this task”.
  • Setting a value for a field that is not linked to the task’s project is rejected with 422.
  • A task with no project (workspace-level) cannot have custom fields at all — see project_required below.

So the workflow is always the same: read the project’s fields, then set values only for those fields on tasks in that project. If someone adds or removes a field for the project in the web app, that change is reflected in GET /custom_fields?project_id=... the next time you read it.

Terminal window
curl "https://api.bordio.com/public/v1/custom_fields?project_id=proj_6594a1b2c3d4e5f6a7b8c9d0" \
-H "Authorization: Bearer brd_sk_live_..."
{
"data": [
{ "id": "cf_aaa", "name": "Story points", "kind": "number" },
{ "id": "cf_bbb", "name": "Budget", "kind": "currency" },
{ "id": "cf_ccc", "name": "Release", "kind": "dropdown", "allow_multiple": false,
"options": [
{ "id": "cf_option_x1", "value": "v1.0" },
{ "id": "cf_option_x2", "value": "v2.0" }
] },
{ "id": "cf_ddd", "name": "Owners", "kind": "people", "allow_multiple": true }
]
}
  • kind tells you which value field to use on a task (see the table).
  • allow_multiple is present only for dropdown and people.
  • options is present only for dropdown.
  • Pass ?project_id=proj_... to get the fields available in that project. Without it you get the full workspace catalog. A field must be available in a task’s project to be set on that task.

On a task, each value is one item in custom_fields[]:

{ "custom_field_id": "cf_aaa", "kind": "number", "number_value": 8 }
  • On read (GET /tasks/{id}) every item carries kind and exactly one populated value field. Fields with no value are omitted from the array entirely.
  • On write (POST / PATCH) send custom_field_id + the one value field that matches the field’s kind. You do not need to send kind — it is taken from the definition (if you send it, it is ignored).

Custom field values require the task to belong to a project. Setting them on a workspace-level task (no project_id) fails with 422 validation_error (project_required).

kind Value field Format
text text_value string (≤ 10000 chars)
number number_value number
percent percent_value number, where 75 means 75%
currency currency_value object { "currency": <ISO-4217>, "value": <number> }
date date_value ISO-8601 datetime, or YYYY-MM-DD for date-only
checkbox checkbox_value boolean
email email_value string (≤ 320)
phone phone_value string (≤ 40)
url url_value string (≤ 2048)
dropdown dropdown_value array of option ids (cf_option_...)
people people_value array of user ids (user_...)

The sections below show the write payload and the read shape for each kind.

Plain strings. Differ only in their max length and intent (email/phone/url are not format-validated by the API — store what you send).

// write
{ "custom_field_id": "cf_txt", "text_value": "Needs design review" }
{ "custom_field_id": "cf_eml", "email_value": "ops@acme.com" }
// read
{ "custom_field_id": "cf_txt", "kind": "text", "text_value": "Needs design review" }

Any number (integer or decimal). No unit.

// write
{ "custom_field_id": "cf_pts", "number_value": 8 }
// read
{ "custom_field_id": "cf_pts", "kind": "number", "number_value": 8 }

A percent value is a plain number representing the percentage itself75 means 75%, not 0.75. Decimals are allowed (33.5 → 33.5%).

// write — set progress to 75%
{ "custom_field_id": "cf_prog", "percent_value": 75 }
// read
{ "custom_field_id": "cf_prog", "kind": "percent", "percent_value": 75 }

A currency value is an object, not a number:

{ "currency": "<ISO-4217 code>", "value": <number> }
  • currency — an ISO-4217 code such as USD, EUR, GBP (required).
  • value — the numeric amount (optional; omit it to record a currency without an amount).
// write — set budget to 1990.50 USD
{
"custom_field_id": "cf_budget",
"currency_value": { "currency": "USD", "value": 1990.5 }
}
// read
{
"custom_field_id": "cf_budget",
"kind": "currency",
"currency_value": { "currency": "USD", "value": 1990.5 }
}

ISO-8601 datetime, or YYYY-MM-DD for a date without a time. On read, a date-only value comes back as YYYY-MM-DD; a datetime comes back as a full ISO-8601 timestamp.

// write — date-only
{ "custom_field_id": "cf_due", "date_value": "2026-07-01" }
// write — datetime
{ "custom_field_id": "cf_due", "date_value": "2026-07-01T09:00:00.000Z" }
// read
{ "custom_field_id": "cf_due", "kind": "date", "date_value": "2026-07-01" }

A boolean.

// write
{ "custom_field_id": "cf_billable", "checkbox_value": true }
// read
{ "custom_field_id": "cf_billable", "kind": "checkbox", "checkbox_value": true }

An array of option ids (cf_option_...) taken from the field’s options in its definition. Send a single-element array unless the definition has allow_multiple: true.

// write — single select
{ "custom_field_id": "cf_release", "dropdown_value": ["cf_option_x1"] }
// write — multi select (only if allow_multiple)
{ "custom_field_id": "cf_release", "dropdown_value": ["cf_option_x1", "cf_option_x2"] }
// read
{ "custom_field_id": "cf_release", "kind": "dropdown", "dropdown_value": ["cf_option_x1"] }

Every option id must belong to that field, otherwise the request fails with 422 validation_error (custom_field_invalid_option).

An array of user ids (user_...). Each must be a workspace member. Single-element unless the definition has allow_multiple: true.

// write
{ "custom_field_id": "cf_owners", "people_value": ["user_abc", "user_def"] }
// read
{ "custom_field_id": "cf_owners", "kind": "people", "people_value": ["user_abc", "user_def"] }

Worked example: set several fields on a task

Section titled “Worked example: set several fields on a task”
Terminal window
curl -X PATCH https://api.bordio.com/public/v1/tasks/task_6a2918cff58b0a1d387866ee \
-H "Authorization: Bearer brd_sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"custom_fields": [
{ "custom_field_id": "cf_prog", "percent_value": 75 },
{ "custom_field_id": "cf_budget", "currency_value": { "currency": "USD", "value": 1990.5 } },
{ "custom_field_id": "cf_release","dropdown_value": ["cf_option_x1"] }
]
}'

Reading the task back:

// GET /tasks/task_6a2918cff58b0a1d387866ee
{
"data": {
"id": "task_6a2918cff58b0a1d387866ee",
"title": "Ship the API",
"custom_fields": [
{ "custom_field_id": "cf_prog", "kind": "percent", "percent_value": 75 },
{ "custom_field_id": "cf_budget", "kind": "currency", "currency_value": { "currency": "USD", "value": 1990.5 } },
{ "custom_field_id": "cf_release", "kind": "dropdown", "dropdown_value": ["cf_option_x1"] }
]
}
}

Because custom_fields is replace-on-write, leave a field out of the array to clear it — but remember you must include every other field you want to keep.

// task currently has cf_prog, cf_budget, cf_release.
// This PATCH keeps cf_prog and cf_budget, and clears cf_release:
{
"custom_fields": [
{ "custom_field_id": "cf_prog", "percent_value": 75 },
{ "custom_field_id": "cf_budget", "currency_value": { "currency": "USD", "value": 1990.5 } }
]
}

To clear all custom fields, send "custom_fields": [].

Situation HTTP code
Custom fields set on a task with no project 422 project_required
Dropdown option id not defined on that field 422 custom_field_invalid_option
Field not available in the task’s project 422 validation_error
People value referencing a non-member 422 validation_error

All carry the standard error envelope — see Errors.