The FerrFlow API exposes a small set of hosted HTTP endpoints under https://api.ferrlabs.com/v1/ferrflow/*. They are backed by the same FerrFlow core the CLI runs, so validate and preview return results identical to ferrflow validate and ferrflow check — no second implementation to drift.
Every endpoint is public (no authentication) and safe to call from CI, editors, or a browser. The machine-readable contract is served at /v1/ferrflow/openapi.json (OpenAPI 3.1).
GET /v1/ferrflow/health
Liveness and version probe. Powers status dashboards.
{ "status": "ok", "service": "ferrflow-api", "version": "10.17.0", "time": "2026-07-21T15:00:00Z" }
GET /v1/ferrflow/schema
Returns the config JSON Schema (Content-Type: application/schema+json), served from the schema bundled in the FerrFlow release — the same bytes the CLI validates against. Sends a strong ETag and Cache-Control, so point your editor's $schema here:
{ "$schema": "https://api.ferrlabs.com/v1/ferrflow/schema" }
GET /v1/ferrflow/schema/v{major} returns the schema frozen at a CLI major (e.g. /schema/v5). Only the current major is served today; older majors return 404 until per-major snapshots land.
GET /v1/ferrflow/latest
Resolves the latest FerrFlow release from GitHub, cached server-side. Pass platform to get a single asset:
curl "https://api.ferrlabs.com/v1/ferrflow/latest?platform=linux-x64"
{
"version": "5.45.0",
"tag": "v5.45.0",
"platform": "linux-x64",
"download_url": "https://github.com/FerrLabs/FerrFlow/releases/download/v5.45.0/ferrflow-linux-x64.tar.gz",
"signature_url": "https://github.com/FerrLabs/FerrFlow/releases/download/v5.45.0/ferrflow-linux-x64.tar.gz.sig",
"cert_url": "https://github.com/FerrLabs/FerrFlow/releases/download/v5.45.0/ferrflow-linux-x64.tar.gz.crt",
"published_at": "2026-07-21T13:24:24Z"
}
Releases are signed with Sigstore — verify the .sig + .crt rather than a checksum. Without platform, the response lists assets for every platform. Valid platforms: linux-x64, linux-arm64, linux-arm, darwin-x64, darwin-arm64, win32-x64, win32-arm64.
POST /v1/ferrflow/validate
Validates a config without a repo — you send the config text and, optionally, the contents of the versioned files it references so the file-existence and version-consistency checks run. The result is identical to ferrflow validate --json.
curl -X POST https://api.ferrlabs.com/v1/ferrflow/validate \
-H 'content-type: application/json' \
-d '{
"config": "{\"package\":[{\"name\":\"app\",\"path\":\".\",\"versionedFiles\":[{\"path\":\"package.json\",\"format\":\"json\"}]}]}",
"files": { "package.json": "{\"version\":\"1.0.0\"}" }
}'
{
"valid": true,
"config_file": null,
"package_count": 1,
"errors": [],
"warnings": [],
"suggestions": []
}
An invalid config is still a successful validation: the response is 200 with "valid": false and the offending entries. Only a malformed request body returns 400. The optional format field (json | json5 | toml) skips format inference.
POST /v1/ferrflow/preview
Computes the version bumps and changelog for an explicit list of commits — the same logic as ferrflow check, as a service. No repo access; you pass the commits.
curl -X POST https://api.ferrlabs.com/v1/ferrflow/preview \
-H 'content-type: application/json' \
-d '{
"config": "{\"package\":[{\"name\":\"api\",\"path\":\".\"}]}",
"commits": [{ "message": "feat(api): add endpoint", "hash": "a1b2" }],
"current_versions": { "api": "1.2.3" }
}'
{
"packages": [
{
"name": "api",
"current": "1.2.3",
"next": "1.3.0",
"bump": "minor",
"commits": [{ "hash": "a1b2", "type": "feat", "scope": "api", "breaking": false }],
"changelog": "### Features\n- ..."
}
]
}
In a monorepo config, each commit is assigned to a package when its files fall under that package's path. Packages with no releasable commit are omitted.