Read a file or list a folder
A file comes back as an inert download (application/octet-stream, attachment). A folder, or list=1, gives a listing. Also works on a stopped session, read-only, from the workspace it saved (its stop archive, or the last checkpoint after a lost machine) without starting a machine; .boxline/ is left out and links are never followed. 409 nothing_saved when it saved no workspace. One request scans at most 1 GiB of the saved archive, and a stopped session's folder lists at most 10,000 entries (413 payload_too_large for both), and at most 8 such reads of a project run at once (429 archive_busy). Listing a file is 400 not_a_directory.
/v1/sessions/{id}/filesRequest
| Method and path | GET/v1/sessions/{id}/files |
|---|---|
| Base URL | https://api.boxline.dev |
| Authentication | Your API key in the x-api-key header (or Authorization: Bearer). The examples read it from BOXLINE_API_KEY. |
Path parameters
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
idrequired | string | – | – |
Query parameters
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
path | string | . | – | A path inside the workspace, e.g. downloads/report.csv. |
list | string | – | 1 |
curl -G "https://api.boxline.dev/v1/sessions/$SESSION_ID/files" \ -H "x-api-key: $BOXLINE_API_KEY" \ --data-urlencode "path=downloads/report.csv" \ -o report.csv# A folder listing instead: add --data-urlencode "list=1"import { writeFile } from "node:fs/promises";import { Boxline } from "@boxline/sdk";const bx = new Boxline(); // reads BOXLINE_API_KEY and BOXLINE_API_URLconst bytes = await bx.sessions.files.read("SESSION_ID", "downloads/report.csv");await writeFile("report.csv", bytes);const folder = await bx.sessions.files.list("SESSION_ID", "downloads"); // the same call with list=1console.log(folder.entries);from boxline import Boxlinebx = Boxline() # reads BOXLINE_API_KEY and BOXLINE_API_URLdata = bx.sessions.files.read("SESSION_ID", "downloads/report.csv")with open("report.csv", "wb") as f: f.write(data)print(bx.sessions.files.list("SESSION_ID", "downloads")) # the same call with list=1boxline files get $SESSION_ID downloads/report.csv # saves report.csv hereboxline files ls $SESSION_ID downloads # a folder listing insteadResponses
200 OK
The file's bytes, or a listing.
application/octet-stream: The file's bytes.application/json: JSON.
Fields
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
path | string | – | – | |
entries | object[] | – | – | |
entries[].name | string | – | – | |
entries[].type | string | – | file, dir, other | |
entries[].size | integer | – | – | |
entries[].mtime | string | – | – | Format: date-time. |
{ "path": "/workspace/downloads/report.csv", "entries": [ { "name": "Work account", "type": "file", "size": 0, "mtime": "2026-09-29T10:00:00.000Z" } ]}Errors
Errors have a matching HTTP status and the same body. code is stable, so check it in your code; message is for people. See Errors and request ids.
| Status | Codes | When |
|---|---|---|
| 400 Bad Request | invalid_request, invalid_json, invalid_cursor, invalid_idempotency_key, invalid_extension, variables_with_extensions, terms_not_accepted, invalid_reset_token, invalid_confirmation_code, wrong_password, no_password, invalid_next, invalid_oauth_token | The request is not valid. |
| 401 Unauthorized | unauthorized | Missing or invalid API key. |
| 404 Not Found | not_found, invite_not_found, provider_unavailable | No such thing in this project (or organization), or no such route. |
| 409 Conflict | session_not_running, shell_disabled, browser_disabled, nothing_saved, not_resumable, invalid_state, conflict, email_taken, identity_in_use, provider_already_linked, last_sign_in_method, not_impersonating, machine_too_old, too_many_credential_values, limit_reached, terms_version_mismatch, no_project, last_owner, organization_not_empty, project_has_sessions, already_member, invite_pending, idempotency_in_progress | The current state does not allow it, or a request with this Idempotency-Key is still being answered. |
{ "error": { "code": "not_found", "message": "session not found", "requestId": "req_4fJx0aQm2Lk9Pz7N" }}Use with the browser
Work on what the browser downloaded: wait for the file, run Python on it in the same session, and read the result. See Browser, shell and files together.
curl -G https://api.boxline.dev/v1/sessions/$SESSION_ID/files/wait \ -H "x-api-key: $BOXLINE_API_KEY" \ --data-urlencode "pattern=downloads/*.csv"curl -X POST https://api.boxline.dev/v1/sessions/$SESSION_ID/shell/exec \ -H "x-api-key: $BOXLINE_API_KEY" \ -H "content-type: application/json" \ -d @- <<'JSON'{"command": "mkdir -p output && python3 -c \"import pandas as pd; print(pd.read_csv('downloads/report.csv')['revenue'].sum())\" > output/total.txt"}JSONcurl -G https://api.boxline.dev/v1/sessions/$SESSION_ID/files \ -H "x-api-key: $BOXLINE_API_KEY" \ --data-urlencode "path=output/total.txt"const csv = await session.files.waitFor("downloads/*.csv"); // the browser's downloadawait session.exec(`mkdir -p output && python3 -c "import pandas as pd; print(pd.read_csv('downloads/report.csv')['revenue'].sum())" > output/total.txt`);const total = (await session.files.readText("output/total.txt")).trim();csv = session.files.wait_for("downloads/*.csv") # the browser's downloadsession.exec("""mkdir -p output && python3 -c "import pandas as pd; print(pd.read_csv('downloads/report.csv')['revenue'].sum())" > output/total.txt""")total = session.files.read_text("output/total.txt").strip()Learn more
These docs describe a beta API. Endpoints, fields and SDK methods may change before general availability; breaking changes will be listed in the changelog.