Set Custom Field Values

Write values to custom fields on a record with the type-specific parameter each field expects.


Use the setRecordCustomField mutation to write a value to a custom field on a single record. The mutation is an upsert: it creates the value if the field is empty on that record, or overwrites the existing value. Records are Record objects in the API; custom fields are CustomField objects, scoped to a workspace.

Each field type reads a different parameter from the input (text, number, option IDs, assignee IDs, and so on). Send only the parameter that matches the field’s type — see the Value reference below. To set values on many records at once, use bulkSetCustomField instead.

Request

setRecordCustomField takes a single SetRecordCustomFieldInput and returns Boolean!.

mutation SetTextField {
  setRecordCustomField(
    input: {
      todoId: "todo_123"
      customFieldId: "field_123"
      text: "Project specification document"
    }
  )
}

Send these headers with every request. blue-workspace-id accepts a workspace ID or slug.

blue-token-id: YOUR_TOKEN_ID
blue-token-secret: YOUR_TOKEN_SECRET
blue-org-id: YOUR_ORG_ID
blue-workspace-id: project_123

Parameters

SetRecordCustomFieldInput

todoId and customFieldId are always required. Beyond those, supply only the value parameter that matches the field’s type.

ParameterTypeRequiredDescription
todoIdString!YesThe record to write to.
customFieldIdString!YesThe custom field to set. Must belong to the same workspace as the record.
textStringNoValue for TEXT_SINGLE, TEXT_MULTI, PHONE, EMAIL, URL.
numberFloatNoValue for NUMBER, PERCENT, RATING, CURRENCY, TIME_DURATION.
currencyStringNoISO 4217 currency code for a CURRENCY field (e.g. "USD"), paired with number.
checkedBooleanNoValue for CHECKBOX.
startDateDateTimeNoStart of a DATE field (or the single date).
endDateDateTimeNoEnd of a DATE range.
timezoneStringNoIANA timezone for a DATE field (e.g. "America/New_York").
latitudeFloatNoLatitude for a LOCATION field, paired with longitude.
longitudeFloatNoLongitude for a LOCATION field.
regionCodeStringNoISO region code for a PHONE field (e.g. "US").
countryCodes[String!]NoISO 3166 country codes for a COUNTRY field.
customFieldOptionIdStringNoSelected option for a SELECT_SINGLE field.
customFieldOptionIds[String!]NoSelected options for a SELECT_MULTI field.
customFieldReferenceTodoIds[String!]NoLinked record IDs for a REFERENCE field.
assigneeUserIds[String!]NoUser IDs for an ASSIGNEE field.

Response

The mutation returns true on success.

{
  "data": {
    "setRecordCustomField": true
  }
}

To read the value back, query the record’s customFields. Record.customFields returns [CustomField!]! directly — the value lives on each element, with no wrapper object.

query ReadFieldValue {
  recordQueries {
    todos(filter: { companyIds: ["company_123"], todoIds: ["todo_123"] }) {
      items {
        id
        customFields {
          id
          name
          type
          text
          number
          checked
          selectedOption {
            title
          }
          value
        }
      }
    }
  }
}

Field type examples

Number

mutation SetNumber {
  setRecordCustomField(input: { todoId: "todo_123", customFieldId: "field_123", number: 15000.5 })
}

Single-select and multi-select

Pass customFieldOptionId for a SELECT_SINGLE field and customFieldOptionIds for a SELECT_MULTI field.

mutation SetSelect {
  single: setRecordCustomField(
    input: { todoId: "todo_123", customFieldId: "field_123", customFieldOptionId: "option_123" }
  )
  multi: setRecordCustomField(
    input: {
      todoId: "todo_123"
      customFieldId: "field_456"
      customFieldOptionIds: ["option_123", "option_456"]
    }
  )
}

Date and date range

A single date uses startDate only; a range adds endDate.

mutation SetDateRange {
  setRecordCustomField(
    input: {
      todoId: "todo_123"
      customFieldId: "field_123"
      startDate: "2026-01-01T00:00:00Z"
      endDate: "2026-03-31T23:59:59Z"
      timezone: "America/New_York"
    }
  )
}

Assignee

ASSIGNEE fields take assigneeUserIds. Every user must be eligible for the field (an allowed user, role, or access level), and a single-assignee field rejects more than one ID.

mutation SetAssignee {
  setRecordCustomField(
    input: {
      todoId: "todo_123"
      customFieldId: "field_123"
      assigneeUserIds: ["user_123", "user_456"]
    }
  )
}

Location

mutation SetLocation {
  setRecordCustomField(
    input: {
      todoId: "todo_123"
      customFieldId: "field_123"
      latitude: 37.7749
      longitude: -122.4194
    }
  )
}

Currency

A CURRENCY field stores an amount (number) and a currency code (currency).

mutation SetCurrency {
  setRecordCustomField(
    input: { todoId: "todo_123", customFieldId: "field_123", number: 5000, currency: "USD" }
  )
}

Reference

