Multi-Line Text Field

Store longer free-form text — descriptions, notes, logs — on a record with the TEXT_MULTI custom field type.


A multi-line text field stores free-form text that can span several lines, such as descriptions, notes, or logs. It is the TEXT_MULTI value of the CustomFieldType enum. Custom fields are CustomField objects scoped to a workspace (a Workspace in the API); records are Record objects.

TEXT_MULTI and TEXT_SINGLE store and validate text the same way — the difference is the editor the app renders (a multi-line textarea versus a single-line input). Choose TEXT_MULTI when you expect line breaks.

Create

Create the field with createCustomField. The workspace is taken from the blue-workspace-id header — there is no projectId argument.

mutation CreateTextMultiField {
  createCustomField(input: { name: "Notes", type: TEXT_MULTI }) {
    id
    name
    type
  }
}

Pass description to show help text under the field in the app:

mutation CreateDetailedTextMultiField {
  createCustomField(
    input: {
      name: "Notes"
      type: TEXT_MULTI
      description: "Free-form notes and observations about this record."
    }
  ) {
    id
    name
    type
    description
  }
}

CreateCustomFieldInput

ParameterTypeRequiredDescription
nameString!YesDisplay name of the field.
typeCustomFieldType!YesMust be TEXT_MULTI.
descriptionStringNoHelp text shown under the field in the app.

A successful call returns the created CustomField:

{
  "data": {
    "createCustomField": {
      "id": "clm4n8qwx000008l0g4oxdqn7",
      "name": "Notes",
      "type": "TEXT_MULTI"
    }
  }
}

Set a value

Write text to a record with setRecordCustomField, using the text argument. The mutation returns Boolean!true on success — so it takes no selection set.

mutation SetTextMultiValue {
  setRecordCustomField(
    input: {
      todoId: "todo_123"
      customFieldId: "field_123"
      text: "Kickoff call done.\n\nNext: send proposal by Friday."
    }
  )
}
{ "data": { "setRecordCustomField": true } }

SetRecordCustomFieldInput

ParameterTypeRequiredDescription
todoIdString!YesID of the record to write to.
customFieldIdString!YesID of the TEXT_MULTI field.
textStringNoThe text to store. Newlines are preserved. Omit to clear the value.

You can also set the value when creating a record. CreateRecordInput.customFields takes CreateRecordInputCustomField entries ({ customFieldId, value }), where value is the text passed as a string:

mutation CreateRecordWithNotes {
  createRecord(
    input: {
      title: "Acme onboarding"
      todoListId: "list_123"
      customFields: [
        {
          customFieldId: "field_123"
          value: "Kickoff call done.\n\nNext: send proposal by Friday."
        }
      ]
    }
  ) {
    id
    title
  }
}

Read a value

Record.customFields returns CustomField objects directly — there is no junction wrapper type. Read the value on each element. For TEXT_MULTI, the value field resolves to the stored string (the same string is also on the text field).

query GetRecordNotes {
  recordQueries {
    todos(filter: { companyIds: ["company_123"], todoIds: ["todo_123"] }) {
      items {
        id
        title
        customFields {
          name
          type
          text
          value
        }
      }
    }
  }
}
{
  "data": {
    "recordQueries": {
      "todos": {
        "items": [
          {
            "id": "clm4n8qwx000008l0g4oxdqn7",
            "title": "Acme onboarding",
            "customFields": [
              {
                "name": "Notes",
                "type": "TEXT_MULTI",
                "text": "Kickoff call done.\n\nNext: send proposal by Friday.",
                "value": "Kickoff call done.\n\nNext: send proposal by Friday."
              }
            ]
          }
        ]
      }
    }
  }
}

CustomField (record context)

When a CustomField is read through Record.customFields, these fields carry the record’s value:

FieldTypeDescription
nameString!The field’s display name.
typeCustomFieldType!TEXT_MULTI for this field.
textStringThe stored text, including line breaks.
valueJSONThe resolved value — the plain text string for TEXT_MULTI fields.

Notes

  • Text is stored verbatim through the API: no trimming, no length limit beyond the column’s storage capacity, and full Unicode support. Forms applied to the field may trim whitespace and enforce required-ness; the direct API does not.
  • value is only populated when the CustomField is read in a record context (through Record.customFields). On a bare field definition fetched from the customFields query it is null.
  • TEXT_MULTI and TEXT_SINGLE share storage and validation; this parity is current behavior, not a guaranteed contract.

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 in a workspace you can access.
CUSTOM_FIELD_LIMITThe workspace has reached its 30 custom-field limit (raise it by upgrading to Enterprise).
FORBIDDENYour role cannot perform the action — VIEW_ONLY and COMMENT_ONLY roles cannot set field values.