Quick Start
All endpoints require API Key authentication via headers unless noted as public.
Authentication
// Request headers
X-API-Key: <your_key_id>
X-API-Secret: <your_key_secret>
Create or view keys in Developer Dashboard → API Keys.
Base URL
Your server origin is auto-detected.
Endpoints
/api/v1/files/upload
Upload a file (multipart). On private buckets, the file is stored securely and streamed on download.
Fields: file (required), bucket,
folder, tags, metadata,
createPublicLink ("true"),
expiresIn (hours, 0=never),
downloadLimit (0=unlimited).
Also accepts createShareLink for backward
compatibility.
curl -X POST "$ORIGIN/api/v1/files/upload" \
-H "X-API-Key: $KEY" \
-H "X-API-Secret: $SECRET" \
-F file=@"./image.png" \
-F bucket=media \
-F folder=images/avatars \
-F tags="avatar,profile" \
-F createPublicLink=true
Response
{
"success": true,
"file": { "fileId": "...", "fileName": "image.png", "fileSizeMB": 1.23, ... },
"links": {
"downloadUrl": "$ORIGIN/api/v1/files/{fileId}/download",
"publicLink": { "shareUrl": "$ORIGIN/api/share/{linkId}", "expiresAt": "2100-01-01T00:00:00.000Z", "downloadLimit": 0 }
}
}
Response also includes links.shareLink as a
legacy alias.
/api/v1/files
List files with filters. Query: bucket,
folder, page, limit,
sortBy, sortOrder,
search, tags,
view=list|tree.
curl -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" "$ORIGIN/api/v1/files?bucket=media&folder=images"
/api/v1/files/:fileId
Get file metadata.
curl -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" "$ORIGIN/api/v1/files/{fileId}"
/api/v1/files/:fileId/download
Stream file content (server-to-server). Requires headers.
curl -L -o file.bin \
-H "X-API-Key: $KEY" \
-H "X-API-Secret: $SECRET" \
"$ORIGIN/api/v1/files/{fileId}/download"
/api/v1/files/:fileId
Delete (mark inactive and remove from storage).
curl -X DELETE -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" "$ORIGIN/api/v1/files/{fileId}"
/api/v1/structure
Returns folder structure (for building file browsers).
curl -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" "$ORIGIN/api/v1/structure"
/api/v1/usage
Plan usage and limits (storage, bandwidth, API calls).
curl -H "X-API-Key: $KEY" -H "X-API-Secret: $SECRET" "$ORIGIN/api/v1/usage"
/api/share/:linkId
Public link (no headers). Add ?inline=true to
hint inline display.
curl -L -o file.bin "$ORIGIN/api/share/{linkId}"
Axios Examples (Node.js)
Use these from your server code. Do not embed API keys in browser code.
Upload with public link
import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';
const API_BASE = '$ORIGIN/api/v1';
const headers = { 'X-API-Key': process.env.API_KEY, 'X-API-Secret': process.env.API_SECRET };
async function upload() {
const form = new FormData();
form.append('file', fs.createReadStream('./image.png'));
form.append('bucket', 'media');
form.append('folder', 'images/avatars');
form.append('tags', 'avatar,profile');
form.append('createPublicLink', 'true'); // immediate public link
const res = await axios.post(`${API_BASE}/files/upload`, form, {
headers: { ...headers, ...form.getHeaders() },
maxContentLength: Infinity,
maxBodyLength: Infinity,
});
console.log('fileId:', res.data.file.fileId);
console.log('shareUrl:', res.data.links?.publicLink?.shareUrl);
console.log('downloadUrl (auth):', res.data.links?.downloadUrl);
}
upload().catch(console.error);
List files
import axios from 'axios';
const API_BASE = '$ORIGIN/api/v1';
const headers = { 'X-API-Key': process.env.API_KEY, 'X-API-Secret': process.env.API_SECRET };
async function listFiles() {
const res = await axios.get(`${API_BASE}/files?bucket=media&folder=images`, { headers });
console.log(res.data.files.map(f => ({ id: f.fileId, name: f.fileName })));
}
listFiles().catch(console.error);
Download (stream to disk)
import axios from 'axios';
import fs from 'fs';
const API_BASE = '$ORIGIN/api/v1';
const headers = { 'X-API-Key': process.env.API_KEY, 'X-API-Secret': process.env.API_SECRET };
async function download(fileId) {
const resp = await axios.get(`${API_BASE}/files/${fileId}/download`, {
headers,
responseType: 'stream',
});
const out = fs.createWriteStream('download.bin');
resp.data.pipe(out);
await new Promise((r, j) => { out.on('finish', r); out.on('error', j); });
console.log('Downloaded');
}
download(process.env.FILE_ID).catch(console.error);
Create public link
import axios from 'axios';
const API_BASE = '$ORIGIN/api/v1';
const headers = { 'X-API-Key': process.env.API_KEY, 'X-API-Secret': process.env.API_SECRET };
async function share(fileId) {
const res = await axios.post(`${API_BASE}/files/${fileId}/share`, {
expiresIn: 0, // unlimited
downloadLimit: 0, // unlimited
}, { headers });
console.log('shareUrl:', res.data.publicLink.shareUrl);
}
share(process.env.FILE_ID).catch(console.error);
Use public link in HTML
<img src="$ORIGIN/api/share/{linkId}?inline=true" alt="image" />
Public links require no headers and are safe to embed. Authenticated download URLs are for server-to-server usage only.
Implementation Example: Express + React
This is a minimal end-to-end setup showing how to upload a file from a React app via your own Express server and immediately get a public link to embed. Public links are the recommended way to display files freely (no auth headers).
Server (Express)
Create a small proxy so your API keys stay on the server. The
server forwards the upload to the Developer API with
createPublicLink set to "true", then
returns the publicLink.shareUrl.
// server.js
import express from 'express';
import multer from 'multer';
import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';
const app = express();
const upload = multer({ dest: 'tmp/' });
const API_BASE = '$ORIGIN/api/v1'; // Your Rivspace server origin is injected below
const HEADERS = {
'X-API-Key': process.env.API_KEY,
'X-API-Secret': process.env.API_SECRET,
};
app.post('/upload', upload.single('file'), async (req, res) => {
try {
const form = new FormData();
form.append('file', fs.createReadStream(req.file.path), req.file.originalname);
form.append('bucket', 'media');
form.append('folder', 'public');
form.append('createPublicLink', 'true'); // return a browser-usable public link
const resp = await axios.post(`${API_BASE}/files/upload`, form, {
headers: { ...HEADERS, ...form.getHeaders() },
maxContentLength: Infinity,
maxBodyLength: Infinity,
});
// Clean temp file
try { fs.unlinkSync(req.file.path); } catch {}
// Prefer publicLink for embedding; downloadUrl is for server-to-server (with headers)
const publicLink = resp.data.links?.publicLink?.shareUrl
|| resp.data.links?.shareLink?.shareUrl
|| null;
return res.json({
success: true,
fileId: resp.data.file.fileId,
publicUrl: publicLink,
downloadUrl: resp.data.links?.downloadUrl,
});
} catch (err) {
return res.status(500).json({ success: false, message: 'Upload failed', error: err.message });
}
});
app.listen(3001, () => console.log('Server running on http://localhost:3001'));
Important: never expose API keys in the browser. Keep them on the server.
Client (React)
Upload a file to your server and render the returned
publicUrl.
// App.jsx (simplified)
import React, { useState } from 'react';
export default function App() {
const [file, setFile] = useState(null);
const [publicUrl, setPublicUrl] = useState('');
const onUpload = async () => {
if (!file) return;
const form = new FormData();
form.append('file', file);
const resp = await fetch('/upload', { method: 'POST', body: form });
const data = await resp.json();
setPublicUrl(data.publicUrl);
};
return (
setFile(e.target.files?.[0] || null)} />
{publicUrl && (
)}
);
}
Add ?inline=true to hint inline display for
images/video where supported.
Why public links?
Public links are designed for browser usage and embeds. They
require no headers and are safe to use in HTML tags. The
authenticated downloadUrl is meant for
server-to-server transfers and should not be used in the
browser.
Errors
Common error codes and meanings.
-
INVALID_API_KEY: API Key/Secret mismatch or inactive key. -
FILE_TOO_LARGE,STORAGE_LIMIT_EXCEEDED,BANDWIDTH_LIMIT_EXCEEDED: Plan limits reached. -
FILE_NOT_FOUND,DELETE_ERROR,DOWNLOAD_ERROR -
RATE_LIMIT_EXCEEDED: Too many requests (per IP or per API plan).
Best Practices
-
Use public links in HTML tags (
<img>,<video>, etc.). - Use authenticated download URLs for server-to-server (headers required).
-
Organize with
bucketandfolderto simplify browsing and lifecycle management. -
Attach
tagsandmetadatato enable rich filtering and analytics.