Skip to content

API Reference — Shares

A share turns a scanned-clean file into a public raw link served from the cookieless files domain (https://files.fluidadmin.com/s/<token>). Minting a share returns a one-time URL that embeds a signed token; FluidCloud stores only a hash of that token, so the plaintext link is shown once and never again.

All endpoints are under the API base https://api-cloud.fluidvip.com/api/v1 and the /shares prefix. Authenticate with your API key in the X-API-Key header (see authentication.md).

For the end-to-end "how do I publish a file and hand out a link" walkthrough, see guides/raw-links.md.

MethodPathScopePurpose
POST/sharesshares:writeMint a share link for a clean file
GET/sharesshares:readList the tenant's share links
DELETE/shares/{id}shares:writeRevoke a share link

The share token model

  • A file must be scanned clean (scan_status == "clean") before it can be shared. Every upload is automatically virus-scanned; sharing a not-yet-clean file returns 409. See "quarantine-until-clean" in concepts.md.
  • The minted link looks like https://files.fluidadmin.com/s/<token>. The token is HMAC-signed and verified at the edge — FluidCloud never proxies your file bytes.
  • The plaintext token appears only in the url field of the create response. It is stored hashed at rest, so a listed share (GET /shares) does not include the URL. If you lose the URL, revoke the share and mint a new one.
  • Links can be expiring (1–365 days; counts against your share-link quota) or permanent (expires_in_days: null; never expires, not counted against the share-link quota — metered as storage instead). The TypeScript/Python SDKs' files.upload({ public: true }) shortcut mints a permanent link and surfaces it as public_url.

POST /sharesscope shares:write

Creates a share link for a clean file your tenant owns and returns the one-time URL.

Request body — ShareCreate

FieldTypeDefaultNotes
file_idUUID string(required)The file to share. Must belong to your tenant and be scanned clean.
permissionstring"view""view" (served inline in-browser) or "download" (served as an attachment). Any other value → 422.
expires_in_daysinteger or null71365 for an expiring link, or null for a permanent public link that never expires. Out-of-range → 422.
passwordstring or nullnullAccepted and stored hashed. See known gaps — not enforced at serve time.
max_downloadsinteger or nullnullOptional download cap; minimum 1.

Response — 201 ShareCreated

FieldTypeNotes
urlstringThe full raw link, e.g. https://files.fluidadmin.com/s/<token>. Shown only here — capture it now.
idUUID stringThe share's id (use it to list/revoke).
expires_atISO-8601 UTC string or nullnull for a permanent link.
permissionstring"view" or "download".

Status codes

StatusWhen
201Share created.
402detail is quota_exceeded — you are at your share-link cap (expiring links only; permanent links skip this gate).
404File not found — unknown id, deleted, or it belongs to another tenant (cross-tenant ids return 404, never 403).
409File is not ready — scan_status is not yet clean (quarantine-until-clean). Retry once the scan completes.
422Validation — bad permission, or expires_in_days/max_downloads out of range.
429Rate limited — share-link creation is capped at 120/min per key (plus the global 600/min). Honor the Retry-After header.

Examples

curl

bash
curl -X POST https://api-cloud.fluidvip.com/api/v1/shares \
  -H "X-API-Key: fck_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "file_id": "5f1c2d3e-9a4b-4c6d-8e0f-1a2b3c4d5e6f",
    "permission": "view",
    "expires_in_days": 7
  }'
json
{
  "url": "https://files.fluidadmin.com/s/eyJ0eXAiOiJzaGFyZSJ9.aXNzdWVkLW9uY2U",
  "id": "9b8c7d6e-5f4a-4b3c-2d1e-0f9a8b7c6d5e",
  "expires_at": "2026-06-30T12:00:00Z",
  "permission": "view"
}

Python (pip install fluidcloud)

python
from fluidcloud import FluidCloud

fc = FluidCloud(api_key="fck_live_...")

share = fc.shares.create(
    file_id="5f1c2d3e-9a4b-4c6d-8e0f-1a2b3c4d5e6f",
    permission="view",
    expires_in_days=7,
)
print(share.url)  # capture this now — shown only once

# A permanent public link (never expires, not counted against the share-link cap):
public = fc.shares.create(file_id=share.id and "5f1c2d3e-9a4b-4c6d-8e0f-1a2b3c4d5e6f",
                          expires_in_days=None)

TypeScript (npm install fluidcloud)

ts
import { FluidCloud } from "fluidcloud";

const fc = new FluidCloud({ apiKey: "fck_live_..." });

