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

# Spans

> List, delete, and annotate spans within a project using the Arize Go SDK.

<Note>
  The `spans` client methods are currently in **ALPHA**. The API may change without notice. A one-time warning is emitted on first use.
</Note>

Spans are the unit of work captured for an LLM application — each trace is composed of one or more hierarchical spans. The `Spans` subclient lets you query spans within a project (filtered by time range and an optional filter DSL), remove spans by ID, and write human annotations to a batch of spans. `Project` accepts a name or ID; when a name is passed, `Space` (name or ID) is required so the SDK can resolve the name to a unique ID.

## List Spans

`List` returns a paginated list of spans matching the given filter. Unlike other `List` methods in this SDK, `spans.List` uses `POST` because the filter DSL and projection list can be too large for a query string. Both the body fields (project, time range, filter) and the query params (limit, cursor) are flattened into a single `ListRequest`.

**Signature:**

```go theme={null}
func (c *Client) List(ctx context.Context, req ListRequest) (*SpanList, error)
```

**Usage Example:**

```go theme={null}
package main

import (
    "context"
    "errors"
    "fmt"
    "log"
    "time"

    "github.com/Arize-ai/client-go-v2/arize"
    "github.com/Arize-ai/client-go-v2/arize/spans"
)

func main() {
    client, err := arize.NewClient(arize.Config{APIKey: "your-api-key"})
    if err != nil {
        log.Fatal(err)
    }

    resp, err := client.Spans.List(
        context.Background(),
        spans.ListRequest{
            Project: "your-project-name-or-id",
            Space:   "your-space-name-or-id",
            Start:   time.Now().Add(-24 * time.Hour),
            End:     time.Now(),
            Filter:  "status_code = 'ERROR'",
            Limit:   50,
        },
    )
    if err != nil {
        var unauthorized *arize.UnauthorizedError
        if errors.As(err, &unauthorized) {
            log.Fatalf("unauthorized: %v", unauthorized)
        }
        log.Fatal(err)
    }

    for _, span := range resp.Spans {
        fmt.Printf("%s (trace=%s kind=%s)\n",
            span.Context.SpanId,
            span.Context.TraceId,
            span.Kind,
        )
    }
}
```

## Delete Spans

`Delete` removes spans matching the given criteria. A `nil` `*SpanDeletePartial` return means all spans were fully deleted (HTTP 204). A non-`nil` `*SpanDeletePartial` means the server returned HTTP 200: the request was partially processed and only the IDs listed in `SpanDeletePartial.DeletedSpanIds` were confirmed deleted — the caller should retry for the remainder.

**Signature:**

```go theme={null}
func (c *Client) Delete(
    ctx context.Context,
    req DeleteRequest,
) (*SpanDeletePartial, error)
```

**Usage Example:**

```go theme={null}
package main

import (
    "context"
    "errors"
    "fmt"
    "log"

    "github.com/Arize-ai/client-go-v2/arize"
    "github.com/Arize-ai/client-go-v2/arize/spans"
)

func main() {
    client, err := arize.NewClient(arize.Config{APIKey: "your-api-key"})
    if err != nil {
        log.Fatal(err)
    }

    partial, err := client.Spans.Delete(
        context.Background(),
        spans.DeleteRequest{
            Project: "your-project-name-or-id",
            Space:   "your-space-name-or-id",
            SpanIDs: []string{"span-id-1", "span-id-2"},
        },
    )
    if err != nil {
        var notFound *arize.NotFoundError
        if errors.As(err, &notFound) {
            log.Fatalf("project not found: %v", notFound)
        }
        log.Fatal(err)
    }

    if partial == nil {
        fmt.Println("all spans deleted")
        return
    }
    fmt.Printf("partial delete: confirmed %d span IDs - retry remaining\n",
        len(partial.DeletedSpanIds),
    )
}
```

## Annotate Spans

`Annotate` writes human annotations to a batch of spans. Annotations are upserted by annotation config name per span: resubmitting the same config name for the same span overwrites the previous value, so retries do not create duplicates.

Up to 1000 spans may be annotated per request. Spans are looked up within the configured time window (defaulting to the last 31 days). If any span ID in the batch is not found within the window, the entire request is rejected. The write completes synchronously before the function returns (HTTP 202 Accepted); visibility in read queries may lag by a short interval.

**Signature:**

```go theme={null}
func (c *Client) Annotate(ctx context.Context, req AnnotateRequest) error
```

**Usage Example:**

```go theme={null}
package main

import (
    "context"
    "errors"
    "log"

    "github.com/Arize-ai/client-go-v2/arize"
    "github.com/Arize-ai/client-go-v2/arize/spans"
)

func main() {
    client, err := arize.NewClient(arize.Config{APIKey: "your-api-key"})
    if err != nil {
        log.Fatal(err)
    }

    label := "correct"
    err = client.Spans.Annotate(
        context.Background(),
        spans.AnnotateRequest{
            Project: "your-project-name-or-id",
            Space:   "your-space-name-or-id",
            Annotations: []spans.AnnotateRecordInput{
                {
                    RecordId: "span-id-1",
                    Values: []spans.AnnotationInput{
                        {Name: "quality", Label: &label},
                    },
                },
            },
        },
    )
    if err != nil {
        var badRequest *arize.BadRequestError
        if errors.As(err, &badRequest) {
            log.Fatalf("annotation rejected: %v", badRequest)
        }
        log.Fatal(err)
    }
}
```
