Create and manage charts

Create STAT, PIE, and BAR charts on a dashboard, then rename, reposition, restyle, duplicate, and delete them.


A chart is a single card on a dashboard. This page covers the full lifecycle: create a chart with createChart, change its title, position, display, or metadata with editChart, duplicate it into the same or another dashboard with copyChart, and remove it with deleteChart. Charts are Chart objects in the API.

Every chart is either a manual chart (driven by chartSegments — formulas over project-scoped values) or an auto-generated chart (driven by metadata.barChart or metadata.pieChart). createChart accepts either shape; the segment and value mutations apply only to manual charts. See the section overview for the full type map.

Results are calculated asynchronously

createChart and copyChart enqueue a background calculation rather than returning final chart data. The returned Chart reflects pending state via isCalculating, needCalculation, and isCalculatingWithFilter; final results arrive through the subscribeToChart subscription, not synchronously from the mutation.

createChart

Use the createChart mutation to add a chart to a dashboard.

Request

The smallest call creates an empty STAT chart. You build out its segments afterward with createChartSegment.

mutation CreateChart {
  createChart(input: { dashboardId: "dashboard_123", title: "Open records", type: STAT }) {
    id
    title
    type
    position
    isCalculating
    needCalculation
  }
}

Parameters

CreateChartInput

ParameterTypeRequiredDescription
dashboardIdString!YesDashboard the chart belongs to. You must be its creator or hold the EDITOR role.
titleString!YesDisplay title of the chart.
typeChartType!YesSTAT, PIE, or BAR.
positionFloatNoSort position within the dashboard. Omit to append after the last chart (see Position defaults).
displayFormulaDisplayInputNoHow the chart’s value is formatted (number/currency/percentage) and the optional display rollup function.
chartSegments[ChartSegmentInput!]NoInline segments for a manual chart. Mutually exclusive with metadata. Each segment carries a formula and its values — see below.
metadataChartMetadataInputNoA barChart or pieChart spec for an auto-generated chart. Mutually exclusive with chartSegments.

ChartType

ValueDescription
STATA single headline number (one segment value, or a formula rollup).
PIEA pie chart — either manual segments or a pieChart group-by/value.
BARA bar chart — either manual segments or a barChart x-axis/y-axis.

FormulaDisplayInput

ParameterTypeRequiredDescription
typeFormulaDisplayType!YesNUMBER, CURRENCY, or PERCENTAGE.
currencyFormulaDisplayCurrencyInputNo{ code, name }, e.g. { code: "USD", name: "US Dollar" }. Use with CURRENCY.
precisionFloatNoNumber of decimal places to show.
functionChartFunctionNoDisplay rollup applied across the chart. See ChartFunction.

ChartMetadataInput

Supply exactly one of barChart or pieChart for an auto-generated chart.

ParameterTypeRequiredDescription
barChartBarChartMetadataInputNoAn x-axis/y-axis spec. Use for BAR charts.
pieChartPieChartMetadataInputNoA group-by/value spec. Use for PIE charts.

BarChartMetadataInput is { xAxis: BarChartXAxisInput!, yAxis: BarChartYAxisInput! }; PieChartMetadataInput is { groupBy: PieChartGroupByInput!, value: PieChartValueInput! }. The axis inputs share a common shape:

FieldTypeWhereDescription
titleStringall axesOptional axis label.
typeBarChartXAxisType!xAxis / groupByWhat to bucket records by: PROJECT, ASSIGNEE, TAG, CUSTOM_FIELD, TODO_LIST, TODO_STATUS, TODO_DUE_DATE, TODO_CREATED_AT, TODO_UPDATED_AT, TODO_COMPLETED_AT.
intervalBarChartXAxisIntervalxAxis onlyBucket size for date axes: DAY, WEEK, MONTH, QUARTER, YEAR.
functionChartSegmentValueFunctionsyAxis / valueAggregate applied to the measured records.
filterTodoFilterInputyAxis / valueNarrows which records are measured. Same filter used by list records.
customFieldNameStringall axesCustom-field name when type is CUSTOM_FIELD.
customFieldTypeCustomFieldTypeall axesType of that custom field.
customFieldReferenceProjectIdStringall axesFor reference custom fields, the referenced project.