REFERENCE fields link to records in the field’s target workspace. Send the full set of linked record IDs each time — IDs you omit are unlinked.

mutation SetReference {
  setRecordCustomField(
    input: {
      todoId: "todo_123"
      customFieldId: "field_123"
      customFieldReferenceTodoIds: ["todo_456", "todo_789"]
    }
  )
}

Clearing a value

setRecordCustomField reconciles option, reference, and assignee links by comparing the IDs you send against what is already stored — anything you omit is removed. To clear a multi-value field, re-send it with an empty array:

mutation ClearAssignees {
  setRecordCustomField(input: { todoId: "todo_123", customFieldId: "field_123", assigneeUserIds: [] })
}

For scalar fields (text, number, checked), send the empty/false value to reset it.

Files

File fields use their own mutations rather than setRecordCustomField. Upload the file first (see Upload files) to obtain a fileUid, then attach it. Both mutations return Boolean.

mutation AttachFile {
  createRecordCustomFieldFile(
    input: { todoId: "todo_123", customFieldId: "field_123", fileUid: "file_123" }
  )
}

mutation DetachFile {
  deleteRecordCustomFieldFile(
    input: { todoId: "todo_123", customFieldId: "field_123", fileUid: "file_123" }
  )
}

CreateRecordCustomFieldFileInput / DeleteRecordCustomFieldFileInput

Both inputs share the same three required fields.

ParameterTypeRequiredDescription
todoIdString!YesThe record holding the FILE custom field.
customFieldIdString!YesThe FILE custom field.
fileUidString!YesThe uploaded file’s UID, from the upload step.

Setting values during record creation

createRecord accepts a customFields array so you can seed values when the record is created. Each entry is a CreateRecordInputCustomField with a customFieldId and a stringified value.

mutation CreateRecordWithFields {
  createRecord(
    input: {
      todoListId: "list_123"
      title: "New Feature Development"
      customFields: [
        { customFieldId: "field_123", value: "high" }
        { customFieldId: "field_456", value: "8" }
      ]
    }
  ) {
    id
    title
    customFields {
      id
      name
      value
    }
  }
}

For anything beyond simple scalar seeding (options, references, assignees, dates), create the record first, then call setRecordCustomField per field with the type-specific parameters above.

Errors

CodeWhen
CUSTOM_FIELD_NOT_FOUNDThe customFieldId does not exist or is not in a workspace you can access.
TODO_NOT_FOUNDThe todoId does not exist or is not visible to you.
FORBIDDENYou lack edit access to the record, or your custom role marks this field as non-editable.
BAD_USER_INPUTThe field is computed (FORMULA, LOOKUP, ROLLUP, REFERENCED_BY), the field belongs to a different workspace than the record, an option/reference/assignee ID is invalid, or an assignee is ineligible.
{
  "errors": [
    {
      "message": "ROLLUP fields are computed and cannot be set directly.",
      "extensions": { "code": "BAD_USER_INPUT" }
    }
  ]
}

Permissions

Writing a value requires edit access to the record. Members and clients can set values unless a custom role restricts them. When the caller has a custom project role, the API runs a two-tier check: it confirms workspace access, then confirms the specific field is marked editable in that role. A user can therefore have general workspace access yet be blocked from editing a particular field.

Value reference

Send the parameter listed for the field’s type. Computed types reject writes with BAD_USER_INPUT.

Field typeParameterNotes
TEXT_SINGLEtextPlain string.
TEXT_MULTItextString; newlines preserved.
NUMBERnumberFloat.
CURRENCYnumber + currencyAmount plus ISO 4217 code.
PERCENTnumberFloat.
RATINGnumberWithin the field’s min/max.
TIME_DURATIONnumberDuration value.
CHECKBOXcheckedBoolean.
DATEstartDate (+ endDate, timezone)ISO 8601; add endDate for a range.
SELECT_SINGLEcustomFieldOptionIdOne option ID.
SELECT_MULTIcustomFieldOptionIdsArray of option IDs.
PHONEtext (+ regionCode)E.164 string; regionCode for formatting.
EMAILtextEmail string.
URLtextURL string.
LOCATIONlatitude + longitudeFloats.
COUNTRYcountryCodesArray of ISO 3166 codes.
REFERENCEcustomFieldReferenceTodoIdsArray of record IDs in the target workspace.
ASSIGNEEassigneeUserIdsArray of user IDs; eligibility enforced.
FILEUse createRecordCustomFieldFile / deleteRecordCustomFieldFile.
BUTTONTriggers automations when clicked; not set via this mutation.
UNIQUE_IDSystem-generated; read-only.
FORMULAComputed from other fields; read-only.
LOOKUPPulled from a referenced record; read-only.
ROLLUPAggregated from linked records; read-only.
REFERENCED_BYThe inverse of a REFERENCE link; read-only.
CURRENCY_CONVERSIONComputed from a referenced CURRENCY field; read-only.

CURRENCY does not auto-convert: it just stores an amount and a code. Conversion happens only when a separate CURRENCY_CONVERSION field references that CURRENCY field.