Clone
1
Floatplane API
claude edited this page 2026-10-25 09:38:51 +01:00

Floatplane API (unofficial) — what the plugin uses

Condensed from doc/floatplane-api-notes.md and doc/research/floatplane-api-research.md in the main repo. Verified with plain curl on 2026-10-25 (custom User-Agent, no cookie unless stated). Base URL https://www.floatplane.com.

Endpoint Notes
GET /api/v3/creator/named?creatorURL[0]=<urlname> → [Creator] incl. channels[], liveStream, subscriptionPlans
GET /api/v3/creator/channels/list?ids[0]=<creatorId> → [Channel] (id, creator, title, urlname, order, icon, cover, card)
GET /api/v3/content/creator?id=<creatorId>&limit=20&fetchAfter=<offset> post listing, newest first. Filters: channel=<channelId>, search=<text> (title/body), hasVideo=true (also hasAudio/hasPicture/hasText, mutually exclusive), tags[0]=…, fromDate/toDate (ISO 8601), fromDuration/toDuration (seconds), `sort=ASC
GET /api/v3/content/tags?creatorIds[0]=<creatorId> → { "<tag>": count, … }
https://pbs.floatplane.com/... thumbnails / icons / covers / timeline sprites; childImages[] carry _WxH variants
Endpoint Notes
GET /api/v3/user/self cookie probe → {id, username, email, profileImage}
GET /api/v3/user/subscriptions?active=true → [{plan{id,title,price}, creator:<creatorId>, startDate, endDate}]
GET /api/v3/creator/info?id= · GET /api/v3/creator/list?ids[0]= creator details by id
POST /api/v3/content/creator/list {ids:[…], limit} multi-creator feed with lastElements cursors
GET /api/v3/content/post?id=<postId> full post with videoAttachments[] objects (id, title, duration, levels[], textTracks[]) and attachmentOrder
GET /api/v3/content/video?id=<videoId> video details, progress (resume seconds), timelineSprite
GET /api/v3/delivery/info?scenario=onDemand|download|live&entityId=<videoId> groups[].origins[].url + variants[]{name:"1080-avc1", label, url (+JWT token, 6 h), enabled, hidden, meta{video{codec,width,height,fps,bitrate}, audio{…}, common.access.deniedReason}}. Rate-limited ≈2/min.
GET /api/video/watchKey?token=… HLS AES-128 key (16 bytes) — the only playback request that needs the cookie
GET /api/v3/content/progress?ids[0]=&contentType=blogPost · POST /api/v3/content/progress {id, contentType:"video", progress:<s>} watch progress (read = percent, write = seconds)

Auth facts

  • POST /api/v3/auth/login {username,password,captchaToken} → invalidCaptchaTokenError without a Cloudflare Turnstile token, for every User-Agent tested (browser, Hydravion, Wasserflug/CFNetwork, Android, okhttp).
  • OAuth2/OIDC: https://auth.floatplane.com/realms/floatplane/.well-known/openid-configuration (device-code grant, DPoP supported). Third-party clients (Hydravion, Wasserflug, floatplane-downloader, Floaty, FloatNative) have Floatplane-registered client ids; an unregistered id gets invalid_client. Access token 30 min, refresh token 90 days sliding (measured by the community canary).
  • Session cookie lifetime: not documented; the plugin reports invalid and logs a warning when Floatplane rejects it.

Playback (VOD)

origin = groups[0].origins[0].url                       e.g. https://cdn-vod-drm2.floatplane.com
playlist = origin + variant.url                          /Videos/<videoId>/1080.mp4/chunk.m3u8?token=<JWT>
chunk.m3u8:  #EXT-X-KEY:METHOD=AES-128,URI="https://www.floatplane.com/api/video/watchKey?token=…"   ← needs cookie
             <base64json>.ts?token=<JWT>                                                             ← token only, CORS *

Variants above the account's tier come back enabled:false, url:"" with meta.common.access.deniedReason = isMissingPermission. Subtitles: video.textTracks[].src is an S3-presigned VTT URL valid 15 minutes.

Etiquette

Unique User-Agent (Jellyfin-Floatplane/<version> (+repo url)), honour 429/Retry-After, cache delivery/info per video for the token lifetime, personal use with your own subscription.