const share = await fc.shares.create({
  fileId: "5f1c2d3e-9a4b-4c6d-8e0f-1a2b3c4d5e6f",
  permission: "view",
  expiresInDays: 7,
});
console.log(share.url); // capture this now — shown only once

// Permanent public link:
const publicShare = await fc.shares.create({
  fileId: "5f1c2d3e-9a4b-4c6d-8e0f-1a2b3c4d5e6f",
  expiresInDays: null,
});

Tip: if all you want is a permanent public hotlink for a file you're uploading, files.upload({ public: true }) mints one for you and returns it as public_url — see guides/uploading.md and reference/files.md.


GET /sharesscope shares:read

Returns your tenant's share links, newest first. By default only active links are returned (not revoked and not past expiry; a null expiry never expires).

Query parameters

ParameterTypeDefaultNotes
file_idUUID string(none)Filter to a single file's links.
include_inactivebooleanfalseWhen true, also return revoked and expired links.

Response — 200 array of ShareOut

FieldTypeNotes
idUUID stringThe share id.
file_idUUID stringThe shared file.
permissionstring"view" or "download".
expires_atISO-8601 UTC string or nullnull for permanent links.
max_downloadsinteger or nullThe download cap, if set.
download_countintegerDownloads recorded so far.
revokedbooleanWhether the link has been revoked.
has_passwordbooleanWhether a password was set (the password itself is never returned).
created_atISO-8601 UTC stringWhen the link was minted.
updated_atISO-8601 UTC stringLast modification.

The listed shape never includes the URL or token — those exist only in the one-time create response.

Status codes

StatusWhen
200List returned (may be empty).
429Rate limited — global 600/min per key. Honor Retry-After.

Examples

curl

bash
curl https://api-cloud.fluidvip.com/api/v1/shares \
  -H "X-API-Key: fck_live_..."

# Filter to one file, including revoked/expired links:
curl "https://api-cloud.fluidvip.com/api/v1/shares?file_id=5f1c2d3e-9a4b-4c6d-8e0f-1a2b3c4d5e6f&include_inactive=true" \
  -H "X-API-Key: fck_live_..."

Python

python
shares = fc.shares.list()
for s in shares:
    print(s.id, s.file_id, s.expires_at, s.revoked)

# Filter to one file, including inactive:
one_file = fc.shares.list(
    file_id="5f1c2d3e-9a4b-4c6d-8e0f-1a2b3c4d5e6f",
    include_inactive=True,
)

TypeScript

ts
const shares = await fc.shares.list();
for (const s of shares) {
  console.log(s.id, s.fileId, s.expiresAt, s.revoked);
}

// Filter to one file, including inactive:
const oneFile = await fc.shares.list({
  fileId: "5f1c2d3e-9a4b-4c6d-8e0f-1a2b3c4d5e6f",
  includeInactive: true,
});

DELETE /shares/{id}scope shares:write

Revokes a share link. This flips the link to revoked, frees the share-link quota slot (expiring links only — permanent links never consumed a slot), and pushes the link onto the edge denylist so it stops serving. The operation is idempotent: revoking an already-revoked link still returns 204 and never double-decrements your quota.

Path parameter

ParameterTypeNotes
idUUID stringThe share's id (from create or list).

Response

204 No Content — no body.

Status codes

StatusWhen
204Revoked (or already revoked — idempotent).
404Share link not found — unknown id or it belongs to another tenant (cross-tenant ids return 404, never 403).
429Rate limited — global 600/min per key. Honor Retry-After.

Examples

curl

bash
curl -X DELETE https://api-cloud.fluidvip.com/api/v1/shares/9b8c7d6e-5f4a-4b3c-2d1e-0f9a8b7c6d5e \
  -H "X-API-Key: fck_live_..."

Python

python
fc.shares.revoke("9b8c7d6e-5f4a-4b3c-2d1e-0f9a8b7c6d5e")

TypeScript

ts
await fc.shares.revoke("9b8c7d6e-5f4a-4b3c-2d1e-0f9a8b7c6d5e");

Known gaps

Two behaviors do not work the way you might expect. Design around them:

  • Passwords are not enforced at serve time. You may pass password on create and it is stored hashed (and has_password reflects it), but the edge serves any valid token without prompting for a password. Do not rely on a share password as an access control. Use short expiries, max_downloads, and revocation instead.
  • Revoking a permanent link is not instant at the edge. A revoked permanent link can still serve from edge cache until its cache max-age of 3600 seconds (1 hour) lapses. Plan for up to an hour of residual availability after revoking a permanent link. (Expiring links carry the same edge-denylist push and also stop being treated as active in the backend immediately.)

FluidCloud API — part of the Fluidvip ecosystem.