Create a Custom Field

Add a custom field to a workspace with type-specific configuration via the createCustomField mutation.


Use the createCustomField mutation to add a structured data field to a workspace. Custom fields are CustomField objects scoped to a single workspace (a Project in the API). The new field is created at the end of the workspace’s field list and becomes available on every record (Todo) immediately.

The field’s behavior is driven by its type (a CustomFieldType enum value). Each type reads a different subset of the input — for example a CURRENCY field uses currency/min/max, a REFERENCE field uses referenceProjectId, and a LOOKUP field uses lookupOption. See Field Types below for the per-type configuration.

The target workspace comes from the blue-workspace-id request header, not from the input — there is no projectId field on CreateCustomFieldInput.

POST https://api.blue.app/graphql
blue-token-id: YOUR_TOKEN_ID
blue-token-secret: YOUR_TOKEN_SECRET
blue-org-id: YOUR_ORG_ID
blue-workspace-id: project_123

Company and project headers accept an ID or a slug. Header names are case-insensitive. See Authentication for the full header reference.

Request

The smallest call that works: a single-line text field. Only name and type are required.

mutation CreateTextField {
  createCustomField(input: { name: "Customer Name", type: TEXT_SINGLE }) {
    id
    uid
    name
    type
    position
  }
}

Parameters

CreateCustomFieldInput

ParameterTypeRequiredApplies toDescription
nameString!YesallDisplay name of the field, as shown in the workspace.
typeCustomFieldType!YesallThe field type. See Field Types.
descriptionStringNoallOptional help text explaining the field.
minFloatNoNUMBER, CURRENCY, PERCENT, RATINGMinimum allowed value.
maxFloatNoNUMBER, CURRENCY, PERCENT, RATINGMaximum allowed value.
currencyStringNoCURRENCYISO 4217 currency code, e.g. "USD".
prefixStringNoUNIQUE_IDText prepended to each generated identifier.
useSequenceUniqueIdBooleanNoUNIQUE_IDGenerate sequential numbers instead of random IDs.
sequenceDigitsIntNoUNIQUE_IDZero-padded width of the sequence (e.g. 500001).
sequenceStartingNumberIntNoUNIQUE_IDFirst number in the sequence.
isDueDateBooleanNoDATETreat this date field as the record’s due date.
formulaJSONNoFORMULAFormula configuration.
urlDisplayAsButtonBooleanNoURLRender the URL as a clickable button.
urlButtonLabelStringNoURLButton label when urlDisplayAsButton is true.
urlButtonColorStringNoURLButton color (hex) when displayed as a button.
buttonTypeStringNoBUTTONAction the button performs.
buttonConfirmTextStringNoBUTTONConfirmation prompt shown before the action runs.
buttonColorStringNoBUTTONButton color (hex).
currencyFieldIdStringNoCURRENCY_CONVERSIONThe source CURRENCY field to convert from.
conversionDateStringNoCURRENCY_CONVERSIONExchange-rate date.
conversionDateTypeStringNoCURRENCY_CONVERSIONHow the conversion date is resolved.
referenceProjectIdStringNo*REFERENCEWorkspace to link records from. Required for REFERENCE.
referenceMultipleBooleanNoREFERENCEAllow linking more than one record.
referenceFilterTodoFilterInputNoREFERENCERestrict which records can be linked.
lookupOptionCustomFieldLookupOptionInputNo*LOOKUPLookup configuration. Required for LOOKUP.
referencedByOptionCustomFieldReferencedByOptionInputNoREFERENCED_BYReverse-reference configuration.
rollupOptionCustomFieldRollupOptionInputNo*ROLLUPRollup aggregation configuration. Required for ROLLUP.
assigneeMultipleBooleanNoASSIGNEEAllow assigning more than one person.
assigneeNotifyOnAssignBooleanNoASSIGNEENotify users when assigned via this field.
allowedUserIds[String!]NoASSIGNEERestrict assignable users to these user IDs.
allowedRoleIds[String!]NoASSIGNEERestrict assignable users to these custom-role IDs.
allowedLevels[UserAccessLevel!]NoASSIGNEERestrict assignable users to these access levels.
timeDurationDisplayCustomFieldTimeDurationDisplayTypeNo*TIME_DURATIONDisplay format. Required for TIME_DURATION.
timeDurationTargetTimeFloatNoTIME_DURATIONTarget duration, in seconds.
timeDurationStartInputCustomFieldTimeDurationInputNo*TIME_DURATIONStart trigger. Required for TIME_DURATION.
timeDurationEndInputCustomFieldTimeDurationInputNo*TIME_DURATIONEnd trigger. Required for TIME_DURATION.
enableBulkActionBooleanNosupported typesEnable bulk-set across records. Rejected for unsupported types.

