Flux Decentralized Cloud API (8.18.0)
Welcome to the comprehensive API reference for Flux, the world's leading decentralized Web3 cloud computing platform. This documentation covers all available API endpoints for interacting with the Flux network, nodes, and decentralized applications.
- 🌐 Decentralized Infrastructure: ~6,400 confirmed FluxNodes worldwide providing 52,000+ CPU cores, 170TB+ RAM and 3PB+ SSD storage across three tiers (Cumulus, Nimbus, Stratus)
- ⚡ High Performance: Enterprise-grade computing with automatic placement, fault-domain spreading and high availability
- 🔐 Secure by Design: Multiple authentication methods, enterprise app encryption and runtime tampering detection
- 💰 Cost Effective: Competitive pricing compared to traditional cloud providers
- 🚀 Developer Friendly: Docker-based deployments with comprehensive API support
- 🛡️ ArcaneOS: Hardened, attested node operating system with hardware-backed key custody
Network figures are a live snapshot; query GET /daemon/getfluxnodecount or stats.runonflux.io for current totals.
The Flux API uses a seven-level permission model to ensure secure and controlled access. Every endpoint in this document ends its description with the level it requires:
| Permission Level | Description | Authentication Required |
|---|---|---|
| Public | Open access endpoints | ❌ No |
User (user) | Any FluxID with a valid signature and a live session | ✅ Yes |
FluxTeam (fluxteam) | Flux Team and Flux Support identities | ✅ Yes |
Admin (admin) | The operator of this node (initial.zelid in its config) | ✅ Yes |
AdminAndFluxTeam (adminandfluxteam) | Node operator or Flux Team | ✅ Yes |
AppOwner (appowner) | The FluxID that registered the application | ✅ Yes |
AppOwnerAbove (appownerorfluxteam) | Application owner or Flux Team | ✅ Yes |
Every privilege is a set of identities and asks whether the caller is one of them — the compounds read OR, never AND. admin is a hardware role: the node operator administers the machine and is not a party to a customer's application, so app verbs (appstart, appremove, appkill, redeploy, …) require AppOwnerAbove rather than Admin.
Secure, Simple, Powerful - The next-generation 2FA wallet with enterprise security:
- True 2-of-2 Multi-Signature: Requires both browser extension and mobile app authorization
- Advanced Security: BIP48 derivation, Account Abstraction (ERC-4337), Schnorr signatures
- Multi-Chain Support: Bitcoin, Ethereum, Polygon, BSC, Avalanche, and 15+ blockchains
- WalletConnect v2: Connect to thousands of dApps seamlessly
- Professional Audit: Thoroughly audited by security experts in 2025
Installation:
- Chrome Extension: SSP Wallet - Chrome Web Store
- Mobile App: Available on iOS App Store and Google Play Store
- Website: sspwallet.io
Multi-Asset Cryptocurrency Wallet - The original Flux ecosystem wallet:
- Self-Custodial: Full control over your private keys
- Decentralized 2FA (d2FA): Unique blockchain-based two-factor authentication
- Multi-Chain: Support for 80+ blockchains and thousands of assets
- Hardware Integration: Connect with hardware wallets for enhanced security
- Deep Linking: Native
zel:protocol support
Installation: zelcore.io
Ethereum Ecosystem Wallet - Popular browser extension wallet:
- Ethereum Native: Full Ethereum and EVM chain support
- Sign-In with Ethereum (SIWE): ERC-4361 standard compliance
- Wide Adoption: Most popular Web3 wallet with extensive dApp support
- Domain Binding: Advanced phishing protection
Installation: metamask.io
Universal Wallet Connection Protocol - Connect any compatible wallet:
- 700+ Wallets: Support for hundreds of popular wallets
- Cross-Platform: Mobile, desktop, and web wallet compatibility
- Secure Bridge: Encrypted communication between wallet and dApp
- QR Code Connection: Simple mobile wallet connection
Authenticated requests carry a single zelidauth header. It is a URL-encoded query string, not JSON:
zelidauth: zelid=<address>&signature=<urlencoded-signature>&loginPhrase=<phrase>A complete example:
zelidauth: zelid=1CbErtneaX2QVyUfwU7JGB7VzvPgrgc3uC&signature=H%2BZB3oSrsw6XkBxxlbwk33LEBJYvqtbMIm2kL9JzuoXMC6pSZd0lBHdnhJYzMTXv81zZQ7G%2FpkK1NvYN7cNF0GE%3D&loginPhrase=1574991374806spbcvsuwerl52tppx9dw5khuz8rew13mkq86gg8r2cSignatures are base64 and routinely contain +, / and = — all three change meaning inside a query string, so the signature must be URL-encoded or the request will be refused as unauthentic.
Flux Cloud MCP is an MCP server that lets AI agents use Flux Cloud through this API: quote an app in US dollars, deploy it, pay for it, watch it come up, read its logs, update it and cancel it. It works with Claude, ChatGPT, Cursor, VS Code, Windsurf and other MCP hosts. Source: RunOnFlux/flux-cloud-mcp.
Hosted, nothing to install. Add it as a remote MCP server (Streamable HTTP):
https://mcp.runonflux.com/mcpIn Claude Code: claude mcp add --transport http flux-cloud https://mcp.runonflux.com/mcp. In VS Code and Cursor, use Connect MCP at the bottom of the sidebar.
The hosted server holds no keys. Read-only tools need none; tools that sign or pay take the keys as call arguments, used for that call only and never stored. Create a dedicated pair with flux_generate_keys and fund it with only what a deployment needs.
Local, keys stay on your machine. For larger budgets, run the server locally:
claude mcp add flux-cloud -s user \
-e FLUX_ID_PRIVATE_KEY=<wif> -e FLUX_PAYMENT_PRIVATE_KEY=<wif> \
-- npx -y @runonflux/flux-cloud-mcp- Documentation: docs.runonflux.com
- Discord Community: discord.gg/runonflux
- GitHub: github.com/RunOnFlux
- Twitter/X: @RunOnFlux
- Website: runonflux.com
FluxOS is free software published under the GNU AGPLv3. Flux, FluxOS, FluxNode and ArcaneOS are projects of InFlux Technologies USA LLC. © 2026 InFlux Technologies USA LLC.
🚀 Ready to build on the decentralized web? Let's get started!
This is the single most important thing to know about the Flux API.
A request that reaches a handler is answered at HTTP 200, in the body — including when the answer is a failure:
{ "status": "success", "data": { ... } }
{ "status": "error", "data": { "code": 401, "name": "Unauthorized", "message": "..." } }The code inside an error body is a FluxOS code, not a wire status. A removed endpoint answers HTTP 200 with data.code: 410; an unauthorised call answers HTTP 200 with data.code: 401. A client that branches on response.ok or response.status will read every one of these as a success.
const res = await fetch(url, { headers: { zelidauth } });
const body = await res.json();
if (body.status !== 'success') { // <- the check that matters
throw new Error(body.data?.message ?? 'Flux API error');
}The in-band shape exists so that a transport failure cannot impersonate a service answer. Wire statuses are therefore reserved for refusals that happen before a handler runs, and for a handful of endpoints that deliberately speak HTTP semantics:
| Status | Where it comes from |
|---|---|
403 | requireHttps — an ArcaneOS endpoint reached over plain HTTP |
503 / 400 | route guards — the node has not finished booting, or query parameters were sent to a route that rejects them |
413 | a request body too large to accept |
404 | a resource that does not exist to be addressed (an unknown operation id, a stream that is not enabled) |
202 | an endpoint that started long-running work — see below |
Endpoints that use wire statuses say so in their own responses section. Everything else answers 200 and puts the outcome in status.
Work whose duration scales with the data — copying, compressing or extracting inside an application volume — does not block the request. It answers 202 Accepted with a jobId, a Location header pointing at the status resource and a Retry-After header:
{ "status": "success",
"data": { "jobId": "op_2f8f...", "statusUrl": "/apps/operations/op_2f8f...", "status": "Running" } }Poll GET /apps/operations/{jobId} until data.status reaches a terminal value. Completion is read from that field, never from the HTTP code — a failed operation is still a successful poll.
status | Meaning |
|---|---|
Running | still working; respect Retry-After |
Succeeded | finished |
Failed | the work could not be done — error carries an RFC 9457 problem object |
Canceled | the caller asked for it via DELETE /apps/operations/{jobId} |
Evicted | the node took the work away — neither the caller's request nor their input was at fault |
Cancellation is best effort: the flag is raised and the worker stops at its next checkpoint, so status stays Running until it does.
Unknown, expired and not-yours are one answer (404) — a jobId must not reveal whether someone else has an operation running.
Every endpoint in this specification is served by an individual FluxNode. The https://api.runonflux.io gateway load-balances across confirmed nodes, so it is the right target for network-wide data (blockchain state, global application specifications, node lists) and the wrong target for anything that reports or changes the state of one machine.
Call a specific node directly — https://<node-ip>:16127 — for:
- node status, benchmark, tier, DOS state, clock drift, peers, topology
- the applications installed on that node, their logs, monitoring and volumes
- anything marked Admin or AdminAndFluxTeam, which is authorised against that node's operator FluxID
- the FluxShare, Syncthing, backup/restore and volume-browser surfaces
Node API calls are not rate-limited by FluxOS itself. The public gateway may apply its own limits.
Endpoints marked deprecated in this document still work; endpoints described as Removed answer an error body with code: 410.
| Kind | Endpoints |
|---|---|
Removed (answer code: 410) | /apps/apppause, /apps/appunpause, /apps/appmonitorstream, /apps/startmonitoring, /apps/stopmonitoring |
| Deleted (no longer routed) | /flux/cruxid, /flux/adjustcruxid, /flux/rebuildhome, /explorer/fluxtxs, /apps/installtemporarylocalapp, POST /apps/fluxshare/upload |
| Renamed | POST /apps/fluxshare/upload → POST /apps/fluxshare/uploadfile; /flux/rebuildhome → /flux/rebuildui; POST /syncthing/system/error/clear → GET |
| Aliases | every /zelid/* route aliases the matching /id/* route; every /daemon/*zelnode* route aliases its *fluxnode* counterpart; /flux/zelid aliases /flux/id; /benchmark/signzelnodetransaction aliases /benchmark/signfluxnodetransaction; /flux/broadcastmessageto{outgoing,incoming} both delegate to /flux/broadcastmessage |
Step 1: Get Login Phrase
curl -X GET "https://api.runonflux.io/id/loginphrase"Step 2: Sign the Login Phrase
- SSP Wallet: Use browser extension + mobile app to sign the message
- ZelCore: Use the wallet's message signing feature
- MetaMask: Use
personal_signmethod - Hardware Wallet: Sign via hardware device integration
Step 3: Verify Login
curl -X POST "https://api.runonflux.io/id/verifylogin" \
-H "Content-Type: application/json" \
-d '{
"zelid": "your-wallet-address",
"loginPhrase": "phrase-from-step-1",
"signature": "your-signature-from-step-2"
}'Step 4: Use Authentication Header
curl -X GET "https://api.runonflux.io/id/loggedsessions" \
-H "zelidauth: zelid=your-address&signature=your-signature&loginPhrase=your-phrase"Browser Extension Setup:
- Install SSP Wallet Chrome Extension
- Install SSP Key mobile app (iOS/Android)
- Pair devices using QR code
- Fund wallet with small amount for testing
Signing Messages with SSP:
// Connect to SSP Wallet
if (window.ssp) {
const accounts = await window.ssp.request({
method: 'wallet_requestPermissions',
params: [{ wallet_accounts: {} }]
});
// Sign login phrase
const signature = await window.ssp.request({
method: 'personal_sign',
params: [loginPhrase, accounts[0]]
});
}Connect and Sign:
// Connect MetaMask
const accounts = await ethereum.request({
method: 'eth_requestAccounts'
});
// Sign login phrase
const signature = await ethereum.request({
method: 'personal_sign',
params: [loginPhrase, accounts[0]]
});
// Use Ethereum address as zelid
const zelid = accounts[0];Deep Link Integration:
// Generate ZelCore deep link for signing
const zelcoreUrl = `zel:?action=sign&message=${encodeURIComponent(loginPhrase)}&icon=https://yourapp.com/icon.png&callback=${encodeURIComponent('https://yourapp.com/auth/callback')}`;
// Open ZelCore for signing
window.location.href = zelcoreUrl;WebSocket Integration:
// Listen for ZelCore signature via WebSocket
const ws = new WebSocket(`wss://api.runonflux.io/ws/id/${loginPhrase}`);
ws.onmessage = (event) => {
const authData = JSON.parse(event.data);
if (authData.status === 'success') {
// Authentication successful
console.log('Signed in with FluxID:', authData.data.zelid);
}
};Setup WalletConnect:
import { SignClient } from '@walletconnect/sign-client';
const signClient = await SignClient.init({
projectId: 'your-walletconnect-project-id',
metadata: {
name: 'Your Flux App',
description: 'Flux Network Integration',
url: 'https://yourapp.com',
icons: ['https://yourapp.com/logo.png']
}
});
// Connect to wallet
const { uri, approval } = await signClient.connect({
requiredNamespaces: {
eip155: {
methods: ['personal_sign'],
chains: ['eip155:1'],
events: ['chainChanged', 'accountsChanged']
}
}
});
// Sign message when connected
const signature = await signClient.request({
topic: session.topic,
chainId: 'eip155:1',
request: {
method: 'personal_sign',
params: [loginPhrase, address]
}
});Firebase Integration:
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth';
// Email/password login
const auth = getAuth();
const userCredential = await signInWithEmailAndPassword(auth, email, password);
// Get ID token for API authentication
const idToken = await userCredential.user.getIdToken();
// Use token in API calls
fetch('https://api.runonflux.io/protected-endpoint', {
headers: {
'Authorization': `Bearer ${idToken}`,
'Content-Type': 'application/json'
}
});Login Phrase Expiration:
// Always check phrase timestamp
const phraseTimestamp = parseInt(loginPhrase.substring(0, 13));
const now = Date.now();
const age = now - phraseTimestamp;
if (age > 15 * 60 * 1000) { // 15 minutes
throw new Error('Login phrase expired, get a new one');
}Signature URL Encoding:
// Always URL encode signatures for headers
const encodedSignature = encodeURIComponent(signature);
const authHeader = `zelid=${zelid}&signature=${encodedSignature}&loginPhrase=${loginPhrase}`;Error Handling:
try {
const response = await fetch('/api/authenticated-endpoint', {
headers: { 'zelidauth': authHeader }
});
if (response.status === 401) {
// Re-authenticate user
redirectToLogin();
}
} catch (error) {
console.error('API call failed:', error);
}Current Version: 8.18.0
Version Notes:
- All endpoints documented in this specification are available in FluxOS 8.18.0
- This documentation reflects the current stable API implementation and is generated against
ZelBack/src/routes.jsof the Flux repository - For the latest changes and updates, refer to the Flux GitHub repository
Notable changes since 6.6.x
| Area | What changed |
|---|---|
| Long-running operations | Volume and file operations no longer block the request. They return a jobId; poll GET /apps/operations/{jobId} and cancel with DELETE /apps/operations/{jobId}. |
| Volume file management | POST /apps/moveobject, /apps/copyobject, /apps/compressobject and /apps/extractobject operate inside an application's persistent volume. |
| Placement | POST /apps/placementfeasibility answers whether a prospective specification can be placed, and GET /apps/placementlocations publishes the live node/fault-domain/tier geography. |
| Network observability | GET /flux/topology, /flux/networkhealth, /flux/peerhistory, /flux/unstablenodes, /flux/peers and the SSE GET /flux/eventstream. |
| Tampering detection | GET /apps/tamperingevents reports containers whose running image no longer matches the registered specification. |
| ArcaneOS | GET /arcane/authchallenge and POST /arcane/configsync for hardware-attested node configuration. Available only on ArcaneOS nodes. |
| Syncthing | Metrics, health summary, metrics history and peer sync diagnostics endpoints, plus the full configuration write surface. |
| Deprecations | Every /zelid/* route is a deprecated alias of the matching /id/* route, and every /daemon/*zelnode* route a deprecated alias of its *fluxnode* counterpart. /flux/cruxid, /flux/adjustcruxid, /flux/rebuildhome, /explorer/fluxtxs and /apps/installtemporarylocalapp were removed; POST /apps/fluxshare/upload is now POST /apps/fluxshare/uploadfile. |