ReflexioDeveloper Docs
Menu
All

Data Sources API

Connect trace providers, select traffic, preview and promote mappings, manage collection, and resolve attention records.

Use these enterprise REST endpoints to import existing Braintrust, Langfuse Cloud, and LangSmith Cloud traces. They do not require a second interaction-publish flow in your agent. For the dashboard workflow, see Connect existing traces. Request and response field tables are in Data-source schemas.

Authentication and project scope

There are two equivalent route prefixes:

PrefixAuthenticationDestination
/api/data-sourcesFull-access Reflexio API key in Authorization: Bearer …The project bound to the key.
/api/projects/{project_id}/data-sourcesFull-access API key or authenticated dashboard session bearerRequires X-Reflexio-Project: {project_id} matching the URL. API keys must also be bound to that project.

Limited API keys cannot manage sources. A project header cannot redirect an API key to another project. Send JSON bodies with Content-Type: application/json, including revision-checked DELETE requests. Provider credentials belong in connection request bodies, never in the Reflexio authorization header.

User-purge endpoints additionally require governance authorization; ordinary API keys cannot erase users. Use their project-scoped routes with a governance-authorized session. See Governance API.

export REFLEXIO_URL="https://www.reflexio.ai"
# Set REFLEXIO_API_KEY privately to a full-access key for the destination project.
curl --fail-with-body "$REFLEXIO_URL/api/data-sources" \
  -H "Authorization: Bearer $REFLEXIO_API_KEY"

IDs, revisions, and timestamps

A connection owns provider credentials. Its stream selects one external project and its traffic filters. A sample is temporary mapping evidence. Activating the stream creates the collection lifecycle. Do not interchange these IDs: the dashboard URL's source parameter is the connection ID, while collection API paths use the stream ID.

RevisionRead fromUsed by
Connection revisionConnection.revisionCredential rotation, stream selection, connection deletion.
Stream revisionStream.revision; activated status also returns stream_revisionSampling, draft history selection, activation; live-filter edits use stream_revision.
Lifecycle revisionActivated GET /streams/{stream_id}/status → revisionOperations, backfill extension, live-filter edits, mapping promotion, retry; deletion uses lifecycle_revision.
Mapping draft revisionGET /streams/{stream_id}/mapping → revisionMapping save/preview/validation use expected_revision; activation, promotion and retry use mapping_revision.

Re-read the relevant resource after a 409; do not blindly retry a stale revision. A mapping's validated_revision identifies the validated draft, while status's mapping_revision identifies the active mapping. Saving a draft is not promotion. Stream.status is the setup resource's draft marker; use collection status for current lifecycle state.

Lifecycle and status timestamps are Unix seconds. SampleWindow.start and end use timezone-aware ISO 8601 strings. Historical ranges are start-inclusive and end-exclusive; activation requires a past range with 0 < start < end <= now.

Endpoint index

Append these paths to either prefix above. A successful response is 200 unless another status is shown. A 202 accepts asynchronous work; it does not mean that records have been published.

