> ## Documentation Index
> Fetch the complete documentation index at: /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.md) for how these opaque IDs are encoded.

```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 } } } } }
    }
  }
}
```

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

```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>" }
```

## 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.

```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>" }
```

`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)).

```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>" }
```

## 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.md) page.

```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"])
```

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.md#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.

```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>" }
  }
}
```

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.md) and the [AQL syntax reference](/docs/ax/machine-learning/machine-learning/how-to-ml/custom-metrics-api/custom-metric-syntax.md). 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.

```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"
  }
}
```

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.

```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" }
    ]
  }
}
```

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.md#querying-and-filters) panel when viewing traces.

```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>"
  }
}
```

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.

```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>" } }
```

> [!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]
>
> `deleteModel` permanently deletes the project and everything in it. There is no undo.

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

> [accordion] 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] 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] 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] 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] 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] 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.md#source-mapping). Both take a `JSON` argument, and source mapping only applies to spans ingested after the change; existing data is not backfilled.

> [card] [Project and model mutations reference](/docs/ax/graphql-reference/mutations/projects-and-models.md)
>
> Full arguments, return types and minimal examples for every mutation in this domain.

> [card] [All mutations](/docs/ax/graphql-reference/mutations.md)
>
> Browse mutations for every other domain: monitors, datasets, prompts and more.

> [card] [API explorer](/docs/ax/graphql-reference/overview/api-explorer.md)
>
> Run queries and mutations interactively against your own space.
