https://git.tensorlake.ai. You can make those requests yourself from curl, a CI job, a browser, or a language the SDKs don’t cover. This page is the reference for that surface: the URL scheme, the credential you send, and every request and response shape a client needs.
The Python and TypeScript SDKs and the
tl fs CLI wrap this API. Mounts add a local session and a bulk upload protocol on top of it. Use the raw API when you need a language the SDKs don’t cover, a serverless function with no tl binary, or a signed download link. See Cloud Volumes for the product overview.URL scheme
A file system lives in a project and is addressed by name:{project}: the project id, such asproject_9f3c2a1b.tl git tokenprints it, and the dashboard shows it in project settings.{filesystem}: the file system name you chose at creation, such asagent-scratch.{path}: a file or directory path inside the file system, given literally afterfs/files/orfs/presign/. Percent-encode characters that aren’t valid in a URL.
/project/{project}/repos/{name} namespace. Every file-system route sits under /fs. Calling a Git route on a file system returns 404.
Authenticate
File-system requests use HTTP Basic auth with a short-lived credential. The username is alwayst. The password is a token you mint from your Tensorlake API key or CLI login. Your API key itself is never sent to git.tensorlake.ai.
- CLI
- API key
tl fs token mints a credential scoped to one file system. Its JSON output has the same shape as the API response below.
A file-system-scoped credential can’t push to Git repositories or delete the file system. Tokens expire after 1 hour by default. Mint a new one when a request answers
401.
Manage file systems
These routes need a project-wide credential.Create a file system
201 Created with an empty body. kind must be filesystem; without it the route creates a Git repository. A name that already exists answers 409.
List file systems
next_after is set, repeat the request with after=<next_after> to fetch the next page.
Get one file system
404 with the header x-tensorlake-error: repo-not-found.
Fork a file system
snapshot. It copies no file content: both file systems share the stored bytes until they diverge. The request takes no body. The response is 201 Created.
Delete a file system
204 No Content. Deletion removes the file system and its snapshots. Bytes shared with a fork remain until the last file system that references them is deleted.
Read the current version
snapshot_id: the id of the current version. It isnullon a file system nothing has written to yet.generation: a counter that increases by 1 each time the file system’s shared state advances.last_autosave_ms: when a mount last published an autosave checkpoint, in Unix milliseconds.nullif no mount has published.permanent_snapshot_count: how many permanent snapshots the file system holds.
?snapshot={snapshot_id} to read a fixed version instead of the moving head. Pass the snapshot_id from this response to make a series of reads consistent with each other.
Wait for a change
wait_generation or the timeout elapses, then returns the head in the shape above. timeout_ms is clamped to between 100 and 55,000 and defaults to 30,000. Poll this in a loop to follow a file system without a mount.
List a directory
path: the directory to list. Omit it or pass an empty string for the root.name: the entry’s file name, without its directory.oid: a content id. Two files with the sameoidhave identical bytes.mode: the POSIX mode as a decimal integer.33188is a regular file with permissions0644,16384is a directory, and40960is a symbolic link. Mask with0o170000to get the type and0o7777for permissions.size: the file size in bytes, or the link target length for a symbolic link.nullfor directories.
limit is clamped to between 1 and 4,096. When truncated is true, pass next_after back as after to continue. A missing directory answers 404. A directory holding a name that isn’t valid UTF-8 answers 422.
Read a file
Content-Type: application/octet-stream. The response carries these headers:
Send a
Range header to read part of a file. The server answers 206 Partial Content with a Content-Range header, or 416 when the range starts past the end of the file:
404. A path that names a directory isn’t a file and also answers 404.
Write a file
version_id is the new head, and previous_version_id is the head the write was applied on top of. Following mounts see the file within seconds.
Query parameters:
mode: the file’s permission bits in octal, such as644or755. Defaults to644.message: a description stored on the version. Defaults toPUT {path}.operation_id: an idempotency key. Two requests with the same key publish one version. When you omit it, the server derives one from the path and the content, so retrying an identical write after a lost response replays the first result instead of publishing twice.
413. The SDKs and tl fs push upload larger files and whole directories through a multi-part protocol that streams bytes straight to object storage. Use them for bulk uploads.
Concurrent writers to different paths merge automatically. Two writers to the same path in overlapping windows are last-writer-wins. See Concurrent Writes.
Delete a file
{version_id, previous_version_id} object as a write. A path that doesn’t exist at the current head answers 404 and publishes nothing. When you omit operation_id, the server derives one from the path and the head the delete was issued against, so a retried delete replays and a fresh delete after the file was recreated publishes a new version.
Get a presigned download URL
Authorization header. Use it in an <img> tag or hand it to a service that can’t send credentials. expires_in_secs is clamped to between 60 and 3,600 and defaults to 900. Pin snapshot so the link keeps working after the file changes or is deleted at head.
A URL is minted only when one stored object holds exactly the file’s bytes. Small files stored inline and files assembled from several stored pieces answer 409 with the body {"code": "not_presignable", "message": "..."}. Fall back to GET fs/files/{path}, which serves every file.
Snapshots
A file system has two kinds of versions, as described in Core Concepts:auto_checkpoint: a version published by a write or a mount autosave. Tensorlake keeps the newest 256 and everything from the last 24 hours, then expires older ones.permanent_snapshot: a version you retained. It remains until you delete it.
version_id a write returns is a snapshot id you can read from, fork from, or retain, as long as it hasn’t expired.
List snapshots
snapshot_class to show only permanent snapshots, as tl fs history does. Pass next_after back as after to continue.
Get one snapshot
permanence_epoch, an integer that changes each time the snapshot is retained or released. Pass it as expected_permanence_epoch on a delete to make the delete conditional. An expired autosave checkpoint answers 410 Gone.
Make the current version permanent
tl fs snapshot and the SDK snapshot() call do. It promotes the current head to a permanent snapshot in place: no bytes are uploaded and no new version is created. request_id is an idempotency key; a retry with the same id returns the first result. If the head is already permanent the call is a no-op.
Retain a specific version
{message, request_id} object, plus an optional expected_permanence_epoch. Use it to retain a version_id a write returned before the autosave window expires it.
Delete a permanent snapshot
204 No Content. The version drops back to auto_checkpoint and expires with the retention window. Content still reachable from the head, a fork, or another snapshot stays stored.
Diff two versions
from and to. before is null for an added path and after is null for a removed one. The entry objects are the storage engine’s raw directory entries: path_utf8 is null and before/after carry byte arrays for names that aren’t valid UTF-8. Compare data.File.content ids to tell a content change from a metadata-only change. Pass next_after back as after to continue.
Errors
Error responses other than409 not_presignable carry a text/plain body with a one-line message. The status codes you should handle:
Every write is idempotent under its
operation_id or request_id, so retrying after a timeout or a 503 is safe.
Not on this page
Mount sessions, the bulk multi-part upload protocol, and the raw byte-path routes the mount daemon uses are also HTTP, but their request shapes are coupled to the client that drives them. Usetl fs, the SDKs, or a mount for those.
Core Concepts
File systems, sessions, autosave checkpoints, and permanent snapshots.
Platform Authentication
API keys, personal access tokens, and SSO.