WeaveScope

Ingestion API

Send native observations, LangSmith-compatible runs, or OpenTelemetry traces to WeaveScope.

Use the ingestion API to send trace data from custom clients, compatibility bridges, and OpenTelemetry collectors.

Base URL:

https://app.weavescope.com

Authentication

Every request requires a project API key in one of these headers:

Authorization: Bearer ws_...
x-api-key: ws_...

The key must have ingest:write. A missing or invalid key receives 401 Unauthorized; a valid key without ingest permission receives 403 Forbidden.

Endpoints

Method Path Accepts
POST /api/v1/observations/batch Native WeaveScope observations.
POST /api/v1/runs A LangSmith-compatible run creation.
PATCH /api/v1/runs/:id A LangSmith-compatible run update.
POST /api/v1/runs/batch LangSmith-compatible post and patch arrays.
POST /api/public/otel/v1/traces OpenTelemetry Protocol over HTTP (OTLP/HTTP) traces.

Native observations

Send native events in an events array:

{
  "events": [
    {
      "observation_id": "018f5f2a-77a6-7bd4-bb58-df7b90f8e337",
      "trace_id": "018f5f2a-77a6-7bd4-bb58-df7b90f8e337",
      "operation": "finish",
      "name": "support.reply",
      "kind": "agent",
      "status": "success",
      "start_time": "2026-07-02T12:00:00Z",
      "end_time": "2026-07-02T12:00:03Z",
      "event_version": 17830032030000002,
      "inputs": {"messages": [{"role": "user", "content": "Hello"}]},
      "outputs": {"text": "Hi"},
      "usage": {"input_tokens": 12, "output_tokens": 7},
      "custom_fields": {"account_id": "acct_123"}
    }
  ]
}

Required fields:

Field Requirement
observation_id or id A non-empty string.
trace_id A non-empty string.
operation start, finish, or error.
kind or run_type One of the accepted observation kinds.
status One of the accepted statuses.

Validated optional fields:

Field Requirement
start_time An ISO 8601 datetime.
end_time An ISO 8601 datetime.
event_version An integer from 0 through 18446744073709551615. A string integer is also accepted.

Accepted kinds:

event, span, generation, agent, tool, chain, retriever, evaluator,
embedding, guardrail, graph, model, llm

Accepted statuses:

pending, running, success, ok, error, interrupted, cancelled

Example request

curl https://app.weavescope.com/api/v1/observations/batch \
  -H "authorization: Bearer $WEAVESCOPE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "events": [
      {
        "observation_id": "018f5f2a-77a6-7bd4-bb58-df7b90f8e337",
        "trace_id": "018f5f2a-77a6-7bd4-bb58-df7b90f8e337",
        "operation": "finish",
        "name": "manual.test",
        "kind": "span",
        "status": "success"
      }
    ]
  }'

Native responses

An accepted event returns 202 Accepted:

{
  "status": "queued",
  "accepted": 1,
  "rejected": 0,
  "results": [
    {
      "index": 0,
      "id": "018f5f2a-77a6-7bd4-bb58-df7b90f8e337",
      "status": "queued",
      "raw_event_id": "..."
    }
  ]
}

A partially accepted batch still includes an itemized results array. Rejected items contain status, code, and reason.

Status Meaning
202 Accepted At least one event was accepted and queued.
400 Bad Request No event was accepted or the request shape was invalid.
401 Unauthorized The API key is missing or invalid.
402 Payment Required The accepted-event limit was reached.
403 Forbidden The API key cannot ingest.
413 Content Too Large The request exceeds a size or event-count limit.
429 Too Many Requests An hourly ingest or edge rate/concurrency limit was reached.
503 Service Unavailable WeaveScope could not safely accept the payload.

An hourly ingest-limit response includes hourly_ingest_reset_at. An edge 429 can use a different response body. Retry either case with backoff.

LangSmith-compatible runs

Create one run:

POST /api/v1/runs

Update one run:

PATCH /api/v1/runs/:id

Send a batch:

{
  "post": [{"id": "run-id", "name": "root", "run_type": "chain"}],
  "patch": [{"id": "run-id", "end_time": "2026-07-02T12:00:03Z"}]
}

