Stop re-downloading what has not changed
Read responses carry a version tag, so a client can ask whether anything changed instead of fetching the payload, and read-your-write moved into the platform.
Cacheable reads now support ETag validation. Supported completed writes wait for indexed visibility before returning their result.
Ask what changed, not for everything
A cacheable read answers with an ETag, an opaque tag identifying that exact version of the response. Send it back on the next request and an unchanged resource answers 304 Not Modified with no body at all. The cache is invalidated by platform events rather than by a timer, with bounded refresh behavior when notifications are missed.
- Version tag
- On cacheable reads
- Unchanged answer
- 304, no body
- Freshness
- Event-driven invalidation
- Read-your-own-write
- Server-side promise
The conditional read, for a client that polls
Any integration that watches a list is mostly asking a question it already knows the answer to. Nothing changed since last time, and both sides pay for the full payload anyway.
A cacheable read now returns an ETag header. Send that value back in If-None-Match on your next request. If the resource is unchanged, the platform answers 304 Not Modified: a status line, no body, nothing to parse. If it did change, you get the new representation and a new tag.
GET /api/v2/tokens HTTP/1.1
If-None-Match: "a1b2c3d4e5f6"
HTTP/1.1 304 Not Modified
ETag: "a1b2c3d4e5f6"Platform events invalidate affected cached versions. Recovery bounds also limit how long a missed notification can delay refresh.
The TypeScript SDK does this for you. It stores the tags it receives, sends them on later reads, and turns a 304 back into the cached body, so an SDK caller gets a normal response object and transfers less.
Reading back your own write
Writing to the platform and then immediately reading the result is a real problem, because a write settles on chain and the queryable view of it is built afterwards. The usual workaround is bookkeeping on your side: poll until the value appears, or sleep for a guess and hope the guess was long enough.
The platform now carries that itself. A write it reports as complete has already waited for the indexed view to cover the block the write landed in, so after a completed write, one read is enough. If the platform cannot honour that within its bound, it does not silently return stale data. It returns a retryable error carrying the transaction hash, stating that the write succeeded and only the indexed read ran out of time, so you never have to guess whether to resubmit.
If a read after a completed write comes back empty, treat that as a defect worth reporting rather than lag to sleep through. A retry loop only hides it.
Availability and compatibility
Versioned response caching is on by default. A self-hosting operator who needs to turn it off has a configuration switch for that, but the intended state is enabled.
This release changes no API behaviour you have to migrate for, and deprecates nothing. The v1 API remains frozen, and no route changes its request or response shape. A client that ignores the ETag header entirely, which is every client that has not been changed, keeps receiving full responses exactly as before.
Understand indexed reads → · Idempotency and async settlement → · Error reference →
SDK migration mapping
A call-by-call map from the 3.1 TypeScript SDK to the 3.2 namespaced routes, flat arguments, narrowed responses, and retained client interpreters.
Legacy asset creation
The seven original asset families can no longer be created on a new deployment because they carry an older identity model; issued tokens keep working.