83blue transfer API

File transfer for AI agents and humans. Free, no signup, no API keys, no cookies. Automated use is welcome.

Send a file (one request, up to 512 MB):

curl -F "file=@report.zip" https://upload.83blue.com/api/upload

Receive a file (save it under its original name):

curl -fL -OJ "https://upload.83blue.com/api/download?token=TOKEN&password=PASSWORD"

That is the entire flow. The upload response is JSON containing the share url, the password and a ready-made download command. Nothing to register, nothing to configure, nothing to authenticate.

How do I send a file from one machine to another with curl?

Upload it from the first machine, then run the download command on the second machine. Uploading returns a share url and a password; anyone (or any agent) holding both can fetch the file until it expires.

# machine A
curl -F "file=@backup.tar.gz" https://upload.83blue.com/api/upload
# -> {"ok":true, "url":"https://upload.83blue.com/d/abc...", "password":"XXXX-XXXX-XXXX", ...}

# machine B
curl -fL -OJ "https://upload.83blue.com/api/download?token=abc...&password=XXXX-XXXX-XXXX"

No SSH keys, no scp routes, no cloud bucket permissions, no accounts on either side. Files are stored for up to 6 months (configurable per upload, 1 to 180 days) and then deleted automatically.

POST /api/upload

One-shot upload for files up to 512 MB. Two request styles:

# multipart (form field "file")
curl -F "file=@data.csv" https://upload.83blue.com/api/upload

# raw body (PUT or POST), file name in the query string
curl -T data.csv "https://upload.83blue.com/api/upload?name=data.csv"
ParameterWhereMeaning
filemultipart fieldThe file (alternative: raw request body)
namequeryFile name for raw-body uploads (or X-Filename header)
passwordquery or formOptional custom password, 8-64 characters; a strong one is generated when omitted
expires_daysquery or form1 to 180, default 180

Response (JSON):

{
  "ok": true,
  "token": "1f0c9a41c58a7b2d90aa",
  "url": "https://upload.83blue.com/d/1f0c9a41c58a7b2d90aa",
  "filename": "data.csv",
  "size": 18874368,
  "size_human": "18 MB",
  "expires_at": "2027-02-04T14:00:00+00:00",
  "downloads": 0,
  "password": "Ab3k-Xy7q-Mn2p",
  "download": {
    "api": "https://upload.83blue.com/api/download?token=1f0c9a41c58a7b2d90aa&password=Ab3k-Xy7q-Mn2p",
    "curl": "curl -fL -OJ \"...\""
  },
  "handoff": "Give the receiving agent or person the url and the password. ..."
}

GET /api/download

Streams the file. Supports HTTP Range, so interrupted downloads resume and download managers can fetch in segments.

curl -fL -OJ "https://upload.83blue.com/api/download?token=TOKEN&password=PASSWORD"
ParameterMeaning
tokenThe 20-character transfer id, or the full share url (both accepted)
passwordThe transfer password

Errors are JSON: 404 unknown or expired, 403 wrong password. The share page form at /d/TOKEN and the direct link /dl/TOKEN?p=PASSWORD work too.

Capability and handoff urls

Every upload response also contains two special urls that carry their whole secret, so no separate password is needed:

UrlWhat it does
capability_url
/f/TOKEN/KEY
GET downloads the raw file (HTTP Range supported). DELETE removes the transfer immediately.
handoff_url
/h/TOKEN/KEY
GET returns a markdown briefing any model understands: what the transfer is, its manifest, the HANDOFF.md content for bundles, sha256, and the exact download commands. Send Accept: application/json for the same thing as structured data. This is the one url to paste into any chat with any model.
# fetch
curl -fL -OJ "https://upload.83blue.com/f/TOKEN/KEY"
# clean up when done
curl -X DELETE "https://upload.83blue.com/f/TOKEN/KEY"

The handoff convention: when bundling several files for another agent, put a HANDOFF.md (or INSTRUCTIONS.md / README.md) at the zip root with the briefing. The handoff url and the MCP receive_file tool surface it first, so the receiving agent knows what it has before downloading anything.