Each run object must include id or observation_id.

OpenTelemetry traces

Send OTLP/HTTP traces to:

POST /api/public/otel/v1/traces

The standard OTLP/HTTP protobuf encoding uses:

content-type: application/x-protobuf

Protobuf JSON is also supported:

content-type: application/json

JSON requests must use the OTLP resourceSpans shape. Protobuf requests may use content-encoding: gzip; other encodings receive 415 Unsupported Media Type.

Both the transferred protobuf body and its decompressed value are limited to 25 MiB. A proxy may reject an oversized transferred body before it reaches WeaveScope, so that response body can differ from the OTLP response used for a decompressed-size rejection.

WeaveScope converts every OTLP span to a native observation. Span and resource attributes become metadata, with common fields such as input, output, llm.input_messages, llm.output_messages, error, and exception.message recognized automatically.

Original OTLP TraceId, SpanId, and parentSpanId values remain available as external identifiers. Internal observation IDs include both the trace ID and span ID, so equal span IDs in different traces remain distinct.

Status mapping:

  • STATUS_CODE_ERROR, or numeric code 2, becomes an error observation.

  • STATUS_CODE_OK becomes a successful finished observation.

  • STATUS_CODE_UNSET, or no status, becomes pending. It is treated as finished when the span has an end timestamp and started when it does not.

OTLP responses use OTLP shapes rather than the native JSON envelope:

Case HTTP status Protobuf response JSON response
All spans accepted, or the request is empty 200 OK Empty ExportTraceServiceResponse {}
Some or all spans rejected after a valid decode 200 OK ExportTraceServiceResponse.partial_success {"partialSuccess": {"rejectedSpans": n, "errorMessage": "..."}}
More than 1,000 spans 413 google.rpc.Status with INVALID_ARGUMENT {"code": 3, "message": "..."}
Decompressed protobuf exceeds 25 MiB 413 google.rpc.Status
Invalid media type, encoding, or payload 400 or 415 google.rpc.Status {"code": 3, "message": "..."}
Quota, idempotency, or persistence failure A meaningful status such as 402, 409, 429, or 503 google.rpc.Status {"code": n, "message": "..."}

Custom fields

custom_fields is optional. When present, it must be a JSON object or null. You can provide it at:

  • The event root

  • metadata.custom_fields

  • extra.metadata.custom_fields

  • context_metadata.custom_fields

Missing and null values behave like an empty object. String, number, and boolean values are converted to strings. Nested objects, arrays, blank values, reserved keys, and secret-like keys are ignored.

Values merge in this order, with later values winning:

  1. Context metadata

  2. Effective metadata

  3. Event-level custom fields

An array, string, number, or boolean in place of the object rejects that event with invalid_custom_fields. The reason identifies the invalid path without echoing its value. Other valid events in the request can still be accepted. OTLP reports the rejected spans through partial_success.

Payload size limits

Authenticated request bodies are limited to 25 MiB. Authentication happens before JSON decoding. For gzip-compressed OTLP protobuf, both the transferred and decompressed bodies must fit the limit.

Native batches, combined LangSmith batches, and OTLP trace requests can contain at most 1,000 events or spans. A larger request is rejected atomically with 413 Content Too Large; none of its events are counted, stored, or queued.

Within each event or span, the JSON encoding of each field below can be at most 4 MiB:

  • inputs

  • outputs

  • events

  • metadata

  • context_metadata

For LangSmith-compatible runs, extra.metadata counts as metadata. A field that is exactly 4 MiB is accepted. A larger field rejects only that event with payload_too_large; valid siblings can still be accepted. Accepted fields are stored in full and are never silently truncated.

When usage is counted

An event counts toward monthly usage after it passes validation and WeaveScope safely accepts it for processing. Rejected events do not count and do not consume hourly ingest capacity.

Processing happens after acceptance. If one accepted event later cannot be normalized, valid siblings can still appear, but the accepted event remains counted. Temporary processing failures are retried.

Hourly ingest usage counts accepted data in these fields:

  • inputs

  • outputs

  • metadata

  • context_metadata

  • events