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:
InternalTargetConfigis nowBridgeTargetConfig— 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
SAFETYjoins thefocusenum on evaluation create bodies and on execution reads, alongsideKNOWLEDGE,COMPLIANCEandSCOPE.safetyjoins theClassification.typeenum.- A
safetymember joins the executionoutcomesunion, carryingturn, a nullabledecision, and aseverity. 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_consistencyjoins theClassification.typeenum, and akb_consistencymember (KBConsistencyOutcome) joins the executionoutcomesunion. It carries theturn,checked(how many contradicted claims were examined) andentailed_elsewhere(how many of those the knowledge base also asserts somewhere else).- The outcome is warning-grade: it never contributes to
has_violationormax_severity, and it adds nothing toseverity_counts. A self-contradicting knowledge base does not count against the AI service's score, so treatkb_consistencyas a signal to fix the knowledge base, not as a finding against the target. kb_findingsjoinsClassification: an array of the newKBEntailmentFinding. It is populated only onkb_consistencyclassifications and isnullon every other classification type, so branch ontyperather than testing the field.- Each
KBEntailmentFindingnames both sides of the contradiction.claimis the AI service's own wording, verbatim;reasoningexplains why the two passages cannot both hold;entailing_locatorscite the passage that asserts what the AI service said, andcontradicting_locatorsthe passage that denies it.claim_idjoins to the same execution's factuality claims (the same key asContradiction.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_rateis the percentage of the report's safety-graded executions with no safety violation, from0to100. It isnullwhen the report contains no safety-graded execution, never100: a target that was never safety-tested must not read as fully safe.safety_by_probecuts that same population by probe family, the adversarial technique the prompts came from (encoding,promptinject,dan, and so on). Each entry is aSafetyProbeMetricswithprobe_family,executions,violations,severe_violations,max_severityand its ownsafety_rate, ordered most-violations first. A low rate on one family next to high rates elsewhere localises a weakness the singlesafety_ratehides. Executions whose run snapshot no longer resolves to a task are grouped under theunknownfamily rather than dropped, soexecutionssummed across the list always equals the populationsafety_ratewas computed on. The list is empty when nothing was safety-graded.- Six per-dimension rates join it, each a percentage from
0to100over the executions that dimension was measured on:completion_rate,factuality_rate,validity_rate,principle_compliance_rate,instruction_following_rateandscope_adherence_rate. Anullrate means the dimension was never measured on this report, which is a different statement from a0rate.
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 versionmetadatais an object, a list, ornull; a forensic execution still carries the single object it always did. - The list is sparse.
turnis the position of the model response and is never renumbered, so a turn whose response set nometadatacontributes 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-15and2026-08-04publishmetadataas 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 seeingmetadataon executions that previously carried none. Forensic executions are unchanged on every version.
See Correlate executions with your own records.
Changed
- A report's
readiness_scoreis 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 its0–100range 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, including2026-06-15and2026-08-04. See Read a report's metrics. - Evaluation
execution_config:parallelism,max_turns,max_durationandrunsmust each be at least 1. Values below 1 were never a working configuration —runs: 0produces no executions,max_turns: 0makes the turn budget zero,parallelism: 0is zero-width concurrency. importanceon task and principle create and update bodies must be between 1 and 5 inclusive. Omittingimportance, or sendingnull, 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 anyGET.- A custom evaluation's
task_idsmust contain at least one task id. An empty list (or an omittedtask_ids) previously returned201and then produced an evaluation that never ran — stuck inrunning, holding its budget reservation for an hour, and neither re-runnable nor deletable. It is now rejected up front with a422.
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
apiandresponses_apitarget types merge into a singletype: "api", distinguished by a newprotocolfield (completionsorresponses). A request with the oldresponses_apitype, or one missingprotocol, is rejected. - Target
typeis 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 entrytype, job resourcetype, and connection-teststatus(the cancellation value is now spelledcanceled, notcancelled). - Job
statusgainscanceled. 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 reportscanceledtoo, 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_steponly; the by-id read returnsstepsonly.
Removed
GET /reports/{rid}/pdf. UsePOST /reports/{rid}/pdf, which lets you select report sections.- The
from_evaluationandfrom_executionsreport-create request variants. Requests using either are migrated automatically to the equivalentbased_onshape ({"kind": "evaluation" | "execution", "ids": [...]}), with one behavior change:based_ononly 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 tobased_ondirectly 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.