Skip to content

Integration API

Use the Tuor API from your backend service to send model traces and retrieve reviewed outputs. The Web Console handles organization setup, project creation, API key management, analytics, and reviewer workflows.

All integration endpoints are versioned under /v1. Examples use https://api.tuor.dev as the base URL.


Authentication

Send your API key in the X-API-Key header:

X-API-Key: tuor_AbCdEf123...

API keys are created in the Web Console and are scoped to the organization that issued them. Store them server-side only; do not expose them in browser code.


Limits and payload constraints

The default ingest limit is 200 trace creates per minute. Every integration endpoint has its own per-route limit and returns 429 Too Many Requests with Retry-After when exceeded.

Every JSON payload field is independently validated:

  • Maximum size: 5 MB per field.
  • Maximum nesting depth: 10 levels.

Oversize or over-nested payloads are rejected with 422 Unprocessable Entity.


Core endpoints

Method Path Use when
POST /v1/traces/ Send an ordered model trajectory and structured output to Tuor for review.
GET /v1/traces/{trace_id} Fetch one trace and its current review result.
GET /v1/traces/ List or filter traces by project, status, or tag.
GET /v1/traces/export Stream reviewed traces as JSONL for evals, dashboards, or training pipelines.
GET /v1/tags/ List tags and copy IDs for trace tagging or export filters.
POST /v1/traces/{trace_id}/tags Attach tags for routing, cohorting, or downstream filtering.
DELETE /v1/traces/{trace_id}/tags/{tag_id} Remove a tag from a trace.

Webhook receiver setup is covered separately in Webhooks.


Send a trace

POST /v1/traces/

Creates a new trace with status pending.

Request body

Field Type Required Notes
project_id string yes The project that owns this trace. Copy it from the project's ID column in the Web Console.
spans array yes* Ordered provider-neutral trajectory. Create spans omit id; Tuor assigns one to every returned span.
model_input object deprecated* Legacy input accepted during the RM-76 compatibility window. Supply exactly one of spans or model_input.
model_output object yes Structured JSON of what your model produced. Nested object leaves render as editable dot-path fields.
output_schema object no Per-field schema that gives a path a typed reviewer control, keyed by dot path. Each entry is one of three types: enum (one-of-N label picker, e.g. {"invoice.status": {"type": "enum", "options": ["paid", "due"], "multi": false, "open": true}}), boolean (true/false toggle, {"type": "boolean"}), or json (an arbitrary-JSON subtree kept as a single editable value rather than expanded into child rows, {"type": "json"}). Paths absent from the schema are unconstrained JSON and their control is inferred from the value's type. Validated on ingest/correction, and included in exports.
trace_config object no Metadata such as model, temperature, internal_run_id, or prompt_version_id. Included in exports.
curl -X POST "https://api.tuor.dev/v1/traces/" \
  -H "X-API-Key: $TUOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "proj_abc123",
    "spans": [
      {
        "type": "message",
        "role": "instruction",
        "content": [
          {"type": "text", "value": "Extract the company name and return JSON."}
        ]
      },
      {
        "type": "message",
        "role": "user",
        "content": [
          {"type": "text", "value": "Invoice from Acme Corp."}
        ]
      }
    ],
    "model_output": {
      "invoice": {
        "company": "Acme Corp"
      }
    },
    "trace_config": {
      "model": "gpt-4o",
      "internal_run_id": "run_01j2abcde"
    }
  }'

Span shapes

spans is a flat ordered array. Supported top-level types are:

{"type": "reasoning", "content": "I should verify the total."}
{
  "type": "tool_call",
  "kind": "request",
  "tool_call_id": "lookup_1",
  "name": "lookup_invoice",
  "content": {"invoice_id": "inv_123"}
}
{
  "type": "tool_call",
  "kind": "response",
  "tool_call_id": "lookup_1",
  "content": {"total": 1250.45}
}

Messages contain text, image, document, or unknown blocks. Base64 media uses:

{
  "type": "image",
  "source": {
    "type": "base64",
    "media_type": "image/png",
    "filename": "chart.png",
    "value": "iVBORw0KGgo..."
  }
}

filename and tool_call_id are optional. Unsupported values and recognized values that fail validation are losslessly returned as { "type": "unknown", "content": <original JSON> } for spans or { "type": "unknown", "value": <original JSON> } for content blocks. As with other API schemas, extra fields on recognized values are ignored. Missing, orphaned, duplicated, ambiguous, and out-of-order tool relationships are accepted and rendered as supplied.

Response 201 returns a TraceDetailResponse: every persisted trace column, structured tags, and the trace event timeline. The most important fields for integrations are:

Field Meaning
id Store this if you want to fetch the trace later.
status Starts as pending; later becomes approved, rejected, or corrected.
spans Canonical ordered spans, including Tuor-generated internal IDs. Always present after creation.
model_input Deprecated original value retained for legacy writes. Span-native writes return null.
model_output The original structured review target you sent.
output_schema The output field schema you sent, or null.
corrected_output Reviewer-edited output, present after a correction.
final_output The authoritative result: original output if approved, corrected output if corrected, null if rejected or still pending.
trace_config Your metadata, round-tripped unchanged.
tags Active tag summaries attached to the trace, shaped as {id, name, color}.
events Public TraceEventResponse timeline entries for the trace.
version Optimistic-lock version for advanced lifecycle writes.