For chartSegments (manual charts), the segment and value input fields are documented on Build chart segments and values; the example below shows the inline form.

Response

{
  "data": {
    "createChart": {
      "id": "clm4n8qwx000008l0g4oxdqn7",
      "title": "Open records",
      "type": "STAT",
      "position": 65535,
      "isCalculating": true,
      "needCalculation": true
    }
  }
}

Returns

createChart returns the new Chart.

FieldTypeDescription
idID!Unique identifier of the chart.
titleString!Chart title.
positionFloat!Sort position within the dashboard.
typeChartType!STAT, PIE, or BAR.
chartSegments[ChartSegment!]!Manual segments. Empty for an auto-generated chart.
metadataChartMetadataThe barChart/pieChart spec for an auto-generated chart. null for a manual chart.
displayFormulaDisplayDisplay formatting (type, currency, precision, function).
isCalculatingBooleanA recompute is currently in progress.
needCalculationBooleanResults are stale or pending — a calculation is queued.
isCalculatingWithFilterBooleanSet transiently when the chart is read through charts(filter.todoFilter).
createdAtDateTime!When the chart was created.
updatedAtDateTime!When the chart was last modified.

Full example

Create an auto-generated BAR chart that counts records by workspace, formatted as a whole number.

mutation CreateBarChart {
  createChart(
    input: {
      dashboardId: "dashboard_123"
      title: "Records per workspace"
      type: BAR
      display: { type: NUMBER, precision: 0 }
      metadata: {
        barChart: {
          xAxis: { title: "Workspace", type: PROJECT }
          yAxis: { title: "Records", function: COUNT }
        }
      }
    }
  ) {
    id
    title
    type
    metadata {
      ... on ChartMetadataBarChart {
        barChart {
          xAxis {
            title
            type
          }
          yAxis {
            title
            function
          }
        }
      }
    }
    needCalculation
  }
}

To create a manual chart instead, pass chartSegments (and omit metadata). Each segment carries a formula whose logic.text/logic.html reference its values by their uid:

mutation CreateManualChart {
  createChart(
    input: {
      dashboardId: "dashboard_123"
      title: "Won vs. lost"
      type: PIE
      chartSegments: [
        {
          title: "Won deals"
          color: "#22c55e"
          uid: "seg_won"
          formula: {
            logic: { text: "val_won", html: "<span>val_won</span>" }
            display: { type: NUMBER }
          }
          chartSegmentValues: [
            { uid: "val_won", title: "Won", projectId: "project_123", function: COUNT }
          ]
        }
      ]
    }
  ) {
    id
    title
    chartSegments {
      id
      uid
      title
    }
  }
}

Errors

CodeWhen
DASHBOARD_NOT_FOUNDNo dashboard matches dashboardId for the caller, including when the caller lacks creator or EDITOR access to it.
{
  "errors": [
    {
      "message": "Dashboard was not found.",
      "extensions": { "code": "DASHBOARD_NOT_FOUND" }
    }
  ]
}

editChart

Use the editChart mutation to rename, reposition, restyle, or re-spec a chart. Only the fields you pass are changed; omitted fields are left untouched. Segments and values are not edited here — use the segment and value mutations.

Request

mutation EditChart {
  editChart(input: { id: "chart_123", title: "Open records (this quarter)" }) {
    id
    title
    updatedAt
  }
}

Parameters

EditChartInput

ParameterTypeRequiredDescription
idString!YesID of the chart to edit.
titleStringNoNew title.
positionFloatNoNew sort position within the dashboard.
displayFormulaDisplayInputNoNew display formatting. Replaces the existing display.
metadataChartMetadataInputNoNew barChart/pieChart spec. Changing metadata re-triggers an asynchronous result calculation.
Editing metadata recalculates; editing title/position/display does not

editChart only enqueues a recalculation when the input includes metadata.barChart or metadata.pieChart. Renaming, repositioning, or restyling a chart updates it and publishes the change to subscribers, but does not recompute its data. To force a recompute without changing the spec, use recalculateCharts.

Response

{
  "data": {
    "editChart": {
      "id": "clm4n8qwx000008l0g4oxdqn7",
      "title": "Open records (this quarter)",
      "updatedAt": "2026-05-29T14:07:42.000Z"
    }
  }
}

