> ## Documentation Index
> Fetch the complete documentation index at: https://arize-ax.mintlify.site/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Managing projects and models with GraphQL

> Script project and model config with GraphQL: baselines, schema and dimension binning, custom metrics, cost configs, trace filters, tags and data deletion.

A **project** (the GraphQL schema still calls it a `Model`) is the workspace in Arize AX holding a model or LLM application's traces, evals, schema and monitoring config; see [Projects](/docs/ax/observe/projects) for the concept. This API automates what you'd otherwise click through in a project's **Config** tab: setting the drift/performance baseline, reading the inferred schema, binning a dimension, defining custom metrics and LLM cost configs, saving trace filters, tagging projects, and deleting data or whole projects.

## Find the IDs you need

Most mutations here take a project ID (`modelId`, despite the name) or a space ID. Start from `viewer` to list spaces and their projects, or jump straight to a project with `node` once you have its ID. See [using global node IDs](/docs/ax/graphql-reference/overview/how-to-use-graphql/using-global-node-ids) for how these opaque IDs are encoded.

<CodeGroup>
  ```graphql Query theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  query FindProjectIDs {
    viewer {
      spaces(first: 20) {
        edges { node { id name models(first: 20) { edges { node { id name projectType } } } } }
      }
    }
  }
  ```
</CodeGroup>

Once you have a project ID, pull its space and existing tags in one call (list tag IDs this way before tagging a project):

<CodeGroup>
  ```graphql Query theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  query GetProjectContext($modelId: ID!) {
    node(id: $modelId) {
      ... on Model {
        id
        name
        projectType
        space { id name }
        tags(first: 20) { edges { node { id name } } }
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  { "modelId": "<PROJECT_ID>" }
  ```
</CodeGroup>

## List the projects in a space

`projectType` tells you whether a project is a user-facing LLM application (`application`), an agent harness session (`harness`), or an experiment trace project (`experiment`). `modelType` separately distinguishes classic ML model types from generative ones.

<CodeGroup>
  ```graphql Query theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  query ListProjectsInSpace($spaceId: ID!) {
    node(id: $spaceId) {
      ... on Space {
        name
        models(first: 25) { edges { node { id name projectType modelType } } }
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  { "spaceId": "<SPACE_ID>" }
  ```
</CodeGroup>

`models` defaults to excluding demo models (`filter: {exclude: {isDemoModel: true}}`); pass your own `filter` to include them, or `search` to match by name.

## Read a project's schema and dimensions

