API Reference — Permanent deletion
Permanent deletion hard-deletes your data: it erases the file bytes from storage, removes the database record, and gives the storage back to your quota. There is no undo and no "undelete" endpoint. Use these endpoints only when you intend the data to be gone for good.
If you only want a recoverable delete (move to Trash), use the soft-delete on the Files endpoint instead — that leaves the bytes in place and restorable. The endpoints on this page are the irreversible counterpart.
| Method & path | What it does | Scope |
|---|---|---|
DELETE /gdpr/files/{file_id} | Permanently erase one file and free its quota | files:write |
DELETE /gdpr/trash | Permanently empty Trash (runs in the background) | files:write |
- Base URL:
https://api-cloud.fluidvip.com/api/v1 - Auth: send your key in
X-API-Key(orAuthorization: Bearer). See Authentication. - Both endpoints require the
files:writescope. A request without it returns403with a structureddetailwhoseerrorisinsufficient_scope. See Errors.
Irreversible. Once a permanent-deletion call commits, the bytes are removed from object storage and the row is removed from the database. There is no recovery path at the application layer. Walk through the consequences before you call these endpoints — and read Deleting data for the soft-delete vs. hard-delete decision.
Delete one file permanently
DELETE /gdpr/files/{file_id}Hard-deletes a single file your tenant owns. This is allowed whether or not the file is currently in Trash — you do not need to soft-delete it first. In one atomic operation the API:
- Revokes and deletes every share link pointing at the file (the link is killed at the edge first, then the record is removed).
- Erases the file's bytes from object storage.
- Releases the file's bytes back to your storage quota.
- Deletes the file record.
After this returns, any raw link (https://files.fluidadmin.com/s/<token>) that pointed at this file is dead and the file id no longer resolves.
Edge-cache caveat. A revoked permanent link can still serve from edge cache until its max-age of
3600seconds (1 hour) lapses. Treat permanent deletion as taking effect immediately for the API and within up to an hour at the edge.
Path parameters
| Name | Type | Description |
|---|---|---|
file_id | UUID string | The id of the file to erase. |
Response
204 No Content — success, empty body.
Status codes
| Status | Meaning |
|---|---|
204 | File permanently deleted. |
401 | Missing, invalid, or revoked API key. |
403 | insufficient_scope — the key lacks files:write. |
404 | File not found, or it is not yours. (Cross-tenant ids return 404, never 403, so existence never leaks.) |
429 | Rate limited — retry after the Retry-After header. |
There is no 409 quarantine check here: unlike sharing or serving, you may permanently delete a file at any time, including while it is still being scanned.
Examples
curl
curl -X DELETE "https://api-cloud.fluidvip.com/api/v1/gdpr/files/3f1c8e2a-7b4d-4a9e-9c1f-2d6b0a4e8f10" \
-H "X-API-Key: fck_live_your_key_here" \
-iA successful call returns HTTP/1.1 204 No Content with no body.
Python (pip install fluidcloud)
from fluidcloud import FluidCloud, NotFoundError
fc = FluidCloud(api_key="fck_live_your_key_here")
try:
fc.files.delete_permanent("3f1c8e2a-7b4d-4a9e-9c1f-2d6b0a4e8f10")
print("Erased.")
except NotFoundError:
print("Already gone (or not yours).")TypeScript (npm install fluidcloud)
import { FluidCloud, NotFoundError } from "fluidcloud";
const fc = new FluidCloud({ apiKey: "fck_live_your_key_here" });
try {
await fc.files.deletePermanent("3f1c8e2a-7b4d-4a9e-9c1f-2d6b0a4e8f10");
console.log("Erased.");
} catch (err) {
if (err instanceof NotFoundError) {
console.log("Already gone (or not yours).");
} else {
throw err;
}
}Idempotency tip. A second permanent-delete on the same id returns
404, not an error you need to special-case — the file is simply already gone. If you delete by your own logical key, resolve it first (see Files → resolve byclient_key); a resolve that404s means the file no longer exists.
Empty Trash permanently
DELETE /gdpr/trashPermanently purges everything currently in Trash for your tenant — every soft-deleted file (bytes, record, and its share links) and every soft-deleted folder. This is the bulk counterpart to deleting one file.
Because a Trash can hold thousands of files, the purge runs in the background. The call returns immediately with a count of what is being purged; the actual erasure completes asynchronously. Calling it again for the same scope while a sweep is already in progress is a no-op.
Irreversible, and broad. Without
space_id, this empties the Trash across every space in your tenant in one shot. Make sure that is what you want — restore anything you might still need (via the Files endpoint) before you call this.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
space_id | UUID string | No | Limit the purge to one space's Trash. Omit it to empty the universal Trash across every space in the tenant. |
Response
200 OK with a JSON body:
{
"status": "emptying",
"files": 142,
"bytes": 7340032
}| Field | Type | Description |
|---|---|---|
status | string | Always "emptying" — the background sweep has been accepted. |
files | integer | Number of trashed files counted for this purge at request time. |
bytes | integer | Total bytes those files occupy. This is roughly the quota you will get back when the sweep finishes. |
Because the sweep is asynchronous, a 200 means the purge was accepted and started, not that it has finished. Quota is released as files are erased; re-read it via the Quota endpoint shortly after to see the freed space.
Status codes
| Status | Meaning |
|---|---|
200 | Purge accepted and started (or a no-op if one was already running for this scope). |
401 | Missing, invalid, or revoked API key. |
403 | insufficient_scope — the key lacks files:write. |
404 | space_id was supplied but no such space exists in your tenant. |
429 | Rate limited — retry after the Retry-After header. |
Examples
curl — empty the entire tenant's Trash:
curl -X DELETE "https://api-cloud.fluidvip.com/api/v1/gdpr/trash" \
-H "X-API-Key: fck_live_your_key_here"curl — empty only one space's Trash:
curl -X DELETE "https://api-cloud.fluidvip.com/api/v1/gdpr/trash?space_id=9a2b7c1d-4e5f-4a6b-8c9d-0e1f2a3b4c5d" \
-H "X-API-Key: fck_live_your_key_here"Python
from fluidcloud import FluidCloud
fc = FluidCloud(api_key="fck_live_your_key_here")
# Empty the whole tenant's Trash.
result = fc.trash.empty()
print(result["status"], result["files"], "files")
# Or scope to a single space.
fc.trash.empty(space_id="9a2b7c1d-4e5f-4a6b-8c9d-0e1f2a3b4c5d")TypeScript
import { FluidCloud } from "fluidcloud";
const fc = new FluidCloud({ apiKey: "fck_live_your_key_here" });
// Empty the whole tenant's Trash.
const result = await fc.trash.empty();
console.log(result.status, result.files, "files");
// Or scope to a single space.
await fc.trash.empty({ spaceId: "9a2b7c1d-4e5f-4a6b-8c9d-0e1f2a3b4c5d" });Partial-on-interruption is safe. The sweep purges in batches. If it is interrupted, the files already purged are gone and the rest stay in Trash, ready to be purged by a later call. You can safely re-issue
DELETE /gdpr/trashfor the same scope.
What you cannot do with an API key
Tenant-wide erase (deleting your entire account and all of its data) and per-app erase are not available to API keys. Those operations are owner-only actions performed from the FluidCloud dashboard. An API key is scoped to file-level and Trash-level permanent deletion only.
Related
- Deleting data — the soft-delete (Trash) vs. permanent-delete workflow, and when to use each.
- Files — soft-delete to Trash, restore, and resolve by
client_key. - Shares — share links and how revocation behaves at the edge.
- Quota — read your storage usage; permanent deletion frees it.
- Errors — full error model and typed SDK errors.
- Rate limits — per-key and per-action limits.