2026.09.81 — 2026-09-30
Breaking
Paginate every list endpoint with one envelope (0d43b660)
Every endpoint that returns a collection now answers with {data, page, pageSize, count, hasNext} and takes page (1-based) and size (default 50, at most 500). Table-backed lists page in SQL (audit, broker events, request-reply flows, alert history, config applies, notification deliveries, bulk runs, plugin history); the rest slice the list they already hold. The audit, flow and alert-history page views are now the shared envelope. The message and broker-event pages keep their extra fields beside the envelope. The web UI reads the envelope, asking for size=500 where it needs a whole short list.
Resolve the API version from the path and send deprecation headers (57f657ea)
The API version is now Spring's API version, read from the second path segment of /api/{version}. Controllers map only what follows the prefix, so URLs are unchanged. Only v1 is supported: any other version is a 400 invalid-api-version problem. A declared deprecation sends Deprecation, Sunset and Link headers and marks the operation deprecated in the OpenAPI document; nothing is deprecated yet. The document's info.version is now the running Studio version, and a new REST API guide covers versioning, breaking changes, errors, limits, lists and idempotency.
Return problem+json for every error (15d13f8c)
Every failure now has an application/problem+json body with a stable type: 401 unauthenticated, 403 forbidden and csrf, framework errors (bad-request, not-found, method-not-allowed, not-acceptable, unsupported-media-type) and a 500 internal-error that carries a request id and hides the cause. The login-throttled and too-many-queries 429s send Retry-After. The OpenAPI document declares 4XX, 5XX and 429 problem responses on every operation.
Added
Serve the diagnostics endpoints under the API version (8f77ce42)
The support bundle and bug-report summary endpoints no longer spell /api/v1 in their mappings; the version prefix is added like for every other controller. Their errors were already problems, and the OpenAPI document now lists the 4XX, 5XX and 429 responses on them.
Paginate every list endpoint with one envelope (0d43b660)
Every endpoint that returns a collection now answers with {data, page, pageSize, count, hasNext} and takes page (1-based) and size (default 50, at most 500). Table-backed lists page in SQL (audit, broker events, request-reply flows, alert history, config applies, notification deliveries, bulk runs, plugin history); the rest slice the list they already hold. The audit, flow and alert-history page views are now the shared envelope. The message and broker-event pages keep their extra fields beside the envelope. The web UI reads the envelope, asking for size=500 where it needs a whole short list.
Resolve the API version from the path and send deprecation headers (57f657ea)
The API version is now Spring's API version, read from the second path segment of /api/{version}. Controllers map only what follows the prefix, so URLs are unchanged. Only v1 is supported: any other version is a 400 invalid-api-version problem. A declared deprecation sends Deprecation, Sunset and Link headers and marks the operation deprecated in the OpenAPI document; nothing is deprecated yet. The document's info.version is now the running Studio version, and a new REST API guide covers versioning, breaking changes, errors, limits, lists and idempotency.
Accept Idempotency-Key on every mutating endpoint (bc1432ef)
A POST, PUT, PATCH or DELETE under /api/v1 may now carry an
Idempotency-Keyheader (1 to 255 printable ASCII characters). Within 24 hours a repeat of the same request (method, path, query and body) by the same user returns the first status and body without applying the mutation again, markedIdempotent-Replayed: true. Keys belong to the calling user; tokens and sessions of one user share them. A request without the header behaves as before, and the plugin gateway (/api/v1/p/, /api/v1/clusters/*/p/) is left to the plugins.Refusals, all application/problem+json:
- 422
idempotency-key-reused: the key was used for a different request (adryRun=truepreview and the real run are different requests, so send a new key for the real run). - 409
idempotency-in-progresswithRetry-After: 1: the first request is still running. - 400
idempotency-unsupported: a multipart upload, or a body over 8 MiB, carried a key. - 400
invalid-idempotency-key: the key is empty, over 255 characters or not printable ASCII.
A 5xx answer, an exception, and a 401, 403 or 429 are not recorded, so the retry runs. Other 4xx answers are, so a corrected request needs a new key.
Keys are stored in the new
idempotency_recordtable (applied on startup) and listed on the Data page as "Idempotency keys", with a 24 hour retention that cannot be shortened.- 422
Return problem+json for every error (15d13f8c)
Every failure now has an application/problem+json body with a stable type: 401 unauthenticated, 403 forbidden and csrf, framework errors (bad-request, not-found, method-not-allowed, not-acceptable, unsupported-media-type) and a 500 internal-error that carries a request id and hides the cause. The login-throttled and too-many-queries 429s send Retry-After. The OpenAPI document declares 4XX, 5XX and 429 problem responses on every operation.
Publish generated TypeScript and Java clients (dcb4bea1)
Every release now publishes two clients generated from that release's OpenAPI document:
@artemis-studio/clienton npm (typedopenapi-fetchclient with bearer auth and a typedProblemErrorfor problem+json answers) andio.github.sudoitir:artemis-studio-clienton Maven Central (java.net.httpand Jackson). The release also attachesartemis-studio-<version>.openapi.jsonwith its checksum and provenance.
Fixed
Serve Studio's health under the API version like every endpoint (3f966e49)
Spell the plural of address in the resource lists (3b481cf0)
The empty state and the pager read "No addresss" and "addresss".
Report the page size the message browser actually serves (0a2e531f)
The broker serves at most 200 messages a page. A larger size is now reported as 200, and hasNext is worked out from it, so a client asking for 500 is told that more messages follow rather than that the queue ends. The UI's full-list reads also stop at an empty page.
Accept only the canonical v1 spelling of the API version (74e12ca8)
/api/1/..., /api/V1/... and /api/1.0/... are refused with 400 invalid-api-version. Before, Spring's version parser read them as version 1, so they reached the v1 endpoints past the checks that match the /api/v1/ prefix, such as a disabled feature.
Expire idempotency keys and recover abandoned ones (7a9528f4)
An
Idempotency-Keywhose first request never finished (a crash or a lost connection) is taken over after a 10 minute lease instead of answering 409 until the purge. A key older than 24 hours is forgotten even before the data lifecycle removes it, and a new request claims it. A replay now also carries the originalLocationandETagheaders, never a cookie. A response over 8 MiB is not recorded, so the retry runs. The table (idempotency_record, unreleased) gains aheaderscolumn.Ship the JSON Schema validator the MCP server needs (c759b372)
The contract tests declared com.networknt:json-schema-validator test-scoped, which also removed the copy the MCP server reads at runtime from the jar, so the packaged application failed to start with NoClassDefFoundError. It is now a normal dependency.
Load every page of a list the UI shows in full (2dbc0988)
requestAll stopped at one page of 500, so a list longer than that showed its first rows and read as complete. It now follows hasNext and joins the pages.
Document every response field the API returns (943dd2e6)
The OpenAPI document now describes every member a problem response can carry, marks the fields that are null when unknown as nullable, and documents the optional Idempotency-Key header on every mutating operation.
Send the wait for a refused query in the problem body (d634bf68)
The console's stream reports too-many-queries as a failed frame inside a 200, which cannot carry a Retry-After header, so the problem now also has a retryAfter property with the same wait.
Security
Accept a caller's X-Request-Id only when it is a plain token (6df8a75c)
A request id with line breaks or other characters outside letters, digits, dot, dash and underscore (up to 64) is replaced by a generated one before it reaches the logs, the audit trail or an error body, so it cannot forge log lines.