`modelSchema` returns the project's inferred features, tags, predictions and actuals for a time range (defaults to the last year). Each entry's `dimension` field carries the name, category and data type. `dimensionConfig`, on the same entry, only carries binning settings (`id`, `binOption`, `numBins`, `bins`); it does not repeat the name or category, despite the similarly-named mutation input used to set binning ([`updateDimensionConfig`](/docs/ax/graphql-reference/mutations/projects-and-models#updatedimensionconfig)).

<CodeGroup>
  ```graphql Query theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  query GetProjectSchema($modelId: ID!) {
    node(id: $modelId) {
      ... on Model {
        name
        modelSchema {
          features(first: 10) {
            edges {
              node {
                dimension { name category dataType }
                dimensionStats { cardinality percentEmpty }
                dimensionConfig { binOption numBins }
              }
            }
          }
        }
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  { "modelId": "<PROJECT_ID>" }
  ```
</CodeGroup>

## Query a performance metric over a time range

`performanceMetricOverTime` plots a built-in metric like accuracy or RMSE for a project across a time range and granularity. This is a read-only query, not a mutation, so there's no reference anchor; the full `Model` field list is on the [object graph](/docs/ax/graphql-reference/queries/object-graph) page.

<CodeGroup>
  ```graphql Query theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  query ProjectMetricOverTime($modelId: ID!, $startTime: DateTime!, $endTime: DateTime!) {
    node(id: $modelId) {
      ... on Model {
        performanceMetricOverTime(
          startTime: $startTime
          endTime: $endTime
          timeZone: "UTC"
          environmentName: production
          performanceMetric: accuracy
          timeSeriesDataGranularity: day
        ) {
          key
          dataPoints { x y }
        }
      }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "modelId": "<PROJECT_ID>",
    "startTime": "2026-09-01T00:00:00.000Z",
    "endTime": "2026-10-01T00:00:00.000Z"
  }
  ```

  ```python Script theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  import requests

  API_KEY = "<YOUR_API_KEY>"
  QUERY = """
  query ProjectMetricOverTime($modelId: ID!, $startTime: DateTime!, $endTime: DateTime!) {
    node(id: $modelId) {
      ... on Model {
        performanceMetricOverTime(
          startTime: $startTime, endTime: $endTime, timeZone: "UTC"
          environmentName: production, performanceMetric: accuracy
          timeSeriesDataGranularity: day
        ) { key dataPoints { x y } }
      }
    }
  }
  """
  variables = {
      "modelId": "<PROJECT_ID>",
      "startTime": "2026-09-01T00:00:00.000Z",
      "endTime": "2026-10-01T00:00:00.000Z",
  }
  resp = requests.post(
      "https://app.arize.com/graphql",
      json={"query": QUERY, "variables": variables},
      headers={"x-api-key": API_KEY},
  )
  resp.raise_for_status()
  result = resp.json()
  if "errors" in result:
      raise RuntimeError(result["errors"])
  print(result["data"]["node"]["performanceMetricOverTime"]["dataPoints"])
  ```
</CodeGroup>

For a metric you've already saved as a custom metric, swap `performanceMetric: udf` and pass the same AQL string as `customMetricConfig`.

## Set a primary baseline

A project's baseline is the comparison dataset used for drift and performance-delta calculations; see [Setting your baseline](/docs/ax/observe/production-monitoring/configure-monitors#setting-your-baseline). Point it at a fixed, already-uploaded batch with `datasetBaseline`, or at a moving window of filtered live traffic by setting `referenceType` to `filtered` and using `filteredBaseline` instead.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation SetPrimaryBaseline($input: SetModelBaselineMutationInput!) {
    setModelBaseline(input: $input) {
      modelBaseline { id referenceType baselineType }
      model { id name }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "modelId": "<PROJECT_ID>",
      "referenceType": "model_version_environment_metadata",
      "datasetBaseline": { "batchId": "<BATCH_ID>" }
    }
  }
  ```
</CodeGroup>

Reference: [`setModelBaseline`](/docs/ax/graphql-reference/mutations/projects-and-models#setmodelbaseline). To keep a preproduction baseline pinned to whatever was most recently uploaded instead of a fixed batch, use [`setModelAutoBaselineConfig`](/docs/ax/graphql-reference/mutations/projects-and-models#setmodelautobaselineconfig) with `environmentName` set to `validation` or `training`.

## Create and update a custom metric

Custom metrics are scoped to a space and written in Arize Query Language (AQL); see [Set up custom metrics](/docs/ax/observe/projects/custom-metrics-api) and the [AQL syntax reference](/docs/ax/machine-learning/machine-learning/how-to-ml/custom-metrics-api/custom-metric-syntax). Create one, then edit it in place once you know its ID. Note that the AQL string is named `metric` on create but `customMetric` on update.

<CodeGroup>
  ```graphql Create theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateCustomMetric($input: CreateCustomMetricMutationInput!) {
    createCustomMetric(input: $input) {
      customMetric { id name metric }
    }
  }
  ```

  ```json Create variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "spaceId": "<SPACE_ID>",
      "modelId": "<PROJECT_ID>",
      "name": "Cost per trace",
      "description": "Average LLM cost per trace",
      "metric": "SELECT AVG(totalCost) FROM model"
    }
  }
  ```

  ```graphql Update theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation UpdateCustomMetric($input: UpdateCustomMetricMutationInput!) {
    updateCustomMetric(input: $input) {
      customMetric { id name metric }
    }
  }
  ```

  ```json Update variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "customMetricId": "<CUSTOM_METRIC_ID>",
      "name": "Cost per trace",
      "description": "Average LLM cost per trace, excluding retries",
      "customMetric": "SELECT AVG(totalCost) FROM model WHERE isRetry = false"
    }
  }
  ```
</CodeGroup>

Reference: [`createCustomMetric`](/docs/ax/graphql-reference/mutations/projects-and-models#createcustommetric) and [`updateCustomMetric`](/docs/ax/graphql-reference/mutations/projects-and-models#updatecustommetric). Remove a metric with [`deleteCustomMetric`](/docs/ax/graphql-reference/mutations/projects-and-models#deletecustommetric), which takes `spaceId` and `customMetricId`.

## Create a cost config for an LLM project

Cost configs price an LLM model's prompt and completion tokens so Arize can compute per-trace and per-project cost; see [Tracking token usage](/docs/ax/observe/dashboards/token-counting). Scope a config to a space with `scopings`, or omit `scopings` to fall back to the account's default.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateCostConfig($input: CreateCostConfigInput!) {
    createCostConfig(input: $input) {
      success
      costConfig { id modelName isDefault }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "modelName": "gpt-5.5",
      "llmProvider": "openai",
      "scopings": [{ "spaceId": "<SPACE_ID>" }],
      "tokenConfigs": [
        { "tokenName": "input", "tokenCostDollars": 0.000005, "tokenAppliesTo": "prompt" },
        { "tokenName": "output", "tokenCostDollars": 0.000015, "tokenAppliesTo": "completion" }
      ]
    }
  }
  ```
