Skip to main content
All SDKs POST to the same set of endpoints under {serviceUrl}/api/sdk/. This page documents the wire protocol so you can integrate directly without using an SDK, or debug SDK behavior. Base URL defaults to https://bitfab.ai.

Authentication

All endpoints require the API key in the Authorization header:
Missing, empty, or invalid keys return 401 Unauthorized.

Common Request Fields

The SDKs append these fields to most request bodies:

Endpoints

POST /api/sdk/functions/lookup

Look up a function by name. Blocking. Request:
Response 200:
Response (not found): { "id": null } - SDKs raise a typed error pointing users to /functions.

POST /api/sdk/functions/{functionId}/traces

Record a trace produced by a server-side function execution (e.g. client.call(...)). Fire-and-forget. Request:
Response: 200 OK.

POST /api/sdk/externalSpans

Record a single span produced by withSpan / @span / Span / bitfab_span. Fire-and-forget. Request:
Response: 200 OK.

POST /api/sdk/externalTraces

Record the completion of a root span’s trace. Sent once per trace when the outermost span ends. Fire-and-forget. The request’s top-level id is the canonical Bitfab trace UUID. The nested raw trace ID remains an ingestion correlation value.

GET /api/sdk/traces/{traceId}/span

Fetch one persisted span without loading the full trace. traceId and the optional exact id selector are canonical Bitfab UUIDs. Select exactly one of:
  • id={canonicalSpanId} for an exact match
  • name={spanName} with optional occurrence=first|last|{zeroBasedIndex}; the default is last
The response includes the span’s canonical id, traceId, and parentSpanId, plus its name, type, input, output, contexts, prompt, metadata, metrics, errors, and timestamps. It never exposes ingestion source IDs.

PATCH /api/sdk/traces/{traceId}

Update a detached current trace by its canonical Bitfab ID. The body accepts appendContexts, mergeMetadata, and setSessionId. Request:

POST /api/sdk/replay/start

Begin a replay session. Blocking. Timeout: 30 s on the client side. Request:
name is an optional display name stored on the resulting experiment/test run. limit (1-5,000, default 5) caps how many recent traces are fetched. When traceIds is present (max 100 entries) the ID list determines the count and limit is ignored; the field stays accepted because older SDKs always send a defaulted value. When datasetId is present, the dataset’s full trace list determines the count and limit is ignored. The dataset is validated against the organization; a foreign ID returns a 400. graderIds (max 100) attaches graders directly to this run, independent of the dataset’s own graders; the resulting experiment is graded by the union of these and the dataset’s runnable graders at completion. Each id must be an active grader in the same organization and trace function, or the replay returns a 400. A replay with no dataset can still carry graders this way. Response 200:
Each items[] entry carries reference metrics from the original trace being replayed: durationMs is the end-to-end wall time (integer milliseconds), tokens is an object with input/output/cached/total counts, and model is the model id. Any field may be null when the underlying trace didn’t capture it. The replayed run’s own token usage is returned later by /api/sdk/replay/complete (see below), once its spans are persisted.

POST /api/sdk/replay/complete

Signal that a replay session finished. Request:
Response:
traceIds maps each SDK-generated replay trace id to the persisted server trace id. tokens is each replay trace’s token usage, keyed by server trace id and aggregated from the freshly-uploaded replay spans (the same source the experiments view reads), so it’s the replayed run’s cost rather than the original’s; a trace with no token data maps to null. traceCount is how many traces the server persisted for the run. The SDK maps tokens onto each item to populate its replay tokens.

GET /api/sdk/externalSpans/{id}

Fetch a specific external span by ID. Used by replay internals. Returns the rawSpan object.

Serialization

  • Inputs and outputs in span_data.input / span_data.output are serialized using superjson by the TypeScript SDK. The input_meta / output_meta fields are the superjson meta descriptors.
  • Python, Ruby, and Go SDKs use JSON-compatible fallbacks. Objects that don’t round-trip through JSON are coerced to string via the SDK’s serialize helper.

Error Responses

SDKs swallow all non-2xx responses on fire-and-forget endpoints and log to stderr. Blocking endpoints (lookup, replay/start) raise typed errors.