GET /api/info

Metadata without downloading: file name, size, sha256 (recorded for files up to 1 GB), expiry and download count.

curl "https://upload.83blue.com/api/info?token=TOKEN&password=PASSWORD"

Try it end to end in four commands

The service is trivially testable: upload a small file, check its sha256, fetch it back, delete it.

printf 'hello agent' > probe.txt
CAP=$(curl -sS -F "file=@probe.txt" "https://upload.83blue.com/api/upload?expires_days=1" | jq -r .capability_url)
curl -sS "$CAP" | sha256sum          # compare with .sha256 from the upload response
curl -sS -X DELETE "$CAP"            # {"ok":true,"deleted":true,...}

How do I upload files larger than 512 MB?

With the chunked, resumable protocol, up to 2 TB per file. Create a transfer, then append chunks (up to 256 MB each) until the declared size is reached. If the connection drops, ask for the current offset and continue from there; re-creating with the same fingerprint from the same IP resumes the same transfer.

  1. POST /api/create with JSON {"name", "size", "fingerprint"} (fingerprint: any 64-char hex string that identifies the file, e.g. sha256(name|size)). Optional: password, expires_days. Returns {token, offset, password}. Re-creating with the same fingerprint and size from the same IP resumes the unfinished transfer, and every create call issues a fresh password: always use the most recent one.
  2. POST /api/chunk?token=TOKEN&offset=OFFSET with raw bytes in the body. Returns the new offset; replies 409 with the real offset on a mismatch, and {"complete": true, "link": ...} when the file is done.
  3. GET /api/status?token=TOKEN at any time for the current offset.
#!/bin/bash
# resumable upload of a big file
FILE="big.iso"
SIZE=$(stat -c%s "$FILE")
FP=$(printf '%s' "$FILE|$SIZE" | sha256sum | cut -c1-64)

RES=$(curl -fsS -X POST https://upload.83blue.com/api/create \
  -H 'Content-Type: application/json' \
  -d "{\"name\":\"$FILE\",\"size\":$SIZE,\"fingerprint\":\"$FP\"}")
TOKEN=$(echo "$RES" | jq -r .token)
PASS=$(echo "$RES"  | jq -r .password)
OFFSET=$(echo "$RES" | jq -r .offset)

CHUNK_MB=64
while [ "$OFFSET" -lt "$SIZE" ]; do
  RES=$(dd if="$FILE" bs=1M skip=$((OFFSET / 1048576)) count=$CHUNK_MB 2>/dev/null \
    | curl -fsS -X POST --data-binary @- \
      "https://upload.83blue.com/api/chunk?token=$TOKEN&offset=$OFFSET")
  OFFSET=$(echo "$RES" | jq -r .offset)
done
echo "url: https://upload.83blue.com/d/$TOKEN  password: $PASS"

Uploads and downloads both resume, which matters for agents on flaky connections and for very large artefacts (model weights, datasets, disk images).

MCP server

A remote MCP server (Model Context Protocol, Streamable HTTP transport, no authentication) runs at:

https://upload.83blue.com/mcp

Seven tools: the four transfer tools below, plus deploy_site, list_sites and delete_site for static site hosting (see Host a static site).

ToolWhat it does
share_textUpload text (instructions, code, JSON, a prompt for another model) as a downloadable file; returns handoff + capability urls plus a share url and password
share_fileUpload one or more files in one call; several files are zipped into a single bundle server-side, so one url carries the whole handoff
share_conversationPackage a markdown transcript (context, instructions, task state) as HANDOFF.md plus any files into one bundle; returns the handoff url to paste into any chat with any model
receive_fileFetch a transfer by capability url (or share url + password); returns metadata with sha256, lists zip contents, reads the root HANDOFF.md first, inlines small text files, and hands back a curl command for anything bigger

(The original names send_text, send_files and receive still work as aliases.)

One-click installs: Add to Cursor · Install in VS Code

Claude Code

claude mcp add --transport http transfer https://upload.83blue.com/mcp

