Clear ExchangeDocs Live demo

SPUR telemetry events

Clear Exchange records usage as SPUR Coalition Content Telemetry v1.0 events (Apache-2.0). Field names, event types and enum values come from the published v1.0 JSON schemas (telemetry-event.json, telemetry-event-batch.json, telemetry-session.json). Code: src/telemetry/spur.ts.

Provisional fields

Every field on this page comes from the v1.0 schemas except ext_clear_exchange, which the exchange adds to every event it stores:

"ext_clear_exchange": {
  "provisional": true,
  "entitlement_id": "ent_9989d9af-4391-45ba-b6a8-5aac031eb7cc",
  "offer_id": "off_0f0ef321-f551-42cc-bb22-cf95b7f6be9b",
  "publisher_id": "pub_fieldnote",
  "supply_id": "local-catalogue",
  "usage": "display_snippet"
}

PROVISIONAL. This object is the exchange's own correlation data. It is not part of the SPUR standard (which permits additional properties), and its name and contents may change. Agents do not send it; the exchange sets it.

The cross-checks against the entitlement and the licence-breach warnings described below are also the exchange's own application rules, not SPUR requirements.

Stages and who reports them

StageSPUR event typeReported by
retrievecontent_retrievedThe exchange, on every successful GET /v1/content/{id}
groundcontent_groundedThe agent, via POST /v1/telemetry
citecontent_citedThe agent
presentcontent_presentedThe agent
engagecontent_engagedThe agent

Telemetry references the other two formats by identifier only: license_ref is the entitlement jti, and terms_ref is the rate card ref (rate_card_id@vN).

content_retrieved (emitted by the exchange)

{
  "document_type": "event",
  "schema_version": "1.0",
  "session_id": "52bb3cae-fe4f-4d40-8d5d-322f8c9d1c0e",
  "agent_id": "my-agent",
  "started_at": "2026-10-28T10:51:10.370Z",
  "event": {
    "id": "2dc312b9-38e9-4beb-9738-4f2135654744",
    "type": "content_retrieved",
    "timestamp": "2026-10-28T10:51:17.501Z",
    "source_role": "index",
    "content_telemetry_id": "3f2b8c1e-9a4d-4e7b-8c2a-1d5e6f7a8b9c",
    "content_url": "https://fieldnote.example/energy/2026/04/heat-pumps-cold-climates-field-data",
    "content_id": "fn-2026-0153",
    "license_ref": "ent_9989d9af-4391-45ba-b6a8-5aac031eb7cc",
    "terms_ref": "rc_fieldnote@v1",
    "data": {
      "media_type": "text",
      "content_depth": "full",
      "purpose": "inference",
      "response_status": 200,
      "response_bytes": 691
    },
    "ext_clear_exchange": { "provisional": true, "...": "as above" }
  }
}
  • source_role is index, the role SPUR gives an intermediary that serves content to the agent.
  • content_telemetry_id is the agent's Content-Telemetry-ID request header when it is a UUID, otherwise null.
  • content_depth is always full and purpose always inference in the MVP.

Agent batches (POST /v1/telemetry)

The agent sends a SPUR event_batch with its entitlement as the Bearer token. A full example is in the API reference.

Batch fields

FieldRule
document_type"event_batch"
schema_version"1.0"
session_idUUID. Required unless ctx_token is given. Use the session_id from the query or accept response; a different one is accepted with a session_mismatch warning.
ctx_tokenOptional; must match ^ct_[A-Za-z0-9_-]{16,240}$.
agent_idRequired; must equal the entitlement's sub (otherwise forbidden).
started_atRequired date-time. Use session_started_at from the query or accept response.
eventsNon-empty array.

Event fields

Every event needs type (one of the four agent stages) and timestamp (date-time). The exchange fills in content_id, license_ref and terms_ref from the entitlement when they are omitted; if given, content_id and license_ref must match the entitlement (otherwise forbidden). source_role must be omitted or "agent".

id: required on content_cited and content_presented (other events can refer to them). Optional on content_grounded and content_engaged, but an event without an id gets a fresh one and cannot be deduplicated, so agents that retry should always set ids. Ids must be distinct within a batch.

TypeRequiredOptional (validated)
content_groundeddata.scope: session or turndata.provenance: agent_fetched, agent_cached, third_party_sourced; data.chars_ingested, data.tokens_ingested (non-negative integers); data.content_hash (sha256:<64 hex>)
content_citedid, output_id, data.citation_type: direct_quote, paraphrase, reference, contradiction, unclassifieddata.position: primary, supporting, mentioned, unclassified; data.excerpt_chars, data.excerpt_tokens (non-negative integers)
content_presentedid, output_id, data.presentation_kind: content or source_reference; data.presentation_type (non-empty string)citation_id (only valid on this type)
content_engagedpresentation_id matching a content_presented id in this batch or already recorded for this entitlement (not needed when a ctx_token is present)ctx_token (only valid on this type)

Other fields allowed by the SPUR schema (such as turn_id or output_element_id) are stored as sent.

Licence warnings

The exchange compares the reported use with the licence and returns warnings (the batch is still accepted):

CodeWhen
terms.display_not_licensedcontent_presented with presentation_kind: "content" under a grounding_only licence.
terms.snippet_too_longcontent_cited with excerpt_chars above max_snippet_chars under a display_snippet licence.
session_mismatchBatch session_id differs from the session the entitlement was bought in.

For openly licensed content (Wikinews, Wikipedia) these warnings are advisory: the open licence governs.

Behaviour

  • Atomic. Any error rejects the whole batch: 422 telemetry_invalid, or 403 telemetry_forbidden when any error is a mismatch with the entitlement. details lists every {path, code, message}.
  • Idempotent per event id, per entitlement. Already-recorded ids are returned in duplicate_event_ids and not counted again; a fully replayed batch returns 202 with accepted: 0. The set of seen ids is held in memory and resets on restart.
  • Late reporting. The entitlement is accepted for TELEMETRY_GRACE_SECONDS (default 7 days) after exp.
  • Storage. Each accepted event is stored as a SPUR standalone event document (document_type: "event"), wrapped with received_at, emitter (exchange or agent) and entitlement_id. Operators read them at GET /v1/admin/telemetry.

How telemetry feeds routing and ranking

Each source has a telemetry prior: the share of the four agent stages reached per paid retrieval, smoothed toward 0.5 by PRIOR_STRENGTH pseudo-observations. It nudges routing and adds PRIOR_WEIGHT × (prior − 0.5) to relevance (scoring.prior_adjustment on each offer). GET /v1/supply shows each source's stage counts and prior. See Architecture.

Not built yet

The SPUR telemetry manifest (/.well-known/content-telemetry.json) and delivery of events to publishers. See Roadmap.