HTTP API

The file service the CLI and both MCP servers call. Trade an API token for a session, then call it with that.

Base URL
fffs.freakingfast.io
Requests
POST, JSON
Spec
OpenAPI 3.1

Authenticate#

An API token doesn't call the file service itself. Trade it at /exchange-token for a session token, and send that as the bearer token, along with X-Absurd-App: fffd.

Trade a token
curl -X POST https://auth.freakingfast.io/exchange-token \
  -H "Authorization: Bearer $FREAKING_FAST_API_TOKEN"
Answer
{
  "gelToken": "eyJhbGciOiJIUzI1NiIs…",
  "expiresIn": 86400,
  "userId": "73ad9b0e-7227-11ef-9399-bfdd82c9e268"
}

The session lasts a day, as expiresIn says in seconds. Trade the token again before it runs out. Keep userId: new files go under users/{userId}/.

Then call the service
curl -X POST https://fffs.freakingfast.io/search-files \
  -H "Authorization: Bearer $SESSION" \
  -H "X-Absurd-App: fffd" \
  -H "Content-Type: application/json" \
  -d '{ "text": "harbor", "type": "Video" }'

Upload a file#

Files go straight to storage on a signed form, so an upload never passes through the API.

  1. Ask for a form

    POST/generate-file-urls

    typestringrequired
    The kind of file, like Video, Audio or Image.
    fileNamestringrequired
    The name it shows under.
    fileSizeintegerrequired
    Its exact size in bytes, up to 2 TB.
    objectKeystringrequired
    Where it is stored: users/{userId}/…
    mimeTypestring
    Its content type.

    You get an uploadUrl and an uploadForm. The form lasts 2 days.

  2. Send the file

    POST the file to uploadUrl as multipart/form-data, with every uploadForm field before it, unchanged.

  3. Record it

    POST/insert-file

    Send the same fields with isPublic: false and creator: { id: userId }. The service reads the stored size back, and turns the file down if it differs from fileSize. You get the new file's id.

Large files#

Above 64 MiB, send a file in parts instead, many at once. If an upload stops, start it again with the same objectKey and only the missing parts go up.

CallDoes
/create-multipart-uploadOpens the upload, or picks up the one already open under that key.
/sign-upload-partsGives an upload URL for each part you ask for.
/complete-multipart-uploadJoins the parts into the file.
/insert-fileRecords it, as for any upload.

Share and download#

/generate-download-url gives a link to any of your files that lasts 6 hours. /toggle-file-access makes a file public, and its link then stays up for good, played from the closest region.

Endpoints#

Every route is a POST to https://fffs.freakingfast.io with a JSON body. The OpenAPI spec has the full request and response for each.

Upload#

RouteDoes
/generate-file-urlsA signed form to upload a new file with.
/insert-fileRecord an uploaded file on the account.
/create-multipart-uploadStart an upload in parts, or resume the one open under this key.
/sign-upload-partsUpload URLs for parts of an open upload.
/complete-multipart-uploadJoin the parts into the finished file.
/abort-multipart-uploadThrow away an open upload and its parts.
/import-from-urlBring in a file from a link, fetched by the service.

Find and read#

RouteDoes
/select-user-filesEvery file you made.
/search-filesFind files by words, type, tag, folder, date, length, size, tempo, key or place.
/read-fileWhat is in a file, for a model: an image, a frame, a PDF’s or text file’s text.
/generate-download-urlA link to a file that lasts 6 hours.
/get-user-storage-usageBytes and files by bucket and kind.

Organize#

RouteDoes
/tag-filesTag files by name, making new tags as needed.
/update-file-tagsAdd one tag to files, or take it off.
/move-filesPut files in a folder, by path or id.
/update-file-descriptionSet a file’s description.
/toggle-file-accessMake a file public or private.
/select-collectionsYour folders, playlists, galleries and tags.

Playlists and galleries#

RouteDoes
/create-playlistA playlist of audio and video, in order.
/add-to-playlistAdd to the end of a playlist.
/reorder-playlistPut a playlist in a new order.
/create-galleryA gallery of images, in order.
/add-to-galleryAdd to the end of a gallery.
/reorder-galleryPut a gallery in a new order, and choose what goes up front.
/set-coverPut an image on a track or playlist as its art.
/set-video-thumbnailSet a video’s poster from a frame or an image.
/create-archive-requestA ZIP of files, a gallery or a playlist.

Requests and reviews#

RouteDoes
/create-file-requestA link anyone can send files to.
/select-file-requestsYour requests, and what arrived on each.
/set-file-request-openClose a request, or open it again.
/create-file-reviewA link to watch a video or track and leave notes on it.
/select-file-reviewsYour reviews, each with its notes as an edit list.
/reply-to-review-noteAnswer a note.
/set-review-note-resolvedMark a note dealt with, or not.

Activity#

RouteDoes
/select-file-viewsHow often other people opened your files, and who.
/select-drive-eventsWhat happened in your drive after a point, oldest first.

Images#

RouteDoes
/generate-imageStart an image from a prompt, on your plan.
/select-generationsHow your generations are going, and what they made.

Trash#

RouteDoes
/trash-filesMove files to the trash.
/restore-filesBring files back.
/select-trashed-filesWhat is in the trash.
/purge-trashed-filesEmpty the trash, for good.
/delete-filesDelete files and what is stored for them, for good.

Errors#

Errors come back with a sentence for people and a code for code. retryable says whether trying again could work, which the status alone doesn't tell you.

400
{
  "error": "A fileSize is required",
  "code": "missing_field",
  "field": "fileSize",
  "retryable": false
}
StatusMeans
400Something in the request is missing or wrong. field names it.
401No session, or one that has expired. Trade the token again.
403Signed in, but not allowed, or the account has no plan.
404Nothing of yours has that id.
500Something went wrong on our side. retryable is true.