Ingest Endpoints
The ingest service receives OpenTelemetry data and publishes it to NATS JetStream.
All three OTLP endpoints accept JSON only (OTLP/HTTP proto3 JSON mapping). Protobuf is not yet supported — requests with Content-Type: application/x-protobuf return 415 Unsupported Media Type. Gzip-compressed bodies (Content-Encoding: gzip) are decompressed transparently.
POST /v1/logs
Section titled “POST /v1/logs”Ingest OTLP log records.
POST /v1/logsAuthorization: Bearer gck_your_keyContent-Type: application/jsonAccepts OTLP LogsData as JSON.
Response: 200 OK on success.
POST /v1/metrics
Section titled “POST /v1/metrics”Ingest OTLP metric data points.
POST /v1/metricsAuthorization: Bearer gck_your_keyContent-Type: application/jsonAccepts OTLP MetricsData as JSON, including Gauge, Sum, Histogram, and Summary metrics.
Response: 200 OK on success.
source_event_id identifies each metric datapoint. In R1 and R2, its canonical derivation hashes the schema-bearing metric parent representation together with the individual datapoint. The metric parent representation contains the metric data container but excludes sibling datapoints. In a Sum metric, Metric.sum is an object container, not a scalar value. By contrast, the sum on Histogram and Summary datapoints is numeric.
POST /v1/traces
Section titled “POST /v1/traces”Ingest OTLP trace spans.
POST /v1/tracesAuthorization: Bearer gck_your_keyContent-Type: application/jsonAccepts OTLP TracesData as JSON.
Response: 200 OK on success.
GET /health
Section titled “GET /health”Health check endpoint. Returns a plain-text body.
GET /healthResponse:
200 OKwith bodyokwhen NATS is connected.503 Service Unavailablewith bodynats unhealthywhen NATS is down.
The /health endpoint does not send Retry-After. That header is added only on the OTLP endpoints when the NATS publish pipeline is under backpressure (Retry-After: 5).
- OTLP endpoints accept JSON only; other content types return
415. - Oversized payloads return
413 Payload Too Large. - Under NATS backpressure, OTLP endpoints return
503withRetry-After: 5. - The ingest service is stateless — it publishes to NATS and returns immediately.
- Data flows: Ingest → NATS JetStream → worker archival and landing lanes.
Prompt capture routes
Section titled “Prompt capture routes”The plugin uses the following authenticated routes:
POST /v1/prompts— capture a prompt turn.POST /v1/prompts/response— capture a response for a prompt.GET /v1/plugin/config— resolve runtime configuration for the plugin.POST /v1/setup-complete— plugin signals the end of/prism:setup.
Response capture wire contract
Section titled “Response capture wire contract”Modern response capture selects the prompt with prompt_id or client_event_id and includes response_operation_id. Retries with the same semantic response are idempotent.
When both prompt_id and client_event_id are supplied, prompt_id takes precedence.
Semantic response content consists of response_text and the stable response fields already stored with it: elapsed_ms, input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, model, and cost_usd. cost_catalog_revision and cost_kind are additive catalog provenance, not semantic response content. A later identical retry may fill in missing catalog provenance. If a retry supplies a different value for provenance that is already stored, the first value is preserved and the retry remains an idempotent no-op.
response_content_hash is optional. When supplied, it must equal the server-canonical SHA-256 of response_text and the seven governed response fields: elapsed_ms, input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, model, and cost_usd.
POST /v1/prompts/response returns:
204 No Contentfor a successful capture or idempotent no-op.400 Bad Requestwhen request validation fails, including when a suppliedresponse_content_hashdoes not equal the server-canonical SHA-256.404 Not Foundwhen the selected prompt does not exist.409 Conflictwhen the response operation or semantic content conflicts.413 Payload Too Largewhen the request exceeds the raw ingress frame bound (currently 4 MiB). This is permanent for the request as sent — retrying the same body will not succeed, and the response carries noRetry-After.503 Service UnavailablewithRetry-After: 5when the underlying transport is temporarily saturated — this is retryable, unlike413.
POST /v1/prompts returns the same 413/503 pair for the same reasons.
Session-only response selection with tool_session_id is legacy compatibility only: it is accepted only from plugin versions older than 0.5.1 and only before 2026-08-16T00:00:00Z.
API proxy endpoints
Section titled “API proxy endpoints”For callers that can’t reach the internal API, a small set of API endpoints are proxied through ingest:
| Route | Method | Target |
|---|---|---|
/v1/telemetry/logs | GET | API — see Telemetry Endpoints |
/v1/insights/report | GET | API — see Insights Endpoints |
/v1/insights/report/generate | POST | API — see Insights Endpoints |
/v1/insights/report/quick | POST | API — synchronous, LLM-free report (Insights) |
/v1/score_v3/realtime/sub-sessions | GET | API — see Prompt Score v3.0 |
/v1/score_v3/today-summary | GET | API — today’s rolled-up v3 summary |
/v1/model-catalog | GET | API — compiled model catalog snapshot (Prompt Score v3.0) |
/v1/intelligence/prism | GET | Stub — authenticated, always returns { "scores": [], "total": 0 }. The pre-v2.14 prism.prism_scores pipeline was removed; current scoring lives under Prompt Score v3.0. |
Proxy routes require the same authentication as any other ingest endpoint.