Skip to main content

API changelog

The Spectral API uses a two-tier version scheme: a major (v1, v2, …) for breaking resets, and dated revisions within a major for additive, migratable changes. Pin a specific revision with the Spectral-Version header; this page records what changed at each dated revision.

v1​

2026-09-07: schema names, safety evaluations, and input bounds​

Pin Spectral-Version: 2026-09-07 or later to get these shapes.

Renamed — schema names only, no change to any request or response

Every schema in the API reference dropped its Public prefix: PublicExecution is now Execution, PublicTarget is Target, and so on across the surface. The prefix carried no meaning for API consumers.

This changes nothing on the wire. No path, no field name, no field type, no enum value, and no status code differs. What changes is the names in the spec document — so if you generate a client from the OpenAPI file, regenerating against 2026-09-07 produces differently-named classes for identical payloads. Pinning 2026-06-15 or 2026-08-04 keeps the old names indefinitely; those documents are untouched.

Three names changed by more than the prefix:

  • InternalTargetConfig is now BridgeTargetConfig — it configures a target reached through the Spectral Bridge, which the old name did not convey.
  • The evaluation list feed's page wrapper is now EvaluationPage, replacing a 138-character machine-generated name.
  • The knowledge-base file-upload body is now KnowledgeBaseFileUploadBody, replacing a name generated from the route path.

Six schemas in the report-creation request keep their Public prefix (PublicReportCreateFromBasedOn and the source types it references). These names are stable and will not change: renaming them would alter the already-published 2026-06-15 and 2026-08-04 documents.

Added — safety evaluations

  • SAFETY joins the focus enum on evaluation create bodies and on execution reads, alongside KNOWLEDGE, COMPLIANCE and SCOPE.
  • safety joins the Classification.type enum.
  • A safety member joins the execution outcomes union, carrying turn, a nullable decision, and a severity. Clients pinned to an earlier version continue to receive the previous ten-member union and never see this member.

Added — knowledge-base self-contradiction warnings

When a factuality check flags a claim as contradicted by the documents that grounded it, Spectral now also asks whether some other passage in the same knowledge base asserts that same claim. If one does, the knowledge base contradicts itself, and the defect is in your source material rather than in the AI service under test. The check runs on executions that were graded against a knowledge base, and only where contradicted claims exist.

  • kb_consistency joins the Classification.type enum, and a kb_consistency member (KBConsistencyOutcome) joins the execution outcomes union. It carries the turn, checked (how many contradicted claims were examined) and entailed_elsewhere (how many of those the knowledge base also asserts somewhere else).
  • The outcome is warning-grade: it never contributes to has_violation or max_severity, and it adds nothing to severity_counts. A self-contradicting knowledge base does not count against the AI service's score, so treat kb_consistency as a signal to fix the knowledge base, not as a finding against the target.
  • kb_findings joins Classification: an array of the new KBEntailmentFinding. It is populated only on kb_consistency classifications and is null on every other classification type, so branch on type rather than testing the field.
  • Each KBEntailmentFinding names both sides of the contradiction. claim is the AI service's own wording, verbatim; reasoning explains why the two passages cannot both hold; entailing_locators cite the passage that asserts what the AI service said, and contradicting_locators the passage that denies it. claim_id joins to the same execution's factuality claims (the same key as Contradiction.unfactual_claim_id), so a warning lines up with the claim it came from. See Query your executions.

Clients pinned to 2026-06-15 or 2026-08-04 keep their published Classification shape and their previous outcomes union: kb_consistency rows are filtered out of the response and kb_findings is withheld, so those pins never see either.

Added — safety as a report KPI

ReportMetrics (on a report read) gains a safety score plus the per-dimension rates behind the readiness radar, so a report read carries the same numbers the report PDF charts. All of it is now documented in Read a report's metrics.

  • safety_rate is the percentage of the report's safety-graded executions with no safety violation, from 0 to 100. It is null when the report contains no safety-graded execution, never 100: a target that was never safety-tested must not read as fully safe.
  • safety_by_probe cuts that same population by probe family, the adversarial technique the prompts came from (encoding, promptinject, dan, and so on). Each entry is a SafetyProbeMetrics with probe_family, executions, violations, severe_violations, max_severity and its own safety_rate, ordered most-violations first. A low rate on one family next to high rates elsewhere localises a weakness the single safety_rate hides. Executions whose run snapshot no longer resolves to a task are grouped under the unknown family rather than dropped, so executions summed across the list always equals the population safety_rate was computed on. The list is empty when nothing was safety-graded.
  • Six per-dimension rates join it, each a percentage from 0 to 100 over the executions that dimension was measured on: completion_rate, factuality_rate, validity_rate, principle_compliance_rate, instruction_following_rate and scope_adherence_rate. A null rate means the dimension was never measured on this report, which is a different statement from a 0 rate.

Added — client metadata from Responses API targets

