Migration and retirement timetable
/api is not a new protocol; it gathers the existing domain subcontracts under one prefix and one envelope. Most of the migration therefore consists of changing paths, headers and error handling rather than rewriting business logic; success bodies and event payloads do not change by a single byte.
Path mapping
Section titled “Path mapping”The relation between the old prefixes and /api is recorded in the legacyPath / legacyOffloadPath fields of every manifest operation. The most common entries:
| Old path | /api |
Notes |
|---|---|---|
POST /v2/sessions |
POST /api/sessions |
Session family sdk1 (default) |
POST /v3/sdk2/sessions |
POST /api/sessions + tansr-session-family: sdk2-offload-v1 |
Same path; the family is declared by the header |
GET /v2/sessions/:id/events |
GET /api/sessions/:id/events |
Byte-identical frames without the negotiation header |
POST /v2/sessions/:id/permission/:requestId |
POST /api/sessions/:id/permission/:ticketId |
Placeholder renamed to :ticketId (:id is still the session id) |
POST /v1/approvals/:id/credential |
POST /api/approvals/:id/credential |
The only operation moved in from /v1 (0.14.0) |
GET /v3/sdk2/session-capabilities |
GET /api/capabilities/sessions?protocol=sdk2-ext-v1 |
|
GET /v3/sdk2/capabilities |
GET /api/capabilities/archive |
No query string |
POST /v3/sdk2/bindings |
POST /api/archive/bindings |
|
GET /v3/sdk2/bindings/:id |
GET /api/archive/bindings/:id?protocol=sdk2-ext-v1 |
GET reads carry protocol |
POST /v3/sdk2/bindings/:id/archive/acks |
POST /api/archive/bindings/:id/archive/acks |
|
POST /v3/sdk2/archive-sync/:id |
POST /api/archive/sync/:id |
Error bodies stay in the original archive-sync-v1 envelope |
GET /v3/sdk2/cache/capabilities |
GET /api/capabilities/cache |
|
POST /v3/sdk2/cache/bindings |
POST /api/cache/bindings |
|
POST /v2/executors/connections |
POST /api/executors/connections |
|
GET /v3/terminal/capabilities |
GET /api/capabilities/terminal?contract=terminal-services-v1 |
|
POST /v3/terminal/bindings |
POST /api/terminal/bindings |
|
GET /v3/terminal/sessions/:id/tool-output |
GET /api/terminal/sessions/:id/tool-output?contract=…&sessionContract=… |
|
GET /v3/terminal-observation/sessions/:id/resources |
GET /api/terminal/observation/sessions/:id/resources |
Prefix segment becomes terminal/observation |
GET /v3/terminal-profile/sessions/:id/catalog |
GET /api/terminal/profile/sessions/:id/catalog |
Prefix segment becomes terminal/profile |
Do not maintain this table by hand: the path modules of the official clients are generated from the manifest, and a client of your own should likewise be generated from GET /api/manifest or the in-repo api-manifest.json.
Request and error shape differences
Section titled “Request and error shape differences”| Aspect | Old prefixes | /api |
|---|---|---|
| Session family | Distinguished by path (/v2 vs /v3/sdk2) |
Same path, request header tansr-session-family |
| Subcontract revision | Partly in the path or body | GET reads and streams use the query keys protocol= / contract=; write operations accept no query string (the only exception: the label of session.checkpoint.import) |
| Response headers | No uniform headers | Every response carries tansr-contract / tansr-manifest-revision / tansr-domain / tansr-schema-hash |
| Error body | { error: { code, message, detail? } }, codes from each family’s vocabulary |
Eight-key unified envelope, code is one of 19 unified codes, the family code moves to detail.domainCode |
| Status of some errors | session_ended 409, binding_closed 409, unsupported_capability 422 / 409 |
410 gone, 410 gone, 404 capability_unavailable (original status in detail.domainStatus) |
| Event frames | Original frames per domain | Identical without the negotiation header; the 7-key envelope with tansr-event-envelope: unified-v1 |
| Idempotency / conditional write / deadline | Only requestId / expectedRevision in the body |
Additionally the Idempotency-Key / If-Match / deadline headers (since 0.14.0), mapped by the server onto the body slots |
| 2xx body | — | Byte-identical |
The part most often missed is error handling: replace branches such as error.code === 'session_ended' with a branch on the unified code gone, decide the action from retryAction, and read detail.domainCode only when you need the finer distinction. See Unified request headers, response headers and the error envelope.
The session service’s /v1
Section titled “The session service’s /v1”The /v1 inside the session service process (/v1/status, the /v1/sessions family and the other single-tenant Bearer routes) and /api are two separate identity systems; /api has no counterpart for them. Since @tansr/serve 0.13.0:
/v1is off by default on deployments that assemble/api: as a library,disableV1defaults totruewhenstartServer({ v2: … })is used and/v1*requests get 404; the CLI formtansr serve --v2behaves the same.- Transition: pass
disableV1: falseto the library; or add--legacy-v1to the CLI, or set the environment variableTANSR_SERVE_LEGACY_V1=1(the flag takes precedence over the variable). - A SDK1-only
tansr servewithout--v2has no/apiand is not affected; its/v1works as before. @tansr/serve0.14.0 and@tansr/cli0.10.1 (2026-10-04) mark--legacy-v1/TANSR_SERVE_LEGACY_V1as deprecated: still effective, but a deprecation notice is printed at startup. It is a separate retirement item whose removal date will be announced before 1.0.0.
The /v1 in this site’s REST reference is the platform-side interface and unrelated to the session service /v1 discussed here.
The six-step migration and where it stands
Section titled “The six-step migration and where it stands”| Step | Content | Status as of @tansr/serve 0.15.1 (published 2026-10-10, current npm latest) |
|---|---|---|
| 1 | Internal adapter: /api rewrites and delegates to the existing domain handlers, old prefixes byte-identical |
Done (0.13.0) |
| 2 | Dual write / shadow read: the same golden vectors run through the old entry and /api, success bodies byte-identical, error bodies field-for-field from the same source |
Node and .NET have the same-source mapping tables and conformance replay; Android / iOS / HarmonyOS / Go align by replaying the 165 golden vectors |
| 3 | Client cut-over: no old prefix literal remains in any client’s source | Node @tansr/api-client 0.3.0 stable has cut over (./api). From 0.4.0 (2026-10-06), the frozen ./sdk2 and ./terminal entries also default to /api when routePrefixes is omitted; pass LEGACY_ROUTE_PREFIXES to keep the old prefixes. The ./api entry is unchanged from 0.3.0. .NET NuGet 0.2.0, Go github.com/tansrai/tansr-go v0.3.0, and Rust / Python / C++ 0.1.0 ship on /api; Android, iOS and HarmonyOS release status is in Clients by language; examples/serve-demo goes through the public SDK |
| 4 | Forbid mixing: a structured warning (no rejection) when the same session family is accessed through both prefixes | Started in 0.15.0: when the same session id is used through both /api and /v2 or /v3/*, the server emits api.legacy_prefix_mixed. The default readwrite mode does not reject the request |
| 5 | Read-only window for the old entries: writes on /v2 and /v3/* answer 410, reads are still served, responses carry a retirement header |
The knob shipped in 0.15.0. The default remains readwrite, so writes are not answered with 410. Set TANSR_SERVE_LEGACY_PREFIX=readonly to open the read-only window; off answers 404 for every old prefix. Old-prefix responses also carry Deprecation and Link (and Sunset when TANSR_SERVE_LEGACY_SUNSET is set). The 0.15.0 release notes placed a future default of readonly on a later version. The current npm release, @tansr/serve 0.15.1 (2026-10-10), still defaults to readwrite and does not carry out that change. 0.16.0 is not published |
| 6 | Closure: remove the externally reachable /v2 and /v3/* entries; old prefixes answer 404 in the unified envelope |
1.0.0 |
Self-hosted multi-replica deployments must adjust their reverse proxy before step 3: /api/sessions/:id/** must share shard affinity with /v2/sessions/:id/**, and the four SSE paths under /api follow the same long-connection discipline; otherwise cut-over produces cross-replica 404s.
Retirement timetable
Section titled “Retirement timetable”| Milestone | Releases | Change to the public contract |
|---|---|---|
| 2026-10-02 | @tansr/serve 0.13.0, @tansr/protocol 0.2.0, @tansr/cli 0.10.0 |
/api generally available; /v1 off by default on deployments with /api; retirement of /v2 and /v3/* announced for 1.0.0 |
| 2026-10-04 | @tansr/serve 0.14.0, @tansr/cli 0.10.1, @tansr/api-client 0.3.0 |
Manifest revision 7, the three request headers; --legacy-v1 deprecated |
| 2026-10-06 | @tansr/serve 0.15.0, @tansr/cli 0.10.2, @tansr/api-client 0.4.0 |
Step 4 warnings are on and do not reject by default; the step 5 read-only window can be opened explicitly, and the default remains readwrite; old-prefix responses carry Deprecation / Link; frozen api-client entries default to /api |
| 2026-10-10 | @tansr/serve 0.15.1, @tansr/cli 0.10.3 |
The old-prefix window still defaults to readwrite; two mapping fixes in the unified error envelope — domain codes not registered in the matrix always get 500 internal_error, and the retryAction of result_unknown is narrowed to query-status / rebind; the manifest, paths and success bodies are unchanged |
| 1.0.0 | @tansr/serve 1.0.0, @tansr/api-client 1.0.0 |
External /v2 and /v3/* entries removed, /api becomes the only surface; the unified-v1 family moves from candidate to frozen; the SDK1 entry of @tansr/api-client deprecated, removed in 2.0 |
Turning off /v1 and retiring /v2 and /v3/* are two independent changes to the public contract, each with its own release notes.
Rolling back in pairs
Section titled “Rolling back in pairs”- A server rollback must be paired with a client rollback. 0.12.0 has no
/api: a client that has cut over receives old-shape 404s without thetansr-contractheader and, by the rules, reports “contract unavailable” instead of falling back to the old prefix automatically. When rolling the server back to 0.12.0, roll Node back to@tansr/api-client0.2.0 and the old entries, and mobile clients back to their previous release. - A client can roll back on its own. The 0.13.0, 0.14.0, 0.15.0 and 0.15.1 servers keep
/v2and/v3/*under the defaultreadwritemode, so old clients see no protocol break; this holds until 1.0.0. AfterTANSR_SERVE_LEGACY_PREFIXis set toreadonlyoroff, old clients’ writes, or every old prefix, are rejected in that mode. - 0.13.0 and 0.14.0 change no storage format: the session store, archive host and cache medium need no migration during a rollback. Turning the 0.15.x old-prefix window knob back to
readwritelikewise changes no data. - Reverse-proxy templates and client cut-over must move in the same direction: a client already on
/apiwith a rolled-back template loses shard affinity.
Entry migration for the Node client
Section titled “Entry migration for the Node client”@tansr/api-client 0.3.0 freezes the four old entries ./sdk2, ./sdk2/node, ./terminal and ./terminal/node (shipped with the package, no further changes, not removed) and adds ./api. Recommended steps:
- New code always uses
import { createApiClient } from '@tansr/api-client/api'and calls by operation name instead of assembling paths. - Move call sites of the old entries to
api.call(...)one operation at a time; GET reads in the archive / cache / terminal domains need no hand-filledprotocol/contract, since the SDK injects the default revision per operation. - Switch error handling from family codes to unified codes plus
retryAction, readingerror.domainCodewhen needed. - Do not let old and new entries coexist for the same session family in one process; that is exactly the “mixing” step 4 will warn about.
Was this page helpful?
Thanks for your feedback.