editChart returns the updated Chart (same shape as createChart).

Errors

CodeWhen
CHART_NOT_FOUNDNo chart matches id for the caller, including when the caller lacks creator or EDITOR access to its dashboard.

copyChart

Use the copyChart mutation to duplicate a chart into the same dashboard or a different one. The copy is a deep copy: segments, values, formulas, type, display, and metadata are recreated with fresh identifiers.

Request

mutation CopyChart {
  copyChart(input: { chartId: "chart_123", dashboardId: "dashboard_456" }) {
    id
    title
    type
    position
  }
}

Parameters

CopyChartInput

ParameterTypeRequiredDescription
chartIdString!YesChart to copy. You must be the creator or an EDITOR of its dashboard.
dashboardIdString!YesDestination dashboard. You must be its creator or an EDITOR. May be the same dashboard.
titleStringNoTitle for the copy. If omitted, the copy keeps the original chart’s title.

Response

{
  "data": {
    "copyChart": {
      "id": "clm4n8qwx000409l0d1weq2bk",
      "title": "Open records",
      "type": "STAT",
      "position": 131070
    }
  }
}

copyChart returns the newly created Chart.

Formula UIDs are remapped

For a manual chart, each copied ChartSegmentValue gets a fresh uid, and the new UID is string-replaced into the copied segment’s formula.logic.text and formula.logic.html. The formula keeps working against the copied values rather than pointing back at the originals. The formula-UID linkage is detailed on Build chart segments and values.

The copy is appended after the last chart in the destination dashboard (see Position defaults) and its results are recalculated asynchronously, so it briefly reports needCalculation: true.

Errors

CodeWhen
DASHBOARD_NOT_FOUNDNo destination dashboard matches dashboardId for the caller, or the caller lacks creator or EDITOR access to it.
CHART_NOT_FOUNDNo chart matches chartId for the caller, or the caller lacks creator or EDITOR access to the source chart’s dashboard.

deleteChart

Use the deleteChart mutation to remove a chart and its segments. deleteChart takes the chart id directly, not an input object.

Request

mutation DeleteChart {
  deleteChart(id: "chart_123") {
    success
  }
}

Parameters

ParameterTypeRequiredDescription
idString!YesID of the chart to delete.

Response

deleteChart returns a MutationResult. It exposes only success and operationId — there is no message field.

{
  "data": {
    "deleteChart": {
      "success": true
    }
  }
}

MutationResult

FieldTypeDescription
successBoolean!true if the chart was deleted; false if the delete failed.
operationIdStringCorrelation ID for the operation, when set.

Errors

CodeWhen
CHART_NOT_FOUNDNo chart matches id for the caller, including when the caller lacks creator or EDITOR access to its dashboard.

If the chart is found but the delete itself fails, the mutation returns { "success": false } rather than throwing.

ChartFunction vs. ChartSegmentValueFunctions

Two enums share the same seven members but live in different places — keep them straight in examples:

EnumWhere it appearsMembers
ChartFunctionFormulaDisplayInput.function (the chart-level display rollup)COUNT, COUNTA, SUM, AVERAGE, AVERAGEA, MIN, MAX
ChartSegmentValueFunctionsEach segment value and each barChart/pieChart axis (function)COUNT, COUNTA, SUM, AVERAGE, AVERAGEA, MIN, MAX

Position defaults

position is a Float! controlling order within the dashboard. When you omit position on createChart (and always on copyChart), the server appends the chart after the current last one: it takes the highest existing position and adds a fixed gap, or uses that gap as the starting position if the dashboard has no charts yet. Pass an explicit position to slot a chart between two others. Reorder later with editChart.

Permissions

All four mutations are writes and require the caller to either have created the chart’s dashboard or hold the EDITOR role on it. copyChart checks this on both the source chart’s dashboard and the destination dashboard.

Access to the dashboardCan create / edit / copy / delete
CreatorYes
EDITORYes
VIEWERNo
No accessNo

A caller without sufficient access receives CHART_NOT_FOUND (or DASHBOARD_NOT_FOUND for the dashboard argument) rather than a distinct permission error — the chart or dashboard simply does not match the access-scoped lookup. Reads, by contrast, require only viewer access; see Query and subscribe to charts.