Execution.metadata carried your own data only for forensic executions. An execution run against a Responses API target now carries the metadata your endpoint set on each response, so you can join any execution back to your own records rather than only a transcript you submitted.

  • The field admits a second shape: a turn-indexed list, [{"turn": 0, "data": {…}}]. On this version metadata is an object, a list, or null; a forensic execution still carries the single object it always did.
  • The list is sparse. turn is the position of the model response and is never renumbered, so a turn whose response set no metadata contributes no entry.
  • An entry is dropped, rather than failing the run, when it cannot be stored: a key containing a NUL byte, a value that will not serialize, or an accumulated payload over 1 MB. The budget is spent in turn order and a skipped turn does not consume it, so one oversized turn costs you that turn and not the ones after it.
  • Contents stay opaque and uninterpreted. Nested and non-string values survive intact, so you are not held to a flat string map.
  • Earlier pins receive this too, in a different shape. 2026-06-15 and 2026-08-04 publish metadata as an object and that type is frozen, so rather than withhold the data those versions deliver the same turn list wrapped as {"turns": […]}. A client pinned to either starts seeing metadata on executions that previously carried none. Forensic executions are unchanged on every version.

See Correlate executions with your own records.

Changed

  • A report's readiness_score is now the normalized area of a six-axis radar instead of a five-axis one: safety joins completion, factuality, principle compliance, instruction following and scope adherence. An axis that was never measured still contributes a full-marks radius, as before, so a report with no safety-graded execution scores higher than the same executions scored across five axes. The field's type and its 0–100 range are unchanged, but the geometry behind it is not: a score is only comparable against other scores computed the same way, so do not read a shift against a pre-release report as a change in the AI service. Reports built before this release keep the score they were built with. This is a computation change rather than a schema change, so it applies to reports built on any pin, including 2026-06-15 and 2026-08-04. See Read a report's metrics.
  • Evaluation execution_config: parallelism, max_turns, max_duration and runs must each be at least 1. Values below 1 were never a working configuration — runs: 0 produces no executions, max_turns: 0 makes the turn budget zero, parallelism: 0 is zero-width concurrency.
  • importance on task and principle create and update bodies must be between 1 and 5 inclusive. Omitting importance, or sending null, is unchanged and still accepted — only out-of-range integers are rejected. Reads are unaffected: a stored value outside 1–5 still serializes normally on any GET.
  • A custom evaluation's task_ids must contain at least one task id. An empty list (or an omitted task_ids) previously returned 201 and then produced an evaluation that never ran — stuck in running, holding its budget reservation for an hour, and neither re-runnable nor deletable. It is now rejected up front with a 422.
warning

These three bounds apply to earlier pins too.

Like the readiness_score and metadata changes above, and unlike the rest of this page, these three are enforced on all versions, not only from 2026-09-07 onward. The 2026-06-15 and 2026-08-04 schemas still describe these fields as unbounded, and the API reference for those versions still renders them that way, but a request carrying an out-of-range value is rejected with a 422 VALIDATION_ERROR whichever version you pin.

Each bound rejects only input that could never produce a working result, so a working integration should not be able to reach one.

2026-08-04: target reshape, closed enums, ElevenLabs targets​

Pin Spectral-Version: 2026-08-04 or later to get these shapes; earlier pins keep working against the 2026-06-15 shapes below. (Three exceptions, added later: the three input bounds, the six-axis readiness_score, and turn-indexed execution metadata in 2026-09-07 all reach this version too.)

Added

  • ElevenLabs conversational-agent targets (type: "elevenlabs_agent"). Create and manage them like any other target.

Changed

  • API targets: the api and responses_api target types merge into a single type: "api", distinguished by a new protocol field (completions or responses). A request with the old responses_api type, or one missing protocol, is rejected.
  • Target type is now a closed set of values instead of any string.
  • These fields are now closed enums instead of free-form strings (existing values are unchanged except where noted): classification type, knowledge-base entry type, job resource type, and connection-test status (the cancellation value is now spelled canceled, not cancelled).
  • Job status gains canceled. This value is not reachable yet (job cancellation isn't supported), added ahead of that support so the shape is already in place.
  • Build-step status (on knowledge-base creation, task generation, persona generation, principle generation, and evaluation steps) uses the same status vocabulary as the rest of the API: queued, running, succeeded, failed, canceled. Steps are now cancel-aware: the step in-flight when an evaluation is canceled reports canceled too, instead of the older vocabulary's ambiguous states.
  • Evaluations: the list feed (including the create/cancel/rerun job envelopes) and the get-by-id read are now separate shapes. The list feed returns current_step only; the by-id read returns steps only.

Removed

  • GET /reports/{rid}/pdf. Use POST /reports/{rid}/pdf, which lets you select report sections.
  • The from_evaluation and from_executions report-create request variants. Requests using either are migrated automatically to the equivalent based_on shape ({"kind": "evaluation" | "execution", "ids": [...]}), with one behavior change: based_on only resolves succeeded executions, where the legacy variants included executions of any status. A request naming non-succeeded or unknown executions/evaluations may now 422 with "based_on sources resolved to no succeeded executions" instead of returning a report built from in-progress data (or, for an unknown evaluation, the old 404); that 422 doesn't distinguish "no such evaluation" from "not finished yet." Migrate to based_on directly to avoid relying on this automatic translation.

2026-06-15: initial version​

First public release of the Spectral API. See the API reference.

Three later changes reach back into this version: the three input bounds, the six-axis readiness_score, and turn-indexed execution metadata in 2026-09-07 all apply on every pin, including this one.