— for ai agents & developers
Agent-to-agent file transfer.
ReTransfer is a file-transfer primitive for AI agents: a public REST API with bearer-token auth, an OpenAPI 3.1 contract, a stdio MCP server, and signed webhook delivery so two agents addressable by DID can exchange files without a human in the loop. Crawl /.well-known/agent.json to bootstrap.
Same primitive covers human-to-agent and human-to-human sends. The auth, the access controls, and the link semantics are uniform — only the recipient identifier (email vs DID) tells us which gate to run.
1. Discover
Every ReTransfer deployment exposes an agent manifest at the well-known path. It points at the API base URL, the OpenAPI document, supported capabilities, and rate limits — everything an agent needs to plan a call.
curl https://retransfer.one/.well-known/agent.json
curl https://retransfer.one/.well-known/openapi.jsonOr check this deployment directly: /.well-known/agent.json · /.well-known/openapi.json.
2. Authenticate
Auth is OTP-by-email. Agents that own an inbox can self-onboard without a browser: request a code, fetch it from the inbox, verify, receive a bearer token pair.
POST /v1/auth/otp/request { "email": "agent@example.com" }
POST /v1/auth/otp/verify { "email": "agent@example.com", "code": "123456" }
→ { "access_token": "...", "refresh_token": "...", "user": { ... } }Treat the access token as a normal bearer. Refresh with POST /v1/auth/refresh before it expires.
3. Send a transfer
Three-step send: register the file, PUT the bytes to the presigned URL, then finalize as a transfer with recipients and an access mode.
# 1. Reserve a slot and get a presigned upload URL.
POST /v1/files/init { "folder_id": "...", "name": "report.pdf",
"size": 12345, "mime": "application/pdf" }
→ { "file": { "id": "..." }, "upload_url": "https://..." }
# 2. Upload the bytes directly to object storage.
PUT <upload_url> <file bytes>
# 3. Mark the file complete and attach it to a new transfer.
POST /v1/files/{id}/complete
POST /v1/transfers/init { "file_ids": ["..."], "title": "..." }
POST /v1/transfers/{id}/finalize {
"access_control": "email", // or "public" | "password"
"expiration_days": 7,
"recipients": ["alice@example.com"]
}
→ { "link_url": "https://retransfer.one/t/<token>", ... }4. List, revoke, audit
Every transfer you create is queryable with the same bearer. Revoke when you're done; recipients lose access immediately.
GET /v1/transfers # list your sends
GET /v1/transfers/{id} # detail incl. per-recipient downloads
DELETE /v1/transfers/{id} # revoke (recipients can no longer download)5. MCP server (Claude Desktop, Cursor, Cline, Continue)
If your host speaks the Model Context Protocol, skip the raw HTTP and use the ReTransfer MCP server instead. It exposes four tools — retransfer_send_files, retransfer_list_transfers, retransfer_get_transfer, retransfer_revoke_transfer — over stdio JSON-RPC. Rate limits surface as a structured retry_after_seconds field; a stale access token auto-rotates when a refresh token is configured.
# Build the binary from this repo.
make mcp
# Wire it into Claude Desktop's mcp config (or any MCP host):
{
"mcpServers": {
"retransfer": {
"command": "/path/to/api/bin/retransfer-mcp",
"env": {
"RETRANSFER_ACCESS_TOKEN": "<your access token>",
"RETRANSFER_REFRESH_TOKEN": "<optional, enables auto-rotate>"
}
}
}
}6. Agent identity & agent-to-agent transfers
Upgrade your account to an autonomous agent identity and you become addressable by other agents as a DID — no inbox required. Publish a manifest at a URL you control, register it once, and we'll cache your public signing key. Senders addressing your DID receive a signed webhook to your inbox URL instead of an email.
# 1. Publish a manifest at any HTTPS URL you control.
{
"schema_version": "0.1",
"did": "agent:retransfer.one/u/<your-uuid>",
"name": "Acme Research Bot",
"inbox_url": "https://acme.example/agent/inbox",
"signing_key_jwk": { "kty": "OKP", "crv": "Ed25519", "x": "..." }
}
# 2. Register it. The webhook_secret in the response is one-time —
# capture it now, neither resolve nor re-register will echo it.
POST /v1/me/agent {
"agent_url": "https://acme.example/.well-known/agent.json",
"agent_inbox_url": "https://acme.example/agent/inbox"
}
→ { "did": "...", "webhook_secret": "<base64>", ... }
# 3. Anyone can now resolve your public profile.
GET /v1/agents/u/<your-uuid>When a sender finalizes a transfer addressed to your DID, we POST a signed payload to your inbox URL with X-ReTransfer-Signature (HMAC-SHA256 over ts.delivery_id.body), X-ReTransfer-Timestamp, and X-ReTransfer-Delivery-Id. Verify with your shared secret. Reject anything outside ±5min of wall-clock or any delivery-id you've seen before. Deliveries retry with backoff (1m → 5m → 30m → 2h → 12h, then dead-letter).
Usage example — Robomotion Hermes agent
Robomotion Hermes is a conversational AI agent that orchestrates business workflows via natural-language prompts. When a Hermes user asks it to "send last week's QA report to alice@acme.com", Hermes resolves the file, picks the recipient, and calls the ReTransfer API end-to-end — same three-step shape as Section 3, wired into a Hermes flow.
# Hermes flow: "Send a file with ReTransfer"
# Variables already populated by previous nodes:
# {{access_token}} bearer minted at agent onboarding (Section 2)
# {{file_path}} local path Hermes picked up from the prompt
# {{recipient}} "alice@acme.com" — resolved from the prompt
# {{title}} "QA report — week 24"
# Step 1 — register the file, get a presigned upload URL.
POST https://retransfer.one/api/v1/files/init
Authorization: Bearer {{access_token}}
Content-Type: application/json
{
"name": "{{ basename(file_path) }}",
"size": {{ filesize(file_path) }},
"mime": "application/pdf"
}
→ { "file": { "id": "{{file_id}}" }, "upload_url": "{{upload_url}}" }
# Step 2 — Hermes uploads the bytes straight to object storage.
PUT {{upload_url}}
Body: <bytes of {{file_path}}>
# Step 3 — finalize as a transfer and let ReTransfer email the recipient.
POST https://retransfer.one/api/v1/files/{{file_id}}/complete
POST https://retransfer.one/api/v1/transfers/init
{
"file_ids": ["{{file_id}}"],
"title": "{{title}}"
}
→ { "transfer": { "id": "{{transfer_id}}" } }
POST https://retransfer.one/api/v1/transfers/{{transfer_id}}/finalize
{
"access_control": "email",
"expiration_days": 7,
"recipients": ["{{recipient}}"]
}
→ { "link_url": "https://retransfer.one/t/<token>" }
# Hermes replies to the user:
# "Done — sent QA report to alice@acme.com, expires in 7 days."Same pattern works for any HTTP-capable agent runtime — Robomotion Hermes, LangChain, n8n, Make, Zapier, a custom Python or Go worker. The only contract is the four POSTs above and a stable bearer token. For Claude Desktop / Cursor / Cline users, the MCP server in Section 5 collapses the four calls into a single retransfer_send_files tool invocation.
Limits & etiquette
- Files are capped at 50 GB each.
- Up to 10 recipients per transfer.
- Rate limits: 60 file inits, 30 transfer inits, 30 finalize calls per minute per bearer. Each response carries the current
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset— back off before you hit the cap. - At-rest encryption is on by default. End-to-end encryption is available — pass an
encryptionblock on finalize and the server never sees plaintext. - Unauthorised volume looks like spam to inbox providers and to us. Don't fan out one transfer to many recipients to bypass the per-transfer cap; that's the kind of behaviour that gets accounts suspended.