* Schema-optional, but the resolver requires it for the listed type and returns BAD_USER_INPUT if omitted. See Errors.

SELECT_SINGLE and SELECT_MULTI take no inline options — create the field first, then add options with createCustomFieldOptions.

Response

{
  "data": {
    "createCustomField": {
      "id": "clm4n8qwx000008l0g4oxdqn7",
      "uid": "cf_8h2k9d",
      "name": "Customer Name",
      "type": "TEXT_SINGLE",
      "position": 16384
    }
  }
}

Returns

createCustomField returns the created CustomField. Commonly selected fields:

FieldTypeDescription
idID!Unique identifier of the field.
uidString!Short public identifier.
nameString!Display name.
typeCustomFieldType!The field type.
positionFloat!Sort position within the workspace (auto-assigned at the end).
descriptionStringHelp text, if set.
createdAtDateTime!Creation timestamp.
updatedAtDateTime!Last update timestamp.
min / maxFloatConfigured bounds (numeric types).
currencyStringCurrency code (CURRENCY type).
prefixStringID prefix (UNIQUE_ID type).
isDueDateBooleanDue-date flag (DATE type).
formulaJSONFormula config (FORMULA type).
referenceProjectProjectLinked workspace (REFERENCE type).
customFieldLookupOptionCustomFieldLookupOptionLookup config (LOOKUP type).
customFieldReferencedByOptionCustomFieldReferencedByOptionReverse-reference config (REFERENCED_BY type).
customFieldRollupOptionCustomFieldRollupOptionRollup config (ROLLUP type).

Field Types

CustomFieldType has 26 values. Most types are created with just name + type; the table notes the extra input each type reads.

typeStoresExtra input
TEXT_SINGLESingle-line text
TEXT_MULTIMulti-line text
SELECT_SINGLEOne choice from a listOptions created separately
SELECT_MULTIMultiple choices from a listOptions created separately
CHECKBOXBoolean
RATINGStar ratingmax (defaults to 5)
PHONEPhone number
NUMBERNumbermin, max
CURRENCYMoney amountcurrency, min, max
PERCENTPercentagemin, max
EMAILEmail address
URLWeb linkurlDisplayAsButton, urlButtonLabel, urlButtonColor
UNIQUE_IDAuto-generated identifierprefix, useSequenceUniqueId, sequenceDigits, sequenceStartingNumber
LOCATIONGeographic coordinates
FILEFile attachments
COUNTRYCountry
DATEDateisDueDate
FORMULACalculated valueformula (required)
REFERENCELinks to records in another workspacereferenceProjectId (required), referenceMultiple, referenceFilter
LOOKUPPulled value from a referenced recordlookupOption (required)
REFERENCED_BYRecords that reference this onereferencedByOption
ROLLUPAggregate over referenced recordsrollupOption (required)
TIME_DURATIONElapsed time between two eventstimeDurationDisplay, timeDurationStartInput, timeDurationEndInput (all required)
BUTTONAction triggerbuttonType, buttonConfirmText, buttonColor
CURRENCY_CONVERSIONConverted currency valuecurrencyFieldId, conversionDate, conversionDateType
ASSIGNEEAssigned peopleassigneeMultiple, assigneeNotifyOnAssign, allowedUserIds, allowedRoleIds, allowedLevels

Each type has a dedicated page with set/read examples — see Related.

Full examples

Number field with bounds

mutation CreateQuantityField {
  createCustomField(input: { name: "Quantity", type: NUMBER, min: 1, max: 999 }) {
    id
    name
    min
    max
  }
}

Currency field

mutation CreateBudgetField {
  createCustomField(input: { name: "Budget", type: CURRENCY, currency: "EUR", min: 0 }) {
    id
    name
    currency
  }
}

