Groundfloor Docs

Files API

Presigned upload and download for workspace-scoped object storage.

Base path: /v1/workspaces/{workspace_id}/files

File bytes never proxy through Control Plane. The API owns metadata and mints presigned URLs; clients transfer data directly with S3/MinIO.

See also: Customer Portal — Files

Upload lifecycle

sequenceDiagram
  participant Client
  participant CP as Control Plane
  participant S3 as Object Store

  Client->>CP: POST /files/upload-url
  CP-->>Client: presigned PUT URL + file_id
  Client->>S3: PUT bytes
  Client->>CP: POST /files/{id}/finalize
  CP->>S3: HEAD object
  CP-->>Client: active file metadata

List files

GET /v1/workspaces/{workspace_id}/files

Permission: read

Returns up to 200 active files, newest first.

Request upload URL

POST /v1/workspaces/{workspace_id}/files/upload-url

Creates a pending row and returns a presigned PUT URL (default TTL 3600s).

Permission: write

curl -s -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"report.pdf","content_type":"application/pdf","size_bytes":1048576}' \
  "$CP_URL/v1/workspaces/$WORKSPACE_ID/files/upload-url" | jq .

Request body

FieldTypeRequired
namestringYes
content_typestringYes
size_bytesintegerNo

Response 200

{
  "file": { "id": "…", "name": "report.pdf", "status": "pending", "…": "…" },
  "upload_url": "https://…",
  "expires_in_s": 3600
}

Upload bytes with curl -X PUT -T report.pdf -H "Content-Type: application/pdf" "$UPLOAD_URL".

Finalize upload

POST /v1/workspaces/{workspace_id}/files/{file_id}/finalize

HEADs the object in storage, captures true size/content-type, promotes row to active.

Permission: write

Download URL

GET /v1/workspaces/{workspace_id}/files/{file_id}/download-url

Returns a short-lived presigned GET URL.

Permission: read

Delete file

DELETE /v1/workspaces/{workspace_id}/files/{file_id}

Removes object from bucket and marks row deleted.

Permission: delete

Object key namespacing

Server controls keys: workspaces/{workspace_id}/files/{file_id} — clients cannot target another workspace's prefix.