---
title: "Annotate a batch of project spans"
method: POST
path: "/v2/spans/annotate"
tags: ["Spans"]
---

# Annotate a batch of project spans

`POST /v2/spans/annotate`

Write human annotations to a batch of spans in a project.

**Idempotency**: Writes use upsert semantics — submitting the same annotation
config name for the same span overwrites the previous value. Retrying on
network failure will not create duplicates.

**202 Accepted**: The annotations have been accepted and will be written.
Visibility in read queries may lag by a short interval.

**Partial failure**: Writes are grouped by calendar day and processed
sequentially. A non-2xx response means the request failed during the write
phase — annotations for earlier calendar-day buckets may already be saved
while later ones are not. It is safe to retry the full request;
re-submitting a record that was already saved will overwrite it with the
same value (no duplicates).

**Payload Requirements**
- `project_id` is required and must identify a project the caller has span annotation access to.
- `annotations` is a list of per-span annotation inputs. Each entry identifies
  one span by its `record_id` and provides one or more annotation values.
- Each `record_id` must be unique within the request (duplicates return 400).
- Each record's `values` list must not contain duplicate annotation config names (returns 400).
- `granularity` selects what `record_id` identifies: `SPAN` (a span ID, the
  default), `TRACE` (a trace's root span ID), or `SESSION` (a session ID).
  For SESSION, the annotation is written to the root span of the session's
  earliest trace found within the lookup window.
- `start_time` / `end_time` constrain the time range for span lookup.
  If omitted, `start_time` defaults to 31 days before `end_time` (7 days
  for SESSION granularity) and `end_time` to now. Both `start_time` and
  `end_time` may not be in the future. For SPAN/TRACE the window may not
  exceed 31 days; for SESSION it may not exceed 7 days. If ANY span
  cannot be located within the given range, the entire request is
  rejected with 404 and no annotations are written (all-or-nothing
  pre-validation). Only after all spans are confirmed does the write
  phase begin.
- Annotation names must match existing annotation configs in the project's space.
- Up to 1000 records may be annotated per request for SPAN/TRACE granularity;
  up to 100 records per request for SESSION granularity.

**Valid example**
```json
{
  "project_id": "proj_abc123",
  "annotations": [
    {"record_id": "span_abc", "values": [{"name": "relevance", "label": "good", "score": 1.0}]}
  ]
}
```

**Valid example** (session granularity)
```json
{
  "project_id": "proj_abc123",
  "granularity": "SESSION",
  "annotations": [
    {"record_id": "session_abc", "values": [{"name": "quality", "label": "good", "score": 1.0}]}
  ]
}
```

**Invalid example** (annotation name not found in space)
```json
{
  "project_id": "proj_abc123",
  "annotations": [
    {"record_id": "span_abc", "values": [{"name": "nonexistent_config"}]}
  ]
}
```

**Invalid example** (time window exceeds 31 days)
```json
{
  "project_id": "proj_abc123",
  "start_time": "2025-01-01T00:00:00Z",
  "end_time": "2025-03-01T00:00:00Z",
  "annotations": [
    {"record_id": "span_abc", "values": [{"name": "relevance", "label": "good"}]}
  ]
}
```

**Invalid example** (session time window exceeds 7 days)
```json
{
  "project_id": "proj_abc123",
  "granularity": "SESSION",
  "start_time": "2025-01-01T00:00:00Z",
  "end_time": "2025-01-15T00:00:00Z",
  "annotations": [
    {"record_id": "session_abc", "values": [{"name": "quality", "label": "good"}]}
  ]
}
```

<Note>This endpoint is in beta, read more [here](https://arize.com/docs/ax/rest-reference#api-version-stages).</Note>

## Request body

- AnnotateSpansRequest — Batch annotation request for project spans.
  - `project_id` string, required — The project (model) ID whose spans are being annotated.
  - `start_time` string, date-time — Start of the time range for span lookup. Optional; defaults to 31 days before end_time, or 7 days before end_time when granularity is SESSION.
  - `end_time` string, date-time — End of the time range for span lookup. Optional; defaults to now.
  - `granularity` 'SPAN' | 'TRACE' | 'SESSION' — Granularity of an annotation queue record. - SPAN: The record represents a span. - TRACE: The record represents a trace. - SESSION: The record represents a session.
  - `annotations` AnnotateRecordInput[], required — Batch of annotations to write. Up to 1000 records per request for SPAN or TRACE granularity; up to 100 records per request for SESSION granularity.
    - `record_id` string, required — The record identifier — a span ID, session ID, dataset example ID, or experiment run ID, depending on the endpoint and (for spans) the `granularity` field.
    - `values` AnnotationInput[], required — One or more annotation values to set on this record.
      - `name` string, required — The annotation config name
      - `score` number, double — Numeric score for the annotation. Omit to leave unchanged.
      - `label` string — Categorical label for the annotation. Omit to leave unchanged.
      - `text` string — Free-form text note for the annotation. Omit to leave unchanged.

## Response `202`

Annotations accepted. Writes are idempotent; retry on failure is safe.

## Other responses

- `400` — Invalid request
- `401` — Authentication is required
- `403` — Insufficient permissions to access this resource
- `404` — Not found
- `422` — Unprocessable entity
- `429` — Rate limit exceeded

## Changes

> 18 revisions in range; 1 not diffed.

- **2026-09-01** `4087706f0e01` — 1 info
  - added the new `SESSION` enum value to the request property `granularity/allOf[#/components/schemas/RecordGranularity]/`

[Change history](https://skmtc.dev/arize-ai/apis/arize-rest-api/changes/v2/spans/annotate/post.md)

---

[API](https://skmtc.dev/arize-ai/apis/arize-rest-api.md) · [All operations](https://skmtc.dev/arize-ai/apis/arize-rest-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/arize-ai/arize-rest-api/revisions/cb1b01872ec4/schema)
