## Create spans in a batch

`client.Spans.Batch(ctx, body) (*APIListSpan, error)`

**post** `/v5/spans/batch`

Create multiple spans (up to 1000) in a single request and return the created spans.

Prefer this over repeated POST /v5/spans calls when ingesting many spans at
once; use PUT /v5/spans/batch instead when a span with the same `id` may
already exist, since this endpoint inserts new spans rather than overwriting.
A batch larger than 1000 spans is rejected with a validation error. Each item
follows the same id-generation and per-account dual-write rules as the
single-span create, including that `end_timestamp` must not precede
`start_timestamp`, which rejects the request with a 422. When the tracing
service is the primary store, its 400, 413 and 422 rejections keep that status
and detail, as does a 403 when the request carried its own API key, and every
other failure returns a 503 with a Retry-After header. A batch that forms a cycle,
or a span whose parent belongs to another trace, is rejected with 409 before either
store is written. A parent outside the batch is looked up in Postgres, so that part
of the check ends once the account's spans stop being written there. Postgres
rejects an `id` that already exists, while the tracing service treats the write
as an upsert. Which writes the tracing service rejects depends in part on its
storage engine: on Postgres deployments a NUL byte or invalid UTF-8 inside
`trace_id`, `id`, `parent_id` or `group_id` fails the whole batch with a 400
naming the field, because replacing the byte would change the identity the
response echoes; a NUL byte or invalid UTF-8 in any other field is replaced with
U+FFFD and the span is persisted. ClickHouse deployments store the bytes verbatim.

Credential redaction: values in the free-form `input`, `output`, `metadata`,
and `expected` objects, and in `name`, that are credential-shaped (bearer/JWT,
API keys, connection-string passwords) or under a credential-named key are replaced
with `[REDACTED:credential]` before the span is persisted, so the stored and
returned span reflects the redacted value (EY 12.3).

### Parameters

- `body SpanBatchParams`

  - `SpanBatchCreate param.Field[SpanBatchCreate]`

### Returns

