Appearance
API Reference — Picker
The endpoints behind the embeddable picker. Most integrations never call these directly — the picker.js loader and the picker page drive them for you — but they are documented here for completeness and for building a custom picker experience.
All endpoints are under the API base https://api-cloud.fluidvip.com/api/v1.
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /picker/context | none (public) | May origin X embed the picker (under client id Y)? |
POST | /picker/grants | user session (JWT) | Turn the signed-in user's selection into short-lived URLs |
PUT | /me/api-keys/{key_id}/picker | user session (JWT, admin) | Register your app's embed origins; mints the publishable client id |
Sessions, not API keys
/picker/grants and the origin registration are interactive endpoints: they authenticate the human user's Supabase session JWT and reject API keys. Your secret fck_ key plays no role in the browser flow — the only key-adjacent value that ships to the page is the publishable fcpk_ client id.
Check embed permission
GET /picker/context?origin=…[&client_id=…] — public
The picker page calls this before rendering anything. A deny is a normal 200 answer (never an HTTP error), and deny reasons are deliberately coarse so client ids can't be enumerated.
Query parameters
| Param | Type | Notes |
|---|---|---|
origin | string | The candidate host-page origin, e.g. https://app.example.com. Bare origin only (scheme + host + optional port). |
client_id | string | Your fcpk_ publishable id. Omit for first-party Fluid platforms. |
Response — 200
| Field | Type | Notes |
|---|---|---|
allowed | boolean | Whether this origin may embed the picker. |
first_party | boolean | true when the origin matched the first-party platform list. |
app_name | string or null | Your API key's label (shown in the picker header) — set only for an allowed developer embed. |
reason | string or null | On deny: invalid_origin (not a bare http(s) origin) or origin_not_allowed (everything else — unknown client id, unregistered origin, revoked key, or lapsed plan). |
Rate limited per caller IP at 120/min (429 beyond that).
Mint pick URLs
POST /picker/grants — user session only (API keys get 403)
Converts a confirmed selection of the signed-in user's own files into short-lived signed URLs on the files domain. Stateless: nothing is persisted, no share-link quota is consumed, and the URLs simply expire (~30 minutes). Every file must be visible to the user under their normal tenant / workspace / folder-grant rules and scanned clean.
Request body
| Field | Type | Default | Notes |
|---|---|---|---|
origin | string | (required) | The host-page origin — re-validated server-side exactly like /picker/context. |
client_id | string | — | Your fcpk_ id (omit for first-party origins). |
file_ids | UUID string[] | (required) | 1–100 file ids. |
disposition | string | "inline" | "inline" (fetch/render) or "attachment" (download headers). |
Response — 200
json
{
"items": [
{
"id": "1f9b839c-…",
"name": "Example.jpg",
"mime": "image/jpeg",
"size": 9022,
"url": "https://cloud-files.fluidvip.com/s/…",
"expires_at": 1783456425
}
],
"expires_at": 1783456425
}expires_at is UNIX seconds (~30 minutes out). Items come back in request order.
Status codes
| Status | When |
|---|---|
400 | Invalid origin format, or bad disposition. |
403 | Caller is an API key (session required), or the origin is not allowed for this client id. |
404 | Any requested file is unknown, trashed, another tenant's, or outside the caller's folder grants — the whole request fails (no partial answers). |
409 | not_clean — the selection includes files not yet scanned clean. |
429 | Rate limited — 60/min per user. |
Register embed origins
PUT /me/api-keys/{key_id}/picker — user session, tenant admin, Elite plan
Registers the exact web origins allowed to embed the picker under one of your self-serve API keys. The first non-empty registration mints the key's publishable fcpk_ client id, which is thereafter stable. Requires the fluidcloud_api plan feature (like minting the key itself).
Request body
| Field | Type | Notes |
|---|---|---|
origins | string[] | Up to 10 bare origins. https:// required — plain http:// is accepted only for localhost / 127.0.0.1. [] disables embedding while keeping the client id. |
Response — 200
The full masked key object, now including:
| Field | Type | Notes |
|---|---|---|
picker_public_id | string or null | Your publishable fcpk_ client id. Safe to ship in page source. |
picker_origins | string[] | The registered origins (normalized: lower-cased host, no trailing slash). |
These two fields also appear on every key listed by GET /me/api-keys.
Status codes
| Status | When |
|---|---|
400 | An entry is not a valid registrable origin. |
403 | feature_not_in_plan — the FluidCloud API feature (Elite) is required. |
404 | The key id is unknown, another tenant's, or not a self-serve key. |
409 | The key is revoked. |
Example
bash
curl -X PUT https://api-cloud.fluidvip.com/api/v1/me/api-keys/KEY_ID/picker \
-H "Authorization: Bearer USER_JWT" \
-H "Content-Type: application/json" \
-d '{"origins": ["https://app.example.com", "http://localhost:3000"]}'