Date field flagged as the due date

mutation CreateDeadlineField {
  createCustomField(input: { name: "Deadline", type: DATE, isDueDate: true }) {
    id
    name
    isDueDate
  }
}

Reference field

Links records to records in another workspace, restricted with referenceFilter (a TodoFilterInput).

mutation CreateDependenciesField {
  createCustomField(
    input: {
      name: "Dependencies"
      type: REFERENCE
      referenceProjectId: "project_123"
      referenceMultiple: true
      referenceFilter: { todoListIds: ["list_123"], showCompleted: false }
    }
  ) {
    id
    name
    referenceMultiple
    referenceProject {
      id
      name
    }
  }
}

Lookup field

Pulls a value from records linked by a REFERENCE field. Point referenceId at the REFERENCE field’s ID and lookupType at what to read; for TODO_CUSTOM_FIELD, also set lookupId to the source field’s ID.

mutation CreateLookupField {
  createCustomField(
    input: {
      name: "Customer Email"
      type: LOOKUP
      lookupOption: {
        referenceId: "field_123"
        lookupId: "field_456"
        lookupType: TODO_CUSTOM_FIELD
      }
    }
  ) {
    id
    name
    customFieldLookupOption {
      lookupType
      reference {
        id
        name
      }
      lookup {
        id
        name
      }
    }
  }
}

Rollup field

Aggregates a field across the records reached through a REFERENCE or REFERENCED_BY field. Rollup fields require a Pro subscription.

mutation CreateTotalField {
  createCustomField(
    input: {
      name: "Total Order Value"
      type: ROLLUP
      rollupOption: {
        sourceType: REFERENCE_FIELD
        sourceFieldId: "field_123"
        aggregateFieldId: "field_456"
        aggregationFunction: SUM
      }
    }
  ) {
    id
    name
    customFieldRollupOption {
      sourceType
      aggregationFunction
    }
  }
}

Assignee field

A custom assignee field, optionally limited to a set of users, roles, or access levels.

mutation CreateReviewerField {
  createCustomField(
    input: {
      name: "Reviewer"
      type: ASSIGNEE
      assigneeMultiple: false
      assigneeNotifyOnAssign: true
      allowedLevels: [ADMIN, MEMBER]
    }
  ) {
    id
    name
    assigneeMultiple
    allowedLevels
  }
}

Unique ID with a sequence

mutation CreateOrderNumberField {
  createCustomField(
    input: {
      name: "Order Number"
      type: UNIQUE_ID
      prefix: "ORD-"
      useSequenceUniqueId: true
      sequenceDigits: 6
      sequenceStartingNumber: 1000
    }
  ) {
    id
    name
    prefix
  }
}

Sequence numbers are assigned by a background job, so existing records receive their IDs shortly after creation.

Time-duration field

Measures elapsed time between a start and end event. Both ends take a CustomFieldTimeDurationInput.

mutation CreateTimeToResolution {
  createCustomField(
    input: {
      name: "Time to Resolution"
      type: TIME_DURATION
      timeDurationDisplay: FULL_DATE_STRING
      timeDurationStartInput: { type: TODO_CREATED_AT, condition: FIRST }
      timeDurationEndInput: { type: TODO_MARKED_AS_COMPLETE, condition: LAST }
    }
  ) {
    id
    name
  }
}

Adding select options

SELECT_SINGLE and SELECT_MULTI fields have no choices until you add them. Create the field, then call createCustomFieldOptions with the new field’s id. It takes one CreateCustomFieldOptionsInput and returns [CustomFieldOption!].

mutation CreateSelectOptions {
  createCustomFieldOptions(
    input: {
      customFieldId: "field_123"
      customFieldOptions: [
        { title: "High", color: "#FF0000", position: 1 }
        { title: "Medium", color: "#FFA500", position: 2 }
        { title: "Low", color: "#00FF00", position: 3 }
      ]
    }
  ) {
    id
    title
    color
    position
  }
}

color and position are optional on each CustomFieldOptionInput. To add a single option, use the singular createCustomFieldOption mutation, which takes customFieldId directly in its input.

Nested input reference

TodoFilterInput

Used by referenceFilter to restrict which records a REFERENCE field can link. All fields are optional; common ones:

FieldTypeDescription
todoListIds[String!]Limit to records in these lists.
tagIds[String!]Limit to records carrying these tags.
assigneeIds[String!]Limit to records assigned to these users.
showCompletedBooleanInclude completed records (default excludes them).
recordNameStringMatch by record name.

TodoFilterInput carries many more fields (date ranges, negation arrays, nested groups). See List Records for the full filter surface.

CustomFieldLookupOptionInput

FieldTypeRequiredDescription
referenceIdString!YesID of the REFERENCE field this lookup reads through.
lookupTypeCustomFieldLookupType!YesWhat to pull from the referenced record.
lookupIdStringNoSource field ID — required when lookupType is TODO_CUSTOM_FIELD.

CustomFieldLookupType values: TODO_DUE_DATE, TODO_CREATED_AT, TODO_UPDATED_AT, TODO_TAG, TODO_ASSIGNEE, TODO_DESCRIPTION, TODO_LIST, TODO_CUSTOM_FIELD. The TODO_REFERENCED_BY value is deprecated — create a REFERENCED_BY field and point a LOOKUP at it instead.

CustomFieldReferencedByOptionInput

Configures a REFERENCED_BY field. All fields are optional; omit them to surface every record that references the current one.

FieldTypeDescription
referencingProjectIdStringLimit to records in this workspace. Must belong to the same organization.
referencingFieldIdStringLimit to records linked through this specific REFERENCE field. Requires referencingProjectId.
filtersTodoFilterInputRestrict which referencing records count.

CustomFieldRollupOptionInput

FieldTypeRequiredDescription
sourceTypeRollupSourceType!YesREFERENCE_FIELD or REFERENCED_BY_FIELD.
aggregationFunctionRollupAggregationFunction!YesSUM, AVERAGE, COUNT, COUNTA, MIN, MAX, or ARRAYJOIN.
sourceFieldIdStringNoThe REFERENCE/REFERENCED_BY field to traverse.
aggregateFieldIdStringNoThe field on the related records to aggregate.
filtersTodoFilterInputNoRestrict which related records are included.

CustomFieldTimeDurationInput

FieldTypeRequiredDescription
typeCustomFieldTimeDurationType!YesThe event that triggers this end of the duration.
conditionCustomFieldTimeDurationCondition!YesFIRST or LAST occurrence of the event.
customFieldIdStringNoField to watch when type is TODO_CUSTOM_FIELD.
customFieldOptionIds[String!]NoOption(s) that trigger the event.
todoListIdStringNoList to watch when type is TODO_MOVED.
tagIdStringNoTag to watch when type is TODO_TAG_ADDED.
assigneeIdStringNoUser to watch when type is TODO_ASSIGNEE_ADDED.

CustomFieldTimeDurationType values: TODO_CREATED_AT, TODO_CUSTOM_FIELD, TODO_DUE_DATE, TODO_MARKED_AS_COMPLETE, TODO_MOVED, TODO_TAG_ADDED, TODO_ASSIGNEE_ADDED.

CustomFieldTimeDurationCondition values: FIRST, LAST.

CustomFieldTimeDurationDisplayType values: FULL_DATE, FULL_DATE_STRING, FULL_DATE_SUBSTRING.

Errors

CodeWhen
FORBIDDENThe caller is not an OWNER or ADMIN of the workspace, or the workspace is inactive.
PLAN_LIMIT_REACHEDThe workspace has hit its custom-field limit, or the organization is locked.
PRO_REQUIREDA ROLLUP field was requested without a Pro subscription.
BAD_USER_INPUTA type-specific requirement was not met — e.g. REFERENCE without referenceProjectId, LOOKUP without lookupOption, ROLLUP without rollupOption, TIME_DURATION missing display/start/end, or enableBulkAction on an unsupported type.
PROJECT_NOT_FOUNDreferenceProjectId (or a REFERENCED_BY referencing project) does not exist or the caller has no access to it.

Permissions

Creating a custom field requires OWNER or ADMIN access to the workspace, and the workspace must be active. MEMBER, CLIENT, COMMENT_ONLY, and VIEW_ONLY roles cannot create fields. ROLLUP fields additionally require the organization to be on a Pro plan.