- `type APIListSpan struct{…}`

  - `Items []Span`

    - `ID string`

    - `AccountID string`

    - `Name string`

    - `StartTimestamp Time`

    - `TraceID string`

      id for grouping traces together, uuid is recommended

    - `ApplicationInteractionID string`

      The interaction ID this span belongs to

    - `ApplicationVariantID string`

      The id of the application variant this span belongs to

    - `CreatedBy Identity`

      The identity that created the entity.

      - `ID string`

      - `Type IdentityType`

        - `const IdentityTypeUser IdentityType = "user"`

        - `const IdentityTypeServiceAccount IdentityType = "service_account"`

      - `Object IdentityObject`

        - `const IdentityObjectIdentity IdentityObject = "identity"`

    - `EndTimestamp Time`

    - `Expected map[string, any]`

    - `GroupID string`

      Reference to a group_id

    - `Input map[string, any]`

    - `InputTokens int64`

      Prompt tokens the producer reported for this span, absent when it reported none. Same quantity the input_tokens sort orders by.

    - `Metadata map[string, any]`

    - `Object SpanObject`

      - `const SpanObjectSpan SpanObject = "span"`

    - `ObsSpanID string`

      W3C span id of the observability span this span executed in.

    - `ObsTraceID string`

      W3C trace id of the observability trace this span executed in. Null for spans written without the edge, and for accounts still served by the legacy trace store.

    - `Output map[string, any]`

    - `OutputTokens int64`

      Completion tokens the producer reported for this span, absent when it reported none. Same quantity the output_tokens sort orders by.

    - `ParentID string`

      Reference to a parent span_id

    - `Status SpanStatus`

      - `const SpanStatusSuccess SpanStatus = "SUCCESS"`

      - `const SpanStatusError SpanStatus = "ERROR"`

      - `const SpanStatusCanceled SpanStatus = "CANCELED"`

    - `Type SpanType`

      - `const SpanTypeTextInput SpanType = "TEXT_INPUT"`

      - `const SpanTypeTextOutput SpanType = "TEXT_OUTPUT"`

      - `const SpanTypeCompletionInput SpanType = "COMPLETION_INPUT"`

      - `const SpanTypeCompletion SpanType = "COMPLETION"`

      - `const SpanTypeKBRetrieval SpanType = "KB_RETRIEVAL"`

      - `const SpanTypeKBInput SpanType = "KB_INPUT"`

      - `const SpanTypeReranking SpanType = "RERANKING"`

      - `const SpanTypeExternalEndpoint SpanType = "EXTERNAL_ENDPOINT"`

      - `const SpanTypePromptEngineering SpanType = "PROMPT_ENGINEERING"`

      - `const SpanTypeDocumentInput SpanType = "DOCUMENT_INPUT"`

      - `const SpanTypeMapReduce SpanType = "MAP_REDUCE"`

      - `const SpanTypeDocumentSearch SpanType = "DOCUMENT_SEARCH"`

      - `const SpanTypeDocumentPrompt SpanType = "DOCUMENT_PROMPT"`

      - `const SpanTypeCustom SpanType = "CUSTOM"`

      - `const SpanTypeCodeExecution SpanType = "CODE_EXECUTION"`

      - `const SpanTypeDataManipulation SpanType = "DATA_MANIPULATION"`

      - `const SpanTypeEvaluation SpanType = "EVALUATION"`

      - `const SpanTypeFileRetrieval SpanType = "FILE_RETRIEVAL"`

      - `const SpanTypeKBAddChunk SpanType = "KB_ADD_CHUNK"`

      - `const SpanTypeKBManagement SpanType = "KB_MANAGEMENT"`

      - `const SpanTypeGuardrail SpanType = "GUARDRAIL"`

      - `const SpanTypeOutputGuardrail SpanType = "OUTPUT_GUARDRAIL"`

      - `const SpanTypeTracer SpanType = "TRACER"`

      - `const SpanTypeAgentTracer SpanType = "AGENT_TRACER"`

      - `const SpanTypeAgentWorkflow SpanType = "AGENT_WORKFLOW"`

      - `const SpanTypeStandalone SpanType = "STANDALONE"`

  - `Object APIListSpanObject`

    - `const APIListSpanObjectList APIListSpanObject = "list"`

### Example

```go
package main

import (
  "context"
  "fmt"
  "time"

  "github.com/scaleapi/sgp-dev-go"
  "github.com/scaleapi/sgp-dev-go/option"
)

func main() {
  client := sgpdev.NewClient(
    option.WithAPIKey("My API Key"),
    option.WithAccountID("My Account ID"),
  )
  apiListSpan, err := client.Spans.Batch(context.TODO(), sgpdev.SpanBatchParams{
    SpanBatchCreate: sgpdev.SpanBatchCreateParam{
      Items: []sgpdev.SpanCreateParam{sgpdev.SpanCreateParam{
        Name: "name",
        StartTimestamp: time.Now(),
        TraceID: "trace_id",
      }},
    },
  })
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", apiListSpan.Items)
}
```

#### Response

```json
{
  "items": [
    {
      "id": "id",
      "account_id": "account_id",
      "name": "name",
      "start_timestamp": "2019-12-27T18:11:19.117Z",
      "trace_id": "trace_id",
      "application_interaction_id": "application_interaction_id",
      "application_variant_id": "application_variant_id",
      "created_by": {
        "id": "id",
        "type": "user",
        "object": "identity"
      },
      "end_timestamp": "2019-12-27T18:11:19.117Z",
      "expected": {
        "foo": "bar"
      },
      "group_id": "group_id",
      "input": {
        "foo": "bar"
      },
      "input_tokens": 0,
      "metadata": {
        "foo": "bar"
      },
      "object": "span",
      "obs_span_id": "obs_span_id",
      "obs_trace_id": "obs_trace_id",
      "output": {
        "foo": "bar"
      },
      "output_tokens": 0,
      "parent_id": "parent_id",
      "status": "SUCCESS",
      "type": "TEXT_INPUT"
    }
  ],
  "object": "list"
}
```
