For AI agents: markdown of this page — /docs-content-en/changelog/2026-06-26.md documentation index — /llms.txt

API changes: June 26, 2026

← Changelog · June 2026

FIX-0626-1: catalog-prices: system fields priceScale, extraId, timestampX declared in the schema

Before

GET /v1/catalog-prices and GET /v1/catalog-prices/:id returned the priceScale, extraId, and timestampX fields, but they were not declared in the schema: they passed through without normalization (the timestampX field arrived in an offset format, e.g. 2024-06-17T16:53:24+05:30) and were absent from the GET /v1/catalog-prices/fields response.

After

The three fields are declared as read-only. They are now listed in GET /v1/catalog-prices/fields, and timestampX is normalized to ISO 8601 UTC (2024-06-17T13:53:24.000Z), consistent with the other datetime fields.

Impact on integrators

The instant in timestampX does not change — only its string representation does (UTC instead of a local offset). Clients that parse the value with a standard date parser keep working unchanged.

FIX-0626-2: Server and app source download: the signed URL no longer returns 403

Before

GET /v1/infra/servers/:id/sources/:versionId/download and GET /v1/apps/:id/sources/:versionId/download returned 200 with a signed URL, but downloading from that URL failed with 403 AccessDenied when the request used a personal key (vibe_api_*). Listing versions worked and the file was physically present in storage.

After

The signed URL is now bound to the object's actual storage location, so the download returns the archive content. The fix also covers snapshots whose storage key belongs to a different family (legacy app snapshots linked to a server).

Impact on integrators

The endpoint contract is unchanged — this restores the documented 200 + working signed URL behavior. No client-side changes are required.

NEW-0626-3: api-bearer token refresh and Gateway rejection reason

The new endpoint POST /v1/infra/servers/:id/access-tokens/:tokenId/refresh mints a fresh JWT (up to 10 minutes) for an existing api-bearer token — without creating a new record, and without consuming the active-token limit or the hourly mint limit. A long-running client (CI, AI agent) refreshes the token before jwtExpiresAt instead of minting a new one. A single revoke kills the original and all refreshed JWTs of one token.

The 401 BH_LOGIN_REQUIRED response that the Gateway returns on an app subdomain when it rejects the Authorization: Bearer header now carries a reason field with the specific cause: expired, signature, subdomain, type, revoked, malformed, or invalid. The field is additive — existing clients ignore it.