docs/Reference/API reference

API reference

The Flareo v1 API is REST-ish, accepts and returns JSON, and requires no authentication for read endpoints. The CLI consumes the same API documented here. Full OpenAPI 3.1 spec lives at flareo.app/openapi.json.

Base URL

https://flareo.app

All endpoints are under /api/v1/.

Authentication

Two accepted forms:

  • Session cookie from the web app (NextAuth session). Used by the in-browser tools.
  • API key as a Bearer token: Authorization: Bearer fla_<hex>. Used by the CLI and scripts.

Obtain an API key by running flareo login (see CLI reference) or via the in-app settings page at /app/settings/api-keys.

Unauthenticated requests are allowed on all read endpoints with stricter rate limits.

Rate limits

Every response includes X-RateLimit-Limit and X-RateLimit-Remaining. Buckets:

EndpointUnauthenticatedAuthenticated
/api/v1/verify60/hour/IP600/hour/user
/api/v1/modules300/hour (either)300/hour (either)
/api/v1/whoami120/hour/IP120/hour/user

Exceeded limits return 429 with Retry-After in seconds.

Endpoints

POST /api/v1/verify

Resolves an image reference to a digest and checks for a Sigstore signature. See verify for the semantics.

Request:

{ "imageRef": "public.ecr.aws/flareo/vaultwarden:latest" }

Response (200):

{
  "status": "verified",
  "imageRef": "public.ecr.aws/flareo/vaultwarden:latest",
  "resolvedDigest": "sha256:abc...",
  "signerIdentity": "https://github.com/Yolo1105/flareo/...",
  "signerIssuer": "https://token.actions.githubusercontent.com",
  "rekorLogIndex": "12345678",
  "rekorUrl": "https://search.sigstore.dev/?logIndex=12345678",
  "integratedAt": "2026-04-23T00:14:00Z",
  "flareoModule": {
    "slug": "vaultwarden",
    "name": "Vaultwarden",
    "version": "1.30.3",
    "trust": 94,
    "cves": { "critical": 0, "high": 0, "medium": 2, "low": 5 },
    "sbomUrl": "https://...",
    "scanUrl": "https://..."
  },
  "errorMessage": null
}

status is one of verified, signed, unsigned, invalid, error.

GET /api/v1/modules

List modules. Pagination is cursor-based.

Query parameters:

  • q (optional) — text search across slug, name, description, tags
  • category (optional) — filter by category
  • limit (optional, default 50, max 100)
  • cursor (optional) — slug of the last item from prior page

Response (200):

{
  "modules": [ { "slug": "vaultwarden", ... } ],
  "nextCursor": "uptime-kuma"
}

GET /api/v1/modules/{slug}

Full detail for one module.

Response (200): module with full fields including trustBreakdown, sbomUrl, scanUrl, rekorIndex, signerIdentity.

404 if slug not found or visibility is private.

GET /api/v1/modules/by-digest/{digest}

Reverse lookup. Used by the CLI to enrich Sigstore output when the digest is a Flareo module.

Path parameter: digest in sha256:<hex> form (URL-encode the colon as %3A or pass the raw colon; both work).

Response (200): module summary.

404 if the digest isn't in the catalog.

GET /api/v1/modules/{slug}/vex

OpenVEX 0.2.0 document for the module. Lists per-CVE annotations made by the reviewer team — not_affected, affected, fixed, under_investigation — with public impact statements.

Trivy, Grype, and Snyk all consume this format directly. Pointing your scanner at this URL while scanning a Flareo module will suppress findings the reviewer team has marked non-exploitable, leaving you with the residual real risk.

Response (200): OpenVEX 0.2.0 JSON. Cache-Control: public, max-age=300. ETag invalidates when statements change.

403 for private modules; 404 for unknown slugs.

GET /api/v1/modules/{slug}/policy

Catalog admission-policy verdict for the module. The active policy (CVE thresholds after VEX, signature/SBOM/Rekor presence, SLSA level, composite trust score) is evaluated against the module; this endpoint returns the cached verdict plus the per-rule breakdown plus the input snapshot the evaluator saw.

If no cached verdict exists yet (newly-published module), the endpoint evaluates inline and persists before returning.

Response (200):

{
  "moduleSlug": "vaultwarden",
  "verdict": "pass",
  "policyRevision": 7,
  "evaluatedAt": "2026-04-25T14:32:00Z",
  "summary": "Pass. 9 rules evaluated; all clear.",
  "results": [
    {
      "rule": { "kind": "threshold", "signal": "cve_critical_after_vex", "op": "<=", "value": 0, "severity": "fail", "rationale": "..." },
      "status": "pass"
    }
    // ...
  ],
  "input": {
    "cve_critical": 0,
    "cve_high": 1,
    "cve_critical_after_vex": 0,
    "cve_high_after_vex": 1,
    "slsa_level": 2,
    "trust_score": 88,
    "signature": true,
    "sbom": true,
    "rekor_entry": true,
    "slsa_attestation": true
  }
}

Cache-Control: public, max-age=300. ETag invalidates on policy revision change or verdict re-evaluation. Consumers can chain this into Kyverno admission via the apiCall context — see admission policies.

403 for private modules; 404 for unknown slugs.

GET /api/v1/modules/{slug}/takeaway

Single canonical pointer for "everything you need to verify and run this module." Returns the pinned-by-digest image ref, the verify command (flareo verify ... and cosign verify ...), the pull command, the SBOM URL, the Rekor entry, the policy verdict URL, and a one-line decision summary.

Designed for CLI consumption — flareo pull uses it to resolve "give me everything for X" in one round trip, and copy-paste blocks on the website are generated from it.

Response (200): takeaway JSON. 404 for unknown slugs.

POST /api/v1/submissions

Submit a module for review. Accepts a JSON manifest (matching the shape in flareo.json) and optionally a Dockerfile body. Auth required.

Request body:

{
  "slug": "my-module",
  "name": "My Module",
  "version": "1.2.3",
  "category": "productivity",
  "license": "MIT",
  "upstreamUrl": "https://github.com/me/my-module",
  "contactEmail": "me@example.com",
  "description": "Short blurb",
  "dockerfile": "FROM alpine:3.19\n..."
}

If dockerfile is omitted and the request comes via flareo publish, the worker will detect language signals and attempt a Cloud Native Buildpacks build.

Response (202):

{ "submissionId": "sub_abc...", "status": "pending", "queuePositionEstimate": 4 }

429 if the user has hit their submission quota (Retry-After header included). The CLI's retry helper handles this transparently.

GET /api/v1/whoami

Authenticated user info. Accepts either session cookie or Bearer token.

Response (200):

{
  "id": "usr_abc...",
  "name": "Octocat",
  "email": "oct@example.com",
  "role": "user",
  "authSource": "apikey",
  "apiKeyLabel": "cli / my-laptop"
}

401 if unauthenticated.

GET /api/v1/stats

Aggregate catalog stats used by the landing page.

Response (200):

{
  "moduleCount": 12,
  "verifiedCount": 11,
  "builds7d": 84,
  "scanPassPct": 92,
  "openCves": 23,
  "lastRebuildAt": "2026-04-23T00:14:00Z"
}

Cached at the edge for 60 seconds.

GET /api/v1/health

Liveness check. Returns 200 when the app and database are reachable, 503 otherwise. Used by Instatus for uptime monitoring.

Error envelope

Every 4xx/5xx response has this shape:

{
  "error": {
    "code": "rate_limited",
    "message": "too many verify requests, try again shortly"
  }
}

code is stable; message is a human-readable string and may change.

Next steps