</CodeGroup>

Reference: [`createCostConfig`](/docs/ax/graphql-reference/mutations/projects-and-models#createcostconfig). Change pricing later with [`updateCostConfig`](/docs/ax/graphql-reference/mutations/projects-and-models#updatecostconfig) (pass `costConfigId` plus only the fields you're changing; a `scopings` you include replaces the full set). Remove a config with [`deleteCostConfig`](/docs/ax/graphql-reference/mutations/projects-and-models#deletecostconfig).

## Create a trace filter

A trace filter is a named, reusable filter saved to a space: a top-level `expression` built from one or more named `subqueries`, each its own AQL query against spans. It mirrors what you build in the [querying and filters](/docs/ax/observe/tracing/view-and-manage-traces#querying-and-filters) panel when viewing traces.

<CodeGroup>
  ```graphql Mutation theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation CreateTraceFilter($input: CreateTraceFilterInput!) {
    createTraceFilter(input: $input) {
      traceFilter { id name expression }
    }
  }
  ```

  ```json Variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "name": "Slow checkout traces",
      "description": "Checkout spans slower than 5 seconds",
      "expression": "s1",
      "subqueries": [{ "name": "s1", "query": "latencyMs > 5000 AND spanName = 'checkout'" }],
      "spaceId": "<SPACE_ID>"
    }
  }
  ```
</CodeGroup>

Reference: [`createTraceFilter`](/docs/ax/graphql-reference/mutations/projects-and-models#createtracefilter). Update one with [`updateTraceFilter`](/docs/ax/graphql-reference/mutations/projects-and-models#updatetracefilter), sending only the fields that change, or remove it with [`deleteTraceFilter`](/docs/ax/graphql-reference/mutations/projects-and-models#deletetracefilter).

## Tag, delete data from, or delete a project

Tags group projects for search (list a space's existing tags with the `GetProjectContext` query above). Deleting data removes everything in a time range without touching the project itself; deleting the project removes it completely.

<CodeGroup>
  ```graphql Tag theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation TagProject($input: AddTagsToModelInput!) {
    addTagsToModel(input: $input) {
      result {
        ... on TagAssociationSuccess { success }
        ... on TagAssociationError { errorMessage }
      }
    }
  }
  ```

  ```json Tag variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  { "input": { "modelId": "<PROJECT_ID>", "tagIds": ["<TAG_ID>"] } }
  ```

  ```graphql Delete data theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation DeleteProjectData($input: DeleteDataMutationInput!) {
    deleteData(input: $input) {
      model { id name }
    }
  }
  ```

  ```json Delete data variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  {
    "input": {
      "modelId": "<PROJECT_ID>",
      "startDate": "2026-01-01",
      "endDate": "2026-02-01",
      "deleteType": "PRODUCTION"
    }
  }
  ```

  ```graphql Delete project theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  mutation DeleteProject($input: DeleteModelMutationInput!) {
    deleteModel(input: $input) {
      space { id name }
    }
  }
  ```

  ```json Delete project variables theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  { "input": { "modelId": "<PROJECT_ID>" } }
  ```
</CodeGroup>

<Warning>
  `deleteData` is irreversible, and the deletion itself can take up to an hour to finish. Double-check `modelId`, `startDate` and `endDate` before sending it. `deleteType: PRODUCTION` removes predictions, joined actuals and SHAP values for ML models, or spans for generative projects; `PREPRODUCTION` removes training and validation data instead.
</Warning>

<Warning>
  `deleteModel` permanently deletes the project and everything in it. There is no undo.
</Warning>

Reference: [`addTagsToModel`](/docs/ax/graphql-reference/mutations/projects-and-models#addtagstomodel) (remove tags with [`removeTagsFromModel`](/docs/ax/graphql-reference/mutations/projects-and-models#removetagsfrommodel)), [`deleteData`](/docs/ax/graphql-reference/mutations/projects-and-models#deletedata), and [`deleteModel`](/docs/ax/graphql-reference/mutations/projects-and-models#deletemodel).

## Gotchas and behavior notes

<AccordionGroup>
  <Accordion title="A schema entry's dimensionConfig doesn't carry the dimension's name or category">
    `ModelSchemaDimensionConfig` (what `modelSchema.features/tags/predictions/actuals.dimensionConfig` returns) only has `id`, `modelId`, `binOption`, `numBins` and `bins`. Get the name and category from the sibling `dimension { name category }` field on the same schema entry, not from `dimensionConfig`. Older examples that queried `dimensionConfig { dimensionName dimensionCategory }` no longer match this type.
  </Accordion>

  <Accordion title="updateDimensionConfig's input and output use two different, similarly-shaped bin enums">
    The mutation's input takes `binOption: DimensionBinOption!` (`equalWidth`, `custom`, `medianCentered`, `discrete`, `decile`, `quantiles`, `discreteTopN`). Its payload's `DimensionConfig.binOption` is typed `CustomBinOption`, whose values are spelled differently for the same concepts (`numBins`, `customBins`, `medianCentered`, `discreteBins`, ...). Don't assume the value you sent is the value you'll read back.
  </Accordion>

  <Accordion title="createCustomMetric and updateCustomMetric name the query field differently">
    The AQL string is `metric` on `CreateCustomMetricMutationInput` and `customMetric` on `UpdateCustomMetricMutationInput`. Custom metrics are also space-scoped now: `CustomMetric.modelName`, `CustomMetric.modelId`, `CustomMetric.modelType` and `DeleteCustomMetricMutationInput.modelId` are all deprecated in favor of `spaceId`.
  </Accordion>

  <Accordion title="A baseline is either a fixed dataset or a filtered stream, matching referenceType">
    `SetModelBaselineMutationInput` accepts both `datasetBaseline` and `filteredBaseline`, but only the one matching `referenceType` (`model_version_environment_metadata` with `datasetBaseline`, or `filtered` with `filteredBaseline`) takes effect. The schema's nullability doesn't enforce this pairing, so sending the wrong combination won't fail type validation.
  </Accordion>

  <Accordion title="Cost config accountOrganizationId is legacy">
    `CreateCostConfigInput`, `UpdateCostConfigInput` and `DeleteCostConfigInput` all still carry an `accountOrganizationId` field, but on the current scope-aware surface it's unused or derived automatically. Use `scopings` (account-wide when omitted, org-wide with just `accountOrganizationId`, space-only with `spaceId`) to control placement instead.
  </Accordion>

  <Accordion title="Column and source mapping aren't covered above">
    [`updateModelColumnMappingConfig`](/docs/ax/graphql-reference/mutations/projects-and-models#updatemodelcolumnmappingconfig) sets the shortcut-key-to-column-path mapping for classic ML schemas. [`updateProjectSourceMappingConfig`](/docs/ax/graphql-reference/mutations/projects-and-models#updateprojectsourcemappingconfig) sets which span attributes a tracing project treats as Input and Output; see [Source mapping](/docs/ax/observe/tracing/view-and-manage-traces#source-mapping). Both take a `JSON` argument, and source mapping only applies to spans ingested after the change; existing data is not backfilled.
  </Accordion>
</AccordionGroup>

<CardGroup cols={2}>
  <Card title="Project and model mutations reference" icon="book" href="/docs/ax/graphql-reference/mutations/projects-and-models">
    Full arguments, return types and minimal examples for every mutation in this domain.
  </Card>

  <Card title="All mutations" icon="list" href="/docs/ax/graphql-reference/mutations">
    Browse mutations for every other domain: monitors, datasets, prompts and more.
  </Card>

  <Card title="API explorer" icon="terminal" href="/docs/ax/graphql-reference/overview/api-explorer">
    Run queries and mutations interactively against your own space.
  </Card>
</CardGroup>