claude.ai and Claude Desktop

Settings > Connectors > Add custom connector > paste https://upload.83blue.com/mcp. No OAuth fields needed. Available on all plans.

ChatGPT

Desktop: Settings > MCP servers > Add server > paste the url. Or enable Developer mode (Settings > Apps > Advanced) and create a connector with authentication set to No authentication. Paid plans.

Codex CLI

codex mcp add upload83blue --url https://upload.83blue.com/mcp

Grok

App: grok.com/connectors > New Connector > Custom > paste https://upload.83blue.com/mcp (paid tiers). xAI API: add {"type": "mcp", "server_url": "https://upload.83blue.com/mcp", "server_label": "upload83blue"} to tools in a Responses API call.

Gemini CLI

gemini mcp add --transport http upload83blue https://upload.83blue.com/mcp

Or in settings.json (note the key is httpUrl, not url): { "mcpServers": { "upload83blue": { "httpUrl": "https://upload.83blue.com/mcp" } } }

Cursor

// ~/.cursor/mcp.json (global) or .cursor/mcp.json (project)
{ "mcpServers": { "transfer": { "url": "https://upload.83blue.com/mcp" } } }

VS Code (Copilot)

code --add-mcp '{"name":"upload83blue","type":"http","url":"https://upload.83blue.com/mcp"}'

Windsurf

{ "mcpServers": { "transfer": { "serverUrl": "https://upload.83blue.com/mcp" } } }

Cline

{ "mcpServers": { "transfer": { "url": "https://upload.83blue.com/mcp", "type": "streamableHttp" } } }

(Include "type": "streamableHttp"; without it Cline assumes SSE.)

Zed

{ "context_servers": { "transfer": { "url": "https://upload.83blue.com/mcp" } } }

(Zed supports remote HTTP natively now; no mcp-remote bridge needed.)

JetBrains AI Assistant (2026.1+)

Settings > Tools > AI Assistant > MCP > Add > paste { "url": "https://upload.83blue.com/mcp" }.

Warp

{ "transfer": { "url": "https://upload.83blue.com/mcp" } }

Raycast

Run the Install MCP Server command, choose HTTP transport, paste the url (Pro).

A2A (Agent2Agent protocol)

For agents speaking Google's A2A protocol, the agent card is published at the standard well-known location and a JSON-RPC endpoint (protocol 0.3.0, non-streaming) answers message/send synchronously:

Agent card: https://upload.83blue.com/.well-known/agent-card.json
Endpoint:   https://upload.83blue.com/a2a

How do two AI agents hand files to each other?

The sending agent uploads everything the next agent needs (instructions, code, data) and passes on two strings: the url and the password. That message is small enough to travel through any channel: a chat reply, a ticket, an e-mail, another model's context window, or an A2A message (this service is a natural host for the uri in an A2A FileWithUri part, which the A2A specification deliberately leaves to external infrastructure).

A handoff message that works well as a prompt for the receiving agent:

I have uploaded a bundle for you on 83blue.

url: https://upload.83blue.com/d/TOKEN
password: XXXX-XXXX-XXXX

Fetch it with:
curl -fL -OJ "https://upload.83blue.com/api/download?token=TOKEN&password=XXXX-XXXX-XXXX"

Unzip it and read INSTRUCTIONS.md first: it explains what each file is
and what you need to do.

Agents connected over MCP skip the shell entirely: the sender calls share_file or share_conversation, the receiver calls receive_file, and the bundle contents plus the root briefing are surfaced automatically so the receiving agent knows what it has.

Drop-in transfer.sh replacement

The classic transfer.sh service has been unreachable since 2024, but its upload pattern lives on in thousands of scripts and shell functions. This service answers the same wire contract: raw PUT to /{filename}, plain-text url response, so pointing an old script here just works:

# the classic pattern
curl --upload-file ./hello.txt https://upload.83blue.com/hello.txt
# -> https://upload.83blue.com/f/TOKEN/KEY/hello.txt   (plain text, GET it to download)

# the classic .bashrc function, one hostname swap
transfer() {
  curl --progress-bar --upload-file "$1" "https://upload.83blue.com/$(basename "$1")"
  echo
}

Agent memory and scratchpad

Because every transfer is a durable blob you fetch back by url, this doubles as short and long-term memory for AI agents. Dump text, JSON or a whole working context with share_text (or POST /api/upload), keep it for up to 180 days, then fetch it back by its capability url from a later session, another machine, or a different model:

# stash working memory (kept up to 180 days)
curl -F "file=@state.json" "https://upload.83blue.com/api/upload?expires_days=180"
# -> capability_url; save it, then in any later session:
curl -fL "https://upload.83blue.com/f/TOKEN/KEY"

It is blob-by-url storage (retrieve by the url you kept, not full-text search), which is exactly what agents need to offload context between sessions, cache intermediate artefacts, or pass state to the next agent. No account, no database to set up, and it cleans itself up when the transfer expires.

How do I host a static website an agent just built?

Send the files of a static site and get back a live public url straight away: no signup, no account, no API key. Built for when an agent has coded a landing page, demo, prototype or report and wants to show a human, or hand it to another agent. Each site is published at its own path, https://upload.83blue.com/s/{slug}/. The slug is auto-generated (something like brave-otter-482) unless you pick one yourself (3-40 characters, a-z, 0-9 and hyphens).

curl -sS -X POST https://upload.83blue.com/api/site \
  -H 'Content-Type: application/json' \
  -d '{"files":[{"path":"index.html","text":"<h1>Hello</h1>"},
                 {"path":"style.css","text":"h1{font-family:sans-serif}"}],
       "expires_days":30}'
# -> {"ok":true, "url":"https://upload.83blue.com/s/brave-otter-482/", "manage_key":"..."}
FieldMeaning
filesArray of {path, text} or {path, base64} (for images, fonts, media). Must include an index.html at the root
slugOptional custom path, 3-40 characters (a-z, 0-9, hyphens); auto-generated when omitted
expires_days1 to 30; sites auto-expire after 30 days

GET /api/site?site=... reports status, size and expiry; DELETE /api/site?site=...&manage_key=... takes it down. Redeploy with the same slug and manage_key to update or renew a site you own.

Over MCP, one call does the same thing:

ToolWhat it does
deploy_sitePublish a static site from a files array (each {path, text} or {path, base64}, including a root index.html); optional slug, title, expires_days (1-30) and manage_key to update your own site. Returns the live url and a manage_key
list_sitesLook up a site by url, host or slug; returns status, size and expiry
delete_siteTake a site down (pass the site plus its manage_key)

A site can be up to 50 MB across up to 300 files. Sites are served as pure static files: server-side code is never executed, and .php and other script files are refused, so nothing you upload runs on the server. A published page is public by design, so do not put secrets in it. Suspicious sites are flagged for review and can be taken down. It complements the file transfer and handoff tools above: the same service an agent already uses to move files can now put a web page live for the next task.

Limits and fair use

ThingLimit
Max file size2 TB (chunked); 512 MB in a single request; 100 MB per MCP call
Retention1 to 180 days; default 180 (6 months) for web and HTTP API uploads, 30 days for MCP tool calls
Simultaneous uploads3 site-wide. When all slots are busy the reply is HTTP 429 with a Retry-After header and a JSON error: wait a few seconds and retry
Download speed1 Mbit/s per connection after the first 512 KB, at most 3 download connections per IP: this service optimises for handoffs, not bulk speed
Accounts / API keysNone, ever
PriceFree
Automated useWelcome. Scripts, cron jobs, CI pipelines and AI agents are the intended audience

Fair use means: no illegal content, no malware distribution, no using the service as permanent primary storage or a CDN. See the terms. Infringing or harmful files can be reported; they are removed promptly (their links then return HTTP 410) and their hashes are blocked from re-upload. Normal automated use is never restricted.

Security and privacy

83blue · OpenAPI 3.1 · llms.txt · llms-full.txt · sitemap · terms
Free file transfer for AI agents and humans. No signup, no keys, no nonsense.