API Changelog

History of changes to the FluffyStack API. New releases at the top.

API version ≠ site version

The version on this page tracks the FluffyStack API contract — endpoints, request shapes, response fields, auth model. It bumps when those change, not when the website does.

The website / app version (shown in the footer and the kiosk overlay) is on a separate track and changes more often as providers, services, and UI features ship. Think Android: the OS version & the API level move independently. Each is what it says on the tin.

API versioning policy

  • All current endpoints live under /v1/.
  • Backwards-compatible changes (new endpoints, new optional response fields) bump the minor version (1.x) and do NOT break existing consumers.
  • Breaking changes would ship under a new /v2/ prefix. The old /v1/ stays live indefinitely.
  • Bookmark this page to stay up to date with API changes.

v1.4.0

Service responses now carry a `lifecycle` block for preview / deprecated / sunset / retired services. Lets integrators flag dependencies on services the vendor has advised migrating off, without scraping the website.

Added

New `lifecycle` field on `Service` and `ServiceDetail` responses. Object with `status` (preview | deprecated | sunset | retired) plus optional `sunsetDate` (ISO YYYY-MM-DD), `gaTarget` (free-form GA window for previews), `successorSlug` (recommended replacement), `note` (vendor migration guidance), and `announcementUrl`. Active GA services omit the field — treat absence as `active`.

GET /v1/servicesGET /v1/services/:slugGET /v1/comparePOST /v1/export/markdownGET /v1/lists/:id
Added

OpenAPI spec gains a `ServiceLifecycle` schema and references it from `Service` + `ServiceDetail`. The /v1/openapi.json endpoint reflects this immediately.

Changed

D1 migration 0006_lifecycle.sql adds nullable lifecycle_* columns to the `services` table plus a partial index on lifecycle_status. Purely additive — no data loss; existing rows just have NULL lifecycle until the seed re-runs.

v1.3.0

Auth removed entirely. The API is now fully open — no key, no sign-in, no /account page. Mutation endpoints are rate-limited per IP instead of per API key.

Breaking

All authentication endpoints removed: GET /v1/auth/login/{github,google}, GET /v1/auth/callback/{github,google}, GET /v1/auth/me, POST /v1/auth/rotate, POST /v1/auth/revoke-link, POST /v1/auth/revoke. Any client code that signed in via OAuth or passed an X-API-Key header should drop the header — requests now succeed without it.

GET /v1/auth/login/githubGET /v1/auth/login/googleGET /v1/auth/callback/githubGET /v1/auth/callback/googleGET /v1/auth/mePOST /v1/auth/rotatePOST /v1/auth/revoke-linkPOST /v1/auth/revoke
Changed

Mutation endpoints (POST /v1/policies/*, POST /v1/lists, POST /v1/feedback, POST /v1/export/markdown) no longer require an API key. They're now rate-limited at 10 req/min per IP, down from the previous 30 req/min anonymous bucket — the per-key 120/min path is gone with auth, so the anonymous bucket needs to be tighter.

POST /v1/policies/aws-scpPOST /v1/policies/azure-policyPOST /v1/policies/gcp-org-policyPOST /v1/export/markdownPOST /v1/listsPOST /v1/feedback
Changed

Read endpoints unchanged: GETs are still open, still rate-limited only at the Cloudflare edge cache (5-min s-maxage). Cache hits never reach the Worker.

Changed

OpenAPI spec at /openapi.json updated: securitySchemes block removed, all 'security: [{ apiKey: [] }]' annotations dropped, UserProfile schema removed (was only used by /v1/auth/me). Existing client generators will produce simpler typed clients on regeneration.

Removed

GET /v1/feedback admin-list endpoint and GET /v1/analytics/usage admin endpoint both removed. Both depended on the users table for admin-email lookup. Replace with direct D1 queries — see docs/OPERATIONS.md.

Security

The OAuth-related secrets (GITHUB_CLIENT_SECRET, GOOGLE_CLIENT_SECRET, JWT_SECRET) are no longer needed and can be deleted from the Cloudflare secrets store. The associated GitHub and Google OAuth Apps can also be retired.

v1.2.0

Frontend export gating — all exports require sign-in (free account). Browsing, searching, comparing, and building service lists remain free. (Reverted in 1.3.0.)

Changed

All export actions on the website now require authentication. This mirrors the API gating: read-only catalogue access is open, but generating downloadable artefacts (SCP, Azure Policy, GCP Org Policy, Terraform, JSON, Markdown, migration target lists) requires a free account. The Service Builder shows a 'Sign in to export' prompt; the Migration Assistant shows a 'Sign in to export' button.

Changed

Account page 'What can you do with an API key?' section rewritten to 'What does signing in unlock?' — now accurately reflects both website and API gating.

v1.1.0

OAuth authentication, API key management, rate limiting, and account management.

Added

GitHub and Google OAuth sign-in. Users authenticate via OAuth and receive a persistent API key (flsk_* format) for all gated endpoints.

GET /v1/auth/login/githubGET /v1/auth/login/googleGET /v1/auth/callback/githubGET /v1/auth/callback/google
Added

Account management endpoints: view profile, reveal API key, rotate key.

GET /v1/auth/mePOST /v1/auth/rotate
Added

KV-based rate limiting. Anonymous: 30 req/min by IP. Authenticated: 120 req/min by API key. X-RateLimit-* response headers on every request.

Changed

POST endpoints (policies, export, lists) now require an API key via the X-API-Key header. GET endpoints remain open.

POST /v1/policies/aws-scpPOST /v1/policies/azure-policyPOST /v1/policies/gcp-org-policyPOST /v1/export/markdownPOST /v1/lists
Changed

CORS policy updated: authenticated requests (with API key) are allowed from any origin. Unauthenticated requests still restricted to fluffystack.dev and *.pages.dev.

Security

API keys are generated using nanoid (cryptographically random, 32 chars). JWT session tokens use HMAC-SHA256 with a 64-byte secret and 7-day expiry.

v1.0.0

Initial public API release. Read-only catalogue, policy generation, service list export, and shareable approved lists.

Added

Read-only catalogue endpoints for providers, categories, and services with pagination, search, and filtering.

GET /v1/providersGET /v1/categoriesGET /v1/servicesGET /v1/services/:slug
Added

Side-by-side comparison endpoint for up to 10 services.

GET /v1/compare?ids=a,b,c
Added

Policy generation: AWS SCP, Azure Policy, GCP Org Policy from an approved service list.

POST /v1/policies/aws-scpPOST /v1/policies/azure-policyPOST /v1/policies/gcp-org-policy
Added

Markdown export of approved service lists.

POST /v1/export/markdown
Added

Shareable approved service lists with 90-day auto-expiry.

POST /v1/listsGET /v1/lists/:id
Added

Health check and status endpoints with history tracking.

GET /v1/healthGET /v1/statusGET /v1/status/history
Fixed

AWS SCP: removed invalid _comment top-level key that caused AWS Organisations to reject the policy. Provenance now carried in the grammar-valid Id field.

Fixed

Azure Policy: removed policyType (can't be set), changed mode from "Indexed" to "all" (covers all resource types), removed empty parameters object.

Fixed

GCP Org Policy: removed invalid _comment top-level key that caused the Resource Manager API to reject the policy.

Missing something? Send us feedback