---
title: "Copy a file off a machine into a temporary blob"
method: POST
path: "/api/v1/pull"
---

# Copy a file off a machine into a temporary blob

`POST /api/v1/pull`

## Request

- Base URL: `https://aicommander.dev`
- URL: `https://aicommander.dev/api/v1/pull`
- Auth: HTTP bearer

PRO ONLY: Free and anonymous callers cannot initiate pulls, and a plan-restricted machine fails with reason `plan_device_limit`. Reads an absolute `path` off the machine and stores it as a TEMPORARY blob, returning a blob id and a short-lived download link. A blob/link created while Pro was active remains usable only to its original TTL after downgrade: blob access ends after 24 hours and the link after 1 hour; neither can be renewed. Use this instead of `cat` through exec, which caps output at 1 MiB and corrupts binary. LIMIT: 100 MiB and one regular file; archive directories and send larger artifacts to storage you control. The relay answers within about 55 seconds. QUOTAS after the Pro gate: 60 transfers/hour/account and 5 GiB/account/rolling day for bytes entering relay storage. Pull reserves the full 100 MiB until it settles to actual size, so less than 100 MiB headroom or concurrent reservations can refuse a smaller file with 429 `rate_limited`.

## Request body

- object
  - `code` string, required: Session code (AIC-…) or, with an API key, a saved machine alias.
  - `path` string, required: ABSOLUTE path of the file on the machine. A relative path is refused, never resolved against a working directory.

## Response `200`

The file was read off the machine and stored as a blob.

- object
  - `ok` true, required
  - `blobId` string, required: 32 hex characters. Pass it to /api/v1/push, or fetch the bytes from /api/v1/files/{blobId}.
  - `bytes` integer, required: What the RELAY stored — its own count, not the machine's claim.
  - `downloadUrl` string, required: Link carrying a short-lived token.
  - `linkExpiresAt` string, date-time, required: When the LINK stops working (1 hour).
  - `blobExpiresAt` string, date-time, required: When the BLOB stops being readable (24 hours), collected or not. Physical cleanup follows via an hourly, retrying sweep, so inaccessible bytes may remain until cleanup succeeds. Deliberately separate from linkExpiresAt: conflating them either abandons a blob you could still fetch or shares a link that has already died.

## Other responses

- `400`: Missing/invalid fields. On the job endpoints this is also how the MACHINE reports a request it can never run (`reason: "invalid_request"` — an empty command, a relative `cwd`, a `gpu_index` that names no card): the request itself is at fault, so correct the field the message names rather than retrying it.
- `401`: A token was supplied but is not a valid API key/admin/OAuth token.
- `403`: Resolved but refused. Causes include expired anonymous access; Free/anonymous file transfer; `reason: plan_device_limit`; independent operator block/approval; or `error: reactivation_required`. For plan_device_limit, delete an older saved machine to promote the next or upgrade to Pro. For file transfer, use Pro. Do not conflate either with operator approval.
- `404`: Session code or alias not found (anonymous callers get a unified message that does not confirm existence).
- `429`: After the Pro entitlement gate, a transfer quota (`reason: rate_limited`) or per-IP/global call limit was exceeded: 60 transfers/hour/account, 10000/hour relay-wide, and 5 GiB/account/rolling day for uploads and pulls. Push spends only the hourly count. Pull reserves 100 MiB until settlement, so low headroom or concurrency can refuse a smaller file. Wait for the window or use storage the user controls.
- `503`: The session exists but the agent is offline or disconnected mid-command.

---

[API](https://skmtc.dev/aicommander/apis/ai-commander-remote-shell-and-long-running-jobs-api.md) · [All operations](https://skmtc.dev/aicommander/apis/ai-commander-remote-shell-and-long-running-jobs-api/llms.txt) · [OpenAPI document](https://skmtc.dev/aicommander/apis/ai-commander-remote-shell-and-long-running-jobs-api/revisions/a6bb89f779a1?raw)
