Preview · API may change before GA

VirtualDrive Cloud docs

Object storage for developers and AI agents. Add file storage to any app in minutes.

Quickstart

Create a project in the dashboard, generate an API key, then install the SDK:

npm install @virtualdrive/cloud
import { VirtualDrive } from "@virtualdrive/cloud";

const vd = new VirtualDrive(process.env.VD_API_KEY);

const file = await vd.files.upload({ name: "hello.txt", data: "hi!" });
console.log(file.url);

Authentication

Every request authenticates with a project API key sent as a Bearer token. Keys are scoped to a single project and a set of permissions (files:read, files:write, files:delete). Keys are shown once at creation — store them as a secret.

Authorization: Bearer vdk_live_xxxxxxxxxxxxxxxx

Upload a file

Upload bytes directly, or request a presigned URL for large/browser-direct uploads.

curl https://api.virtualdrive.cloud/v1/files \
  -H "Authorization: Bearer $VD_API_KEY" \
  -F "name=report.pdf" \
  -F "file=@report.pdf"

Download & signed URLs

Every file can be served via a short-lived signed URL. Nothing is public by default.

const { url } = await vd.files.signedUrl(fileId, { expiresIn: 3600 });

List & delete

const { files } = await vd.files.list({ prefix: "invoices/" });
await vd.files.delete(fileId);

Framework examples

A few common integrations. All use the JS SDK; keep your key server-side.

Next.js — route handler

// app/api/upload/route.ts
import { VirtualDrive } from "@virtualdrive/cloud";
const vd = new VirtualDrive(process.env.VD_API_KEY!);

export async function POST(req: Request) {
  const form = await req.formData();
  const file = form.get("file") as File;
  const stored = await vd.files.upload({
    name: file.name,
    data: await file.arrayBuffer(),
    contentType: file.type,
  });
  return Response.json({ url: stored.url });
}

Express

import express from "express";
import { VirtualDrive } from "@virtualdrive/cloud";
const vd = new VirtualDrive(process.env.VD_API_KEY);

app.post("/upload", async (req, res) => {
  const file = await vd.files.upload({ name: req.body.name, data: req.body.data });
  res.json({ url: file.url });
});

Swift (iOS / macOS)

import VirtualDrive

let vd = VirtualDrive(apiKey: ProcessInfo.processInfo.environment["VD_API_KEY"]!)
let file = try await vd.files.upload(name: "photo.jpg", data: imageData, contentType: "image/jpeg")
print(file.url)

Swift Package: add this repo's sdk-swift via Swift Package Manager (iOS 15+ / macOS 12+). Keep the key server-side for shipped apps; use a short-lived key or proxy for clients.

Browser

Never put your API key in the browser. Upload through your server (examples above), or have the server return a signed URL for the client to use.

MCP server

Connect any AI agent to your storage over the Model Context Protocol. Point your MCP client at the hosted endpoint with a project key, or run the local shim:

npx @virtualdrive/mcp --key $VD_API_KEY

# Tools exposed: list_files, read_file, write_file, delete_file

LLM-readable API summary: /developers/llms.txt

Webhooks

Register an endpoint in the dashboard to receive events: file.uploaded, file.deleted. Each delivery is a POST with an HMAC-SHA256 signature so you can verify it came from us.

// Headers on every delivery:
//   X-VD-Event: file.uploaded
//   X-VD-Signature: sha256=<hex>
// Verify (Node):
import crypto from "crypto";
const sig = "sha256=" + crypto.createHmac("sha256", WHSEC).update(rawBody).digest("hex");
if (sig !== req.headers["x-vd-signature"]) throw new Error("bad signature");

// Body: { "event": "file.uploaded", "created": "...",
//         "data": { "id": "...", "name": "...", "size": 1234 } }

Errors & limits

Standard HTTP status codes. 401 invalid key · 403 scope/quota · 413 file too large · 429 rate limited · 503 service paused. Usage is metered per project (stored bytes + requests); a generous free tier is included at launch.

VirtualDrive Cloud is in early access.

APIs may change before GA. Join the waitlist to get your keys first.