Read review results

GET /v1/traces/{trace_id}

Fetch one trace by ID. Use this when your system wants to poll for the final review outcome. The detail response uses the trace shape above, but returns tags as structured {id, name, color} summaries and includes an events array of public TraceEventResponse objects.

curl "https://api.tuor.dev/v1/traces/trace_abc123" \
  -H "X-API-Key: $TUOR_API_KEY"

GET /v1/traces/

List traces with pagination and filters. Each item uses TraceDetailResponse: every persisted trace column plus active tag summaries and the trace event timeline.

Parameter Type Notes
project_id string Restrict to one project.
status pending | approved | rejected | corrected Filter by review outcome.
tag string Restrict to traces carrying this tag ID.
skip int Offset for pagination. Default 0.
limit int Page size. Default 50, max 500.

Export reviewed data

GET /v1/traces/export

Streams one JSON object per line. Use this for offline evals, dashboards, prompt analysis, or training-data jobs.

Parameter Type Notes
project_id string Restrict to one project.
status string Commonly approved or corrected for training/eval datasets.
tag string Restrict to traces carrying this tag ID.
from_date, to_date ISO 8601 Filter by created_at.
exclude_fields comma-separated paths Remove nested keys through arrays. During migration, exclude both canonical and legacy media paths if the export may include rows awaiting backfill.
curl "https://api.tuor.dev/v1/traces/export?status=corrected&exclude_fields=spans.content.source.value,model_input.image_base64,model_input.imageBase64,model_input.pdf_base64,model_input.pdfBase64" \
  -H "X-API-Key: $TUOR_API_KEY"

Each JSONL row uses TraceExportResponse. Datetimes are ISO 8601 strings, status is its value string, and tags are active tag names. Canonical spans are always included; deprecated model_input contains the original value for legacy writes and is null for span-native writes. Trace events are not included.

{
  "id": "trace_abc123",
  "created_by": "user_2def3gh",
  "org_id": "org_2xyz789",
  "project_id": "proj_abc123",
  "status": "corrected",
  "model_input": null,
  "spans": [
    {
      "id": "span_abc123",
      "type": "message",
      "role": "user",
      "content": [{"type": "text", "value": "..."}]
    }
  ],
  "model_output": { "...": "..." },
  "corrected_output": { "...": "..." },
  "final_output": { "...": "..." },
  "trace_config": { "...": "..." },
  "output_schema": null,
  "version": 2,
  "created_at": "2026-05-20T10:00:00Z",
  "updated_at": "2026-05-20T14:19:55Z",
  "updated_by": "user_2def3gh",
  "last_reviewed_at": "2026-05-20T14:19:55Z",
  "last_reviewed_by": "user_2def3gh",
  "deleted_at": null,
  "deleted_by": null,
  "deleted_via": null,
  "restored_at": null,
  "restored_by": null,
  "tags": ["critical", "q2-audit"]
}

Exports intentionally share the public trace contract rather than raw ORM serialization. Most downstream jobs can rely on status, final_output, trace_config, and tags; fetch GET /v1/traces/{trace_id} when you also need the event timeline.


Tags

Tags are optional. Use them when you need to route review work or export a specific cohort.

Create and manage tags in the Web Console under Settings -> Tags. Integration code needs tag IDs, not tag names. To discover IDs, call GET /v1/tags/ and store the returned id for each tag you plan to apply.

curl "https://api.tuor.dev/v1/tags/" \
  -H "X-API-Key: $TUOR_API_KEY"

An abbreviated response includes each tag's id, name, color, and description:

[
  {
    "id": "tag_critical",
    "name": "critical",
    "color": "#ef4444",
    "description": "High-priority reviews"
  }
]
curl -X POST "https://api.tuor.dev/v1/traces/trace_abc123/tags" \
  -H "X-API-Key: $TUOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "tag_ids": ["tag_critical"] }'

A trace can have up to 10 tags.


Advanced

Most integrations do not need these endpoints on day one.

Area Endpoints Notes
Prompt versions GET /v1/projects/{project_id}/prompts, POST /v1/projects/{project_id}/prompts, POST /v1/projects/{project_id}/prompts/refine, POST /v1/projects/{project_id}/prompts/accept-refinement Use when your service fetches active prompts from Tuor at runtime. See Dynamic Prompts.
Trace lifecycle automation POST /v1/traces/{trace_id}/review, POST /v1/traces/{trace_id}/reset, DELETE /v1/traces/{trace_id}, POST /v1/traces/{trace_id}/restore The Web Console is the normal review surface. These endpoints require expected_version to prevent conflicting writes.
Project and tag administration /v1/projects/*, /v1/tags/* Usually handled in the Web Console. Useful only for provisioning automation.

Error responses

Errors are returned as JSON:

{ "detail": "Invalid or revoked API key" }

Common status codes:

Status Meaning
400 Malformed request.
401 Missing or invalid API key.
402 Trace limit reached.
403 API key is valid but does not have an organization context.
404 Resource does not exist or is not visible to this organization.
409 Optimistic-lock mismatch or forbidden lifecycle transition.
422 Payload exceeds size/depth limits or fails schema validation.
429 Rate limit exceeded. Respect Retry-After.