Skip to content

Core concepts & resources

This page is your mental model for the FluidCloud Partner API. It defines every resource your API key touches — Tenant, Space, Folder, File, Share, and Quota — and the fields you get back on each one. It also walks the File lifecycle, the rule that matters most for storage backends (quarantine-until-clean), and an optional convenience for addressing files by your own key (client_key).

Each resource has a full endpoint reference: see Spaces, Folders, Files, Uploads, Shares, and Quota. New here? Start with the Quickstart.


How the resources nest

FluidCloud is hierarchical. Everything you create lives inside your tenant, and the containment chain is fixed:

Tenant  (your workspace — implicit, comes from your API key)
└── Space        (a top-level bucket you create)
    └── Folder    (optional tree inside a Space; can nest)
        └── File  (a stored object: the bytes + metadata)
            └── Share  (a raw link that serves one File's bytes)
  • A Space belongs to your tenant.
  • A Folder belongs to one Space (and may have a parent Folder).
  • A File belongs to one Space, and optionally one Folder.
  • A Share points at exactly one File.
  • Quota is a single per-tenant view of your usage and limits.

All ids are UUID strings. All timestamps are ISO-8601 UTC (e.g. 2026-06-23T14:05:00Z).


Tenant

Your workspace. A tenant is the unit of isolation and billing — every Space, Folder, File, and Share you create lives inside it, and your subscription (and its storage / share-link limits) attaches here.

You do not pass a tenant id on requests and there is no "tenants" endpoint. Your API key is your tenant: every call is automatically scoped to the tenant that owns the key, and you can only ever see your own data. This is why cross-tenant ids return 404 Not Found rather than 403 — an id outside your tenant simply does not exist as far as your key is concerned (see Errors).

The closest thing to a "read my tenant" call is the Quota endpoint, which reports your tenant's usage and limits.

Team membership, seats, and roles are an account-level concern managed in the dashboard and are not exposed to API keys.


Space

A top-level bucket within your tenant. A Space is the natural place to separate one logical area of your integration from another — for example one Space per customer, per project, or per environment. Folders and Files always live inside a Space.

Requires the spaces:read / spaces:write scopes. Full reference: Spaces.

Fields you see:

FieldTypeNotes
idUUID stringThe Space id; use it as space_id when creating folders and files.
namestringDisplay name you chose.
created_atISO-8601 UTCWhen the Space was created.
updated_atISO-8601 UTCLast modification time.
json
{
  "id": "5b1f2c0a-9d4e-4a77-8c21-0f3a6b8e1d22",
  "name": "Customer ACME — production",
  "created_at": "2026-06-20T09:12:44Z",
  "updated_at": "2026-06-20T09:12:44Z"
}

Folder

An optional tree inside a Space. Folders organize Files. They are self-referential — a Folder can have a parent Folder, so you can build an arbitrarily deep tree. Files may sit directly in a Space (no folder) or inside a Folder.

Folders are soft-deletable: deleting a Folder marks it deleted (it stops appearing in listings) without immediately destroying its contents. See Organizing files and Deleting data.

Requires the folders:read / folders:write scopes. Full reference: Folders.

Fields you see:

FieldTypeNotes
idUUID stringThe Folder id.
space_idUUID stringThe Space this folder belongs to.
parent_idUUID string or nullParent folder, or null if it sits at the Space root.
namestringDisplay name.
created_atISO-8601 UTCWhen the folder was created.
updated_atISO-8601 UTCLast modification time.
json
{
  "id": "a77c9e10-2b44-4d8f-bb0e-7c5a1d9e3f04",
  "space_id": "5b1f2c0a-9d4e-4a77-8c21-0f3a6b8e1d22",
  "parent_id": null,
  "name": "renders",
  "created_at": "2026-06-21T11:30:02Z",
  "updated_at": "2026-06-21T11:30:02Z"
}

File

A stored object — the bytes plus their metadata. This is the core resource of the API. A File lives in a Space (and optionally a Folder), carries identifying metadata (name, MIME type, size, content hash), and tracks two pieces of state that gate what you can do with it: its scan status and its lifecycle state.

The API never proxies your bytes. You upload directly from your client to storage via a presigned URL, and you serve bytes to the public over a raw Share link — see Uploading and Raw links. The File row is the metadata record of that object.

Requires the files:read / files:write scopes. Full reference: Files.

Fields you see:

FieldTypeNotes
idUUID stringThe File id (FluidCloud's canonical handle).
space_idUUID stringOwning Space.
folder_idUUID string or nullOwning Folder, or null if at the Space root.
client_keystring or nullYour own logical key, if you supplied one on upload. See client_key.
original_namestringThe filename you uploaded.
mimestring or nullContent type, e.g. image/png.
sizeinteger or nullSize in bytes.
sha256string or nullSHA-256 of the content, once known.
scan_statusstringpending, clean, or infected — gates sharing/serving (see below).
created_atISO-8601 UTCWhen the File row was created.
updated_atISO-8601 UTCLast modification time.
json
{
  "id": "c3e9a1b6-7f20-4f15-9a4d-2e6b8c0f1a33",
  "space_id": "5b1f2c0a-9d4e-4a77-8c21-0f3a6b8e1d22",
  "folder_id": "a77c9e10-2b44-4d8f-bb0e-7c5a1d9e3f04",
  "client_key": "results/job-7/out.png",
  "original_name": "out.png",
  "mime": "image/png",
  "size": 482113,
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "scan_status": "clean",
  "created_at": "2026-06-22T08:01:19Z",
  "updated_at": "2026-06-22T08:01:27Z"
}

The File lifecycle

A File moves through scanning, then optionally soft-delete and permanent purge.

upload (presign → PUT → complete)


  scan_status = pending     ← virus scan runs automatically

   ┌────┴────────────┐
   ▼                 ▼
 clean            infected
 (shareable)      (blocked — cannot be shared or served)


   soft-delete  ──restore──►  (back to live)


   permanent purge  (bytes + row destroyed; not recoverable)
  1. Upload. You start an upload, PUT the bytes straight to storage via the presigned URL, then complete the upload. The File row exists with scan_status: pending. See Uploading.
  2. Scan. Every uploaded file is automatically scanned for malware. While scanning, scan_status stays pending.
  3. Resolve. When scanning finishes the file becomes clean (safe to share and serve) or infected (permanently blocked from sharing and serving).
  4. Soft-delete / restore. Deleting a File marks it deleted — it leaves your listings but its bytes are retained for a grace window, so a delete is reversible by restoring it.
  5. Permanent purge. A purge destroys the bytes and the row. This is not recoverable. See Deleting data and Deletion.

Quarantine-until-clean

A File can only be shared or served once it has been scanned clean. This is the single most important rule for using FluidCloud as a file-link backend.

  • A freshly uploaded file is scan_status: pending.
  • If you try to create a share for it — or serve it — before scanning finishes (or if it came back infected), the API responds 409 Conflict (the file is not ready).
  • Once scan_status becomes clean, sharing and serving succeed.

Build your integration to wait for clean (poll the File, or retry the share on a 409 with backoff) before you publish a link. See the Uploading and Raw links guides for the polling pattern, and Errors for the 409 shape.


Share

A raw link that serves one File's bytes. A Share turns a clean File into a public URL that anyone with the link can open — served from the cookieless files domain, https://files.fluidadmin.com. A raw link looks like:

https://files.fluidadmin.com/s/<token>

The full token is returned once, at creation time — store it then, because it cannot be retrieved again. You can list and revoke shares afterward, but the link string itself is shown only on the create response. Creating a share counts against your tenant's share-link limit (see Quota).

A Share can only be created for a File whose scan_status is clean (otherwise 409, per quarantine-until-clean above). Requires the shares:read / shares:write scopes. Full reference: Shares; concepts and edge cases in Raw links.

Fields you see:

FieldTypeNotes
idUUID stringThe Share id.
file_idUUID stringThe File this link serves.
urlstringThe raw link https://files.fluidadmin.com/s/<token>. Returned only on the create response.
permissionstringview or download — how the bytes are served.
expires_atISO-8601 UTC or nullWhen the link stops working, or null for no expiry.
max_downloadsinteger or nullOptional cap on total downloads, or null for no cap.
download_countintegerHow many times the link has been served.
revokedbooleantrue once you revoke the link.
created_atISO-8601 UTCWhen the link was created.
updated_atISO-8601 UTCLast modification time.
json
{
  "id": "f0a4d2c8-3e51-4b9a-8d77-1c6e5b2f9a40",
  "file_id": "c3e9a1b6-7f20-4f15-9a4d-2e6b8c0f1a33",
  "url": "https://files.fluidadmin.com/s/Hk9_2pQ7zR4vXm1Lb0sN",
  "permission": "view",
  "expires_at": "2026-07-22T08:05:00Z",
  "max_downloads": null,
  "download_count": 0,
  "revoked": false,
  "created_at": "2026-06-22T08:05:00Z",
  "updated_at": "2026-06-22T08:05:00Z"
}

Known limitations to design around. A share-link password is accepted and stored but is not enforced at serve time — do not rely on it to gate access; use expires_at and max_downloads instead. And revoking a permanent (non-expiring) link does not take effect instantly: an already-cached copy can still serve from the edge for up to 3600 seconds (its max-age) after you revoke it. Both are covered in Security and Raw links.


Quota

Your tenant's usage and limits, in one read-only view. Before a big upload or a batch of shares, check Quota to know where you stand. Requires the quota:read scope. Full reference: Quota; guide: Quota and usage.

Fields you see:

FieldTypeNotes
bytes_usedintegerStorage you are currently using, in bytes.
bytes_limitintegerStorage allowance, in bytes. A generous pool comes with your plan.
links_usedintegerActive share links you have created.
links_limitintegerMaximum share links your plan allows.

A limit value of -1 means unlimited.

json
{
  "bytes_used": 18253611008,
  "bytes_limit": 1099511627776,
  "links_used": 412,
  "links_limit": 5000
}

These counters are FluidCloud's authoritative numbers and are checked synchronously on every write. Exceeding them returns 402 with detail equal to quota_exceeded (see Errors). Both an over-storage upload and an over-cap share return 402.


client_key — address a file by your own key

client_key is an optional convenience that lets you reference a File by your logical key instead of FluidCloud's file_id. This is ideal for a stateless backend: you don't have to persist FluidCloud's id alongside every object you store.

On upload, pass your own key (any string that makes sense to you):

text
client_key = "results/job-7/out.png"

Later, fetch that same File back by the key — without ever having stored its file_id — via files.resolve (GET /files/resolve). The resolver matches on your tenant and the key, and returns the most recent live match, so re-uploading under the same client_key supersedes the older object.

A few properties to keep in mind:

  • It is logical per tenant, not globally unique — two different tenants can use the same client_key with no collision.
  • A client_key is optional. Files you upload without one are addressed only by file_id (and client_key is null on the row).
  • Resolve returns the same File object shape shown above, so you can chain straight into sharing or deleting it.

See Files → resolve for the endpoint and the Uploading guide for setting it during upload.


Where to go next

FluidCloud API — part of the Fluidvip ecosystem.