Upload a file from an AI agent in 60 seconds
Authentication is a Bearer token. Payment is 5¢ via x402 (or debited from account credits). Retries are idempotent. The whole surface is OpenAPI 3.1 and MCP-discoverable.
1. Get an API key
One POST. Returns a key like fs_… tied to the email you provide. The same key handles auth, ownership, and your agent-credits ledger.
curl -X POST https://foldr.space/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"agent@example.com"}'Or browse to /developers/signup for a UI version.
2. Upload a file
Multipart POST to /api/v1/files. Every upload is permanent. Response carries the public URL, share token, and direct download URL.
curl -X POST https://foldr.space/api/v1/files \
-H "Authorization: Bearer fs_xxx" \
-H "Idempotency-Key: $(uuidgen)" \
-F "file=@report.pdf" \
-F "folder_slug=research"import { FoldrSpaceClient } from 'foldrspace'
const client = new FoldrSpaceClient({ apiKey: process.env.FOLDR_API_KEY })
const file = await client.uploadFile(blob, {
filename: 'report.pdf',
folderSlug: 'research',
})
console.log(file.publicUrl)from foldrspace import FoldrSpaceClient
client = FoldrSpaceClient(api_key=os.environ["FOLDR_API_KEY"])
f = client.upload_file("./report.pdf", folder_slug="research")
print(f.public_url)3. Handle the 402
If your key isn't Pro+ and your credits balance is empty, the upload returns 402 Payment Required with an x402 envelope. Sign one entry from accepts[] using your Base wallet, then retry the same call with the signed payload in X-PAYMENT.
{
"x402Version": 1,
"accepts": [{
"scheme": "exact",
"network": "base",
"maxAmountRequired": "50000",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0x0fF790fBBF1D26E533cCaf9c9C01EBE728509f74",
"resource": "https://foldr.space/api/v1/files",
"description": "5¢ per upload",
"maxTimeoutSeconds": 60
}]
}Sign with your Base wallet, base64-encode the signed payload, retry:
curl -X POST https://foldr.space/api/v1/files \
-H "Authorization: Bearer fs_xxx" \
-H "Idempotency-Key: <same key as before>" \
-H "X-PAYMENT: <base64 of signed payment payload>" \
-F "file=@report.pdf"Same Idempotency-Key means the original request slot is reused - no double-charge, even if you retry a third time.
4. Retries are safe
Always send Idempotency-Key on writes. Same key + same body replays the original response with Idempotent-Replayed: true. Same key + different body returns 422. In-flight duplicate returns 409 with Retry-After.
HTTP/1.1 201 Created
Idempotent-Replayed: true
{ "success": true, "file": { ... } } // original response, no second charge5. Move, share, list
Once the file exists, you can move it, mint a capability token (time-bounded share), list everything you've uploaded, or batch-delete.
// Mint a 1-hour, 5-use share link
const cap = await client.mintCapability(file.id, {
expiresIn: 3600,
maxUses: 5,
})
console.log(cap.downloadUrl)
// List everything in a folder
const files = await client.listFiles({ folderSlug: 'research' })
// Move into a different folder
await client.moveFile(file.id, 'archive')6. MCP, if you prefer
All of the above is exposed as MCP tools at /api/mcp (streamable-http transport). Connect from Claude Desktop, Cursor, or any MCP client and call upload_file, list_files, etc. directly. Same 5¢ per upload - MCP debits the credits ledger; x402 is HTTP-only.
Ship something
Get an API key, plug it into your agent, point its wallet at our 402 endpoint, and start uploading. Or skip x402 and pre-fund credits via Stripe.