MethodPathRequestResponse
GET(prefix itself)NoneInspection: connections, streams, sample summaries, capabilities.
GET/setup-contextOptional query connection_idNon-secret setup contract, mapping JSON Schema, capabilities, review link.
POST/connectionsConnectionInput201 Connection.
GET/connections/{connection_id}NoneConnection.
GET/connections/{connection_id}/projectsNoneDiscovery. Performs a provider read.
PUT/connections/{connection_id}/credentialRotationInputUpdated Connection.
DELETE/connections/{connection_id}RevisionInput{"deleted": true}.
PUT/connections/{connection_id}/streamStreamInputStream.
PUT/streams/{stream_id}/history-draftHistoryDraftInputSaved history, history_start, history_end.
POST/streams/{stream_id}/samplesSampleInput202 Sample.
GET/samples/{sample_id}NoneSample, including retained records.
GET/streams/{stream_id}/mappingNoneMappingDocument.
PUT/streams/{stream_id}/mappingMappingWriteSaved MappingDocument.
POST/streams/{stream_id}/mapping/initializeInitializeMappingInputGenerated/saved MappingDocument.
POST/streams/{stream_id}/mapping/upgrade-textMappingUpgradeInputUpgraded draft MappingDocument.
POST/streams/{stream_id}/previewPreviewInputPreviewResult; does not publish.
POST/streams/{stream_id}/mapping/validateValidateInputValidated MappingDocument.
GET/streams/{stream_id}/suggestions/modelNoneModel availability and data-sharing description.
POST/streams/{stream_id}/suggestionsSuggestInputAdvisory mapping candidates and measured sample coverage.
POST/streams/{stream_id}/activateActivateInput202 collection status.
GET/streams/{stream_id}/statusNoneCollection status plus evaluation settings.
POST/streams/{stream_id}/operationsOperationInputUpdated collection status.
PUT/streams/{stream_id}/backfill-limitExtendBackfillInputUpdated collection status.
PUT/streams/{stream_id}/traffic-filtersTrafficFiltersInputUpdated collection status; Braintrust only.
PUT/streams/{stream_id}/active-mappingMappingActivationInputUpdated collection status.
GET/streams/{stream_id}/heldOptional query afterUp to 50 attention records and next_cursor.
POST/streams/{stream_id}/retry-previewRetryInputProposed dispositions and preview_digest.
POST/streams/{stream_id}/retryRetryInput with preview digest202 proposed dispositions and queued: true.
GET/streams/{stream_id}/evidenceNoneUp to 20 recent import receipts with extraction/attribution details.
POST/streams/{stream_id}/purge-previewuser_id, request_idEstimated deletion counts and scope explanation. Requires governance authorization.
POST/streams/{stream_id}/purge-useruser_id, request_idUserEraseResult. Requires governance authorization.

Setup context and capabilities

GET /setup-context?connection_id={connection_id} returns a non-secret contract for setup clients. Omit the query for general capabilities; a sole connection is selected automatically. An unknown explicit connection ID returns 404.

FieldsPurpose
setup_version, api_base_path, destination_binding, project_idContract version, API route base and resolved destination.
providers, provider_regions, connection_limitSupported providers, regional choices and connection cap.
connection_id, stream_id, review_path, activationSelected resources and dashboard review handoff. The recommended setup flow ends in frontend review.
traffic_filter_pushdown, provider_filter_execution, traffic_filter_contractSupported paths/operators, AND combination, local-check behavior and candidate scope.
mapping_schema, mapping_scopes, mapping_versionsFull mapping JSON Schema and supported addressing/version contracts.
related_span_layouts, related_span_correlations, related_span_limits, related_span_fetch, sibling_joinsSupporting-span capabilities and bounded evidence limits.
sampling, field_guidance, identity_checks, mapping_aware_readsSampling strategy and mapping evidence capabilities.
automatic_read_retries, shared_connection_cooldown, historical_read_windowsProvider pacing and historical progress capabilities.
backfill_limitMessage units, initial 5,000 allowance, extension path, null-for-all option and whole-interaction admission. Live usage is independent of the historical budget; this does not promise concurrent Braintrust history/live scans.

Use this contract to discover supported behavior without transmitting provider credentials to a model or embedding them in a review URL.

Connect and select traffic

Each Reflexio project supports ten connections, including unexpired setup drafts. Each connection selects one external project. Pausing or disabling retains its slot. Connections never return their stored secret.

ProviderproviderregionCredential fields
Braintrustbraintrustusapi_key
Langfuse Cloudlangfuseus, eu, jp, hipaa-usapi_key (secret key), public_key
LangSmith Cloudlangsmithus, euapi_key; optional workspace_id

Provider defaults are Braintrust and US. Private provider endpoints are not supported. For example, POST this JSON to /connections using your own read credential:

{"name": "Support traces", "provider": "braintrust", "region": "us", "api_key": "<provider-read-key>"}

Discover projects, then PUT /connections/{connection_id}/stream:

{
  "revision": 1,
  "external_project_id": "<ID returned by discovery>",
  "filters": [{"path": "span_attributes.name", "op": "eq", "values": ["answer"]}]
}

revision is the connection revision. The workspace is resolved from discovery. Selection also advances the connection revision; read the connection again before rotating credentials, reselecting, or deleting. Before activation, stream selection can change. After activation, provider, region, external project/workspace, and original activation timestamp stay fixed. Use the live-filter endpoint for supported active edits instead of selecting a new stream.

Filter contract

Filters are combined with AND. An empty list selects all candidate traffic. At most ten filters are accepted. Supported dotted paths are metadata.*, span_attributes.name, and tags (maximum 160 characters).

OperatorvaluesMeaning
eqExactly one stringScalar equals the value, or an array contains a matching value.
in1–20 stringsScalar or any array member matches any listed value.
existsEmpty list (or omitted)Field exists and is not null; empty containers still exist.

Each value is 1–512 characters. Preserve commas and whitespace literally; values are separate JSON array elements, not a comma-separated string. Local checks can compare numbers through their string representation and booleans as "true" or "false".

Braintrust applies supported filters and eligibility time bounds before pagination, with local checks for correctness. filter_execution reports before_download, partial, or after_download. Langfuse and LangSmith filter after download. Supporting spans can be read outside the candidate filters only as context for an eligible interaction, not as additional import candidates.

Credential rotation and deletion

PUT /connections/{connection_id}/credential with the connection revision and replacement credential fields for that provider. The new key must reach the selected project. Rotation invalidates retained sample evidence; fetch a fresh sample before mapping validation. The selected provider dataset remains unchanged.

DELETE accepts {"revision": 2} for a setup draft. For an activated source, also supply its current lifecycle_revision. Deletion removes credentials, configuration, and pending payloads. Imported interactions and deduplication receipts remain. It does not delete the provider's traces and is not a user-data erasure operation.

Sample and prepare a mapping

  1. Optionally PUT /streams/{stream_id}/history-draft with the stream revision, history (default true), and optional Unix-second bounds. This saves setup choices only; it neither activates collection nor changes an activated source.
  2. POST /streams/{stream_id}/samples with the stream revision and, if desired, an explicit sample_window.
  3. Poll GET /samples/{sample_id} until complete, failed, or expired.
  4. Initialize a mapping from examples or save one manually.
  5. Preview, inspect blockers and example output, then validate the exact saved draft.
  6. Explicitly activate or promote the validated revision.
{
  "revision": 1,
  "sample_window": {
    "start": "2026-09-01T00:00:00Z",
    "end": "2026-09-08T00:00:00Z"
  }
}

Samples retain up to 50 records, expire after 24 hours, and are bounded evidence, not a count of all matching traffic. Braintrust samples up to seven time buckets; other providers use bounded pages. Inspect truncated, coverage, buckets, code, and retry_at. Sampling without historical import may still inspect older traffic to help configure mappings; this does not make that traffic eligible for import.

Manual mapping, initialization, and advisory suggestions

GET /mapping returns the current draft, its revision, and validated_revision. PUT /mapping takes expected_revision and a complete definition; use revision 0 for a new draft. Saves increment the draft revision and invalidate its validation. They do not replace an active mapping. For example, this complete MappingWrite selects the first text block while keeping identity and completion explicit:

{
  "expected_revision": 0,
  "definition": {
    "version": 1,
    "rules": [{
      "name": "Answer",
      "fields": {
        "user": {"path": "/metadata/user_id"},
        "session": {"path": "/metadata/session_id"},
        "input": {"path": "/input"},
        "output": {"path": "/output/message/content", "transform": "first_text_block"},
        "version": {"path": "/metadata/agent_version"},
        "references": {"path": "/metadata/reflexio/retrieved_learnings"},
        "source": {"path": "/metadata/environment"},
        "timestamp": {"path": "/created"},
        "completion": {"path": "/metrics/end"}
      }
    }]
  }
}

Adapt these pointers to observed fields; the example does not create missing outputs.

POST /mapping/initialize takes sample_id and expected_revision (default 0). It sends up to three representative masked examples, including message content, to the configured generation model and saves a generated draft. Each example is bounded to 64 KB. Calling with revision 0 preserves an already-saved draft; pass its current revision to explicitly regenerate. Review, validation, and promotion remain separate. Model failures do not authorize ingestion.

GET /suggestions/model returns available, model, data_sent, and usage. The separate POST /suggestions operation requires a saved draft, sample_id, expected_revision, sample_digest from preview, and consent: true. It sends a bounded inventory of field names and types, withholding dialogue values. Its response includes candidates, missing, revision/sample provenance, model, prompt_version, measured_coverage, and automatic_application: false. Apply chosen changes by saving a mapping explicitly. This endpoint does not regenerate or promote an active definition.

Preview and validation

POST /preview with:

{"sample_id": "<sample-id>", "expected_revision": 3}

An optional definition previews an unsaved proposal without saving it. The result includes records, ready, held, excluded, sourceRecords, messages, sample_digest, mapping_revision, mapping_digest, policy_digest, blockers, rule_coverage, field_guidance, and advisory: true.

Each proposal includes resolved fields, proposed messages, disposition, errors, diagnostics, provenance, learning eligibility and attribution capture. Counts apply only to this sample. Ready in preview does not mean published.

To validate, POST the same sample and revision to /mapping/validate, adding the returned sample_digest. Omit definition when validating: this endpoint only validates the saved draft and rejects a supplied definition, even if it matches. Validation requires usable ready evidence (or an already-imported history replay) and rejects overlapping rule matches. Some other sampled records can remain held. Read validated_revision from the returned MappingDocument before activation or promotion.

First matching text and existing draft upgrades

For input/output mappings, first_text_block targets one message's content array:

{"scope": "current", "path": "/output/message/content", "transform": "first_text_block"}

It returns the first direct, non-whitespace-only string text from an untyped block or a block with type: "text", in array order. It skips reasoning, tool, image, and nonmatching entries. It does not recurse or search across conversation messages. It rejects conversation-shaped arrays, arrays longer than 100 blocks, and selected text longer than 100,000 characters. An oversized first match fails rather than falling through to a later answer. No usable answer remains held.

text_blocks explicitly joins all usable direct text blocks with newlines. Existing indexed mappings and active definitions retain their existing behavior. New suggestions prefer first_text_block.

POST /mapping/upgrade-text with {"expected_revision": 3} to revise existing indexed input/output paths and applicable fallback paths in the draft. The upgrade uses the containing content array and removes corresponding index-specific existence conditions, preserving unrelated conditions. An unchanged mapping is a no-op. Preview and validate the result, then explicitly PUT /active-mapping; retry existing held records separately.

Activate and control collection

POST /streams/{stream_id}/activate:

{
  "revision": 1,
  "mapping_revision": 3,
  "operation_key": "support-source-activation-1",
  "history": false
}

revision is the stream revision. operation_key is a caller-chosen 1–100 character idempotency key: repeating the same key and activation payload returns status; a conflicting activation returns 409. With history: true (default), omitted bounds select the seven days ending at activation. With history: false, omit both bounds. A custom historical end leaves any gap before activation excluded.

Braintrust uses selected history → live traffic. History reads only the selected interval, oldest first. It switches to live after the historical scan finishes, its message budget is reached, or remaining history is cancelled. With history disabled, its first live query starts at activation, without paging through excluded history. Live reads retain the original activation lower bound, including traffic that arrived during backfill, until an explicit live-filter edit establishes a later bound.

Live imports have no total message limit. Bounded requests and provider cooldowns still apply. The initial historical budget is 5,000 individual messages, not 5,000 traces or conversations. A complete interaction is never partially imported to fill the remaining allowance. An interaction that does not fit is deferred; unfinished history can resume after extending the budget.

Successful live cycles normally schedule their next run about 30 seconds after completion. Collection is asynchronous, with provider pacing, retries, and backpressure; there is no guaranteed fixed polling interval or import latency. Check read and import status separately. Provider retention and incomplete traces can limit completeness. Langfuse and LangSmith keep independent live collection during historical backfill; ongoing scans revisit seven days for late or edited records. Upstream deletion mirroring is unsupported.

Lifecycle operations

POST /operations with the current lifecycle revision:

{"revision": 4, "action": "pause"}
ActionEffect
pauseActive → paused. Retains configuration and progress.
resumePaused → active. Resumes collection.
disableStops collection/admission while retaining configuration and progress.
enableDisabled → active, after verifying access to the selected provider project.
cancel_backfillCancels remaining selected history; staged historical records are held for review. Preserves source lifecycle; Braintrust can collect live traffic when active.

Invalid transitions and stale revisions return 409. Pausing does not reset budgets. Cancelling is distinct from completing the historical date range.

Extend historical allowance

PUT /backfill-limit with {"revision": 4, "message_limit": 20000}. The limit is a new cumulative total, not an increment. It must exceed the current limit and meet backfill.required_total when present. A JSON null limit selects all remaining matching history; the field itself is required. Valid finite limits are positive integers no greater than 9,007,199,254,740,991.

The operation retains dates, original historical filters, deduplication, and lifecycle. For Braintrust it resumes unfinished/deferred history before returning to live. History that was not selected, was cancelled, is already unlimited, or is fully scanned without deferred work is not extendable. A paused source stays paused. Historical usage never includes live messages.

Edit live Braintrust filters

Read status, then PUT /traffic-filters:

{
  "revision": 4,
  "stream_revision": 2,
  "filters": [{"path": "metadata.environment", "op": "in", "values": ["staging", "production"]}]
}

Use the lifecycle revision and stream_revision from that status response. Only activated Braintrust sources support this operation; paused/disabled sources retain their lifecycle. An actual change increments both revisions, invalidates incompatible live pagination and in-flight collection, and schedules work subject to lifecycle. The response includes saved live_filters, original historical_filters, filter_effective_at, live_created_from, and updated revisions.

The fixed lower bound is max(activation_at, filter_effective_at), inclusive. Older unread traffic and later updates to older spans are excluded from the new live scan, even if the filters were broadened. Polling does not move this bound. Equivalent filters are a no-op: revisions and the effective timestamp do not advance.

Historical scans, counts, deferred records, and later budget extensions use the original historical filters. Existing staged records keep their processing contract; held records are not bulk retried or reclassified. Published interactions are unchanged. Actual edits invalidate samples and draft validation while retaining draft content and the active mapping. Read a fresh sample before validating again.

Read collection status

Draft status contains lifecycle: "draft", activation_available, activation_draft, and provider_read. Activated status adds the following fields. GET /status also adds evaluation_settings; mutation responses need not include that augmentation.

FieldsMeaning
lifecycle, revision, phaseLifecycle (active, paused, disabled), optimistic-lock revision, and backfill/live phase.
stream_revision, mapping_revision, active_mapping_definitionCurrent stream revision and the mapping actually used for new records.
activation_at, history_start, history_endOriginal activation and selected historical bounds.
live_filter_editing, live_filters, historical_filtersWhether edits are supported, current live selection, and retained historical selection. Empty filters mean all traffic in scope.
filter_effective_at, live_created_fromLast actual live-filter cutover (null before an edit) and inclusive live lower bound.
traffic_selectionProvider/local filter execution summary for live traffic.
last_read_at, live_last_read_at, last_import_atSuccessful read, live read, and successful canonical import times. A read alone does not prove import.
last_error, live_last_error, provider_readError codes and provider pacing. provider_read contains waiting, retry_at, and code.
counts, pending_context, held_for_reviewDisposition counts, records waiting for supporting spans, and held records outside that automatic context wait.
admitted_records, admitted_messagesImport receipt count and published message count, not profile count. Counts cover the dataset, including prior imports.
backfillmessage_limit, imported_messages, required_total, state.
history_progressEstimated count status, population, scanned, total, remaining, counted_at, complete, estimate_exceeded; may be null.
history_position, history_pages, page_count, initial_scan_completeCollection checkpoint/progress indicators; use backfill.state to distinguish the historical outcomes.
live_collection_waiting_for_historyBraintrust live collection is waiting for its sequential historical scan.
coverage, retention_seconds, evaluation, evaluation_settingsCoverage limits, held-evidence retention and evaluation eligibility/settings.

backfill.state is one of disabled, cancelled, complete, running, limit_reached, needs_higher_limit, or needs_review. Budget exhaustion is not historical completion. Estimated count exhaustion does not finish a scan; the date range must be exhausted, and queued/held records may still need processing.

Attention records, evidence, and retries

GET /held?after={cursor} returns up to 50 rows in ID order. Continue with next_cursor until null. Despite its name, it can include held, conflict, expired, erased, and temporarily settling ready records. Returned fields are id, event_id, disposition, reason, capture, event_time, available_at, expires_at, source_digest, mapping_revision, canonical_request_id, history_diagnostics, retry_eligible, and source_url.

StatePublished?Next step
readyNot yet admitted for this candidate.Wait for processing/required settling.
heldThis candidate has not been admitted.Inspect reason; correct mapping or source evidence and explicitly retry eligible records.
conflictA prior version may already be published; the conflicting change is not an automatic replacement.Inspect receipts and the conflict reason.
expiredRetained candidate evidence is no longer retryable.Inspect the reason and provider retention before recovery.
erasedEvidence has been removed under erasure policy.Do not retry erased data.

Attribution warnings are different from import blockers. A published response can have missing, empty, malformed, ambiguous, or unresolvable learning attribution. Use /evidence to confirm publication rather than treating every warning as a failed import. Missing input/output or reliable user/session identity remains held; the connector does not manufacture those values.

GET /evidence returns {"records": [...]} for the latest 20 receipts. Each includes event_id, request_id, interaction_ids, admission, message_captures, history_diagnostics, capture, source_url, extraction_status, user_id, session_id, agent_version, and per-agent responses with interaction_id, capture, and references. Imported messages, extraction, and evaluation are separate stages; a receipt does not prove a profile was generated.

Promote and retry deliberately

PUT /active-mapping with {"revision": 4, "mapping_revision": 3} to promote a validated draft. The response advances lifecycle revision. New records use that mapping; queued records retain their saved mapping unless explicitly retried.

Then POST /retry-preview with current revisions and inbox record IDs from /held, not provider event IDs:

{"revision": 5, "mapping_revision": 3, "record_ids": ["<held-record-id>"], "append_late": false}

The response contains preview_digest, queued: false, and records. Each proposal contains id, disposition, errors, capture, messages, and history_group. Preview may fetch missing provider evidence. It does not publish or enqueue admission. To execute, POST the exact selection to /retry, adding that preview_digest. The 202 response has queued: true; poll status/evidence for actual admission.

Select 1–50 retained, unexpired held records. Admitted, erased, expired, or otherwise changed selections are rejected. Late historical or cancelled-backfill records require append_late: true, explicit preview, then execution; consumed learning windows are not rewritten. A changed record, mapping, or lifecycle can invalidate the digest; preview again after a 409. A paused source remains paused after retry.

User erasure

POST /purge-preview or /purge-user with user_id and an audit request_id, using the additional governance authorization described above. The preview returns estimated counts and a human-readable scope; execution uses the existing organization-level user-erasure workflow and returns UserEraseResult.

The stream is an authorization/context anchor, not a source-only erasure boundary. User erasure covers the organization; unresolved source payloads and samples are conservatively cleared in the selected project. Read the preview scope and Governance API before executing. Deleting a connection is a separate operation and does not erase admitted user data.

Errors and recovery

Source business errors use this shape (request-validation and authentication errors can have different detail shapes):

{"detail": {"code": "conflict", "message": "Mapping changed; reload its draft.", "retry_after_seconds": 0}}
StatusTypical meaningRecovery
400Missing/mismatched project header or invalid operation input.Correct routing or request fields.
401/403Invalid credential, insufficient role, project mismatch, or forbidden provider project.Use the correct project and authorized credential.
404Source, stream, sample, or project is unavailable in this scope.Refresh inventory; check IDs and destination.
409Stale revisions, invalid lifecycle transition, stale retry preview, or non-retryable selection.Refresh state and preview before retrying.
410Expired setup/sample evidence.Read fresh evidence or restart expired setup.
422Schema/semantic validation, unsupported provider operation, missing consent, or invalid provider credentials.Inspect detail.code/validation details and fix the input.
429/503Provider pacing/unavailability or unavailable model suggestions.Honor Retry-After when supplied; use provider_read and retry_at.
502Provider response/pagination could not be safely processed.Inspect the error code; preserve checkpoints and retry according to provider status.

Do not trigger discovery every time you read status or render a source page. It makes a live provider request and can fail independently of viewing saved configuration. The dashboard discovers during setup or an explicit project-name lookup, not when opening an activated source's Settings. Invalid credentials still surface when a provider read is actually requested.