/

latester/api reference

what it's for

a read-only JSON API exposing the latest stable versions tracked by latester. designed to be passed to an AI assistant at the start of a session — it can then suggest up-to-date versions for Dockerfiles, CI configs, and similar.

endpoints

  • GET /api/v1/schema — machine-readable route index (methods, params, error codes, tracked IDs) in a single JSON call, meant for AI agents/scripts that don't want to parse this page
  • GET /api/v1/versions — full list of tracked versions
  • GET /api/v1/versions/{id} — single entry by ID
  • GET /api/v1/dockerhub/{name} — on-demand lookup for any Docker Hub image, not limited to the tracked list. Query params: owner, filter (glob), name_filter (Docker Hub-side substring), even_minor (true/false)
  • GET /api/v1/dockerhub/popular — most-searched images via the endpoint above
  • GET /api/v1/github/{owner}/{repo} — on-demand lookup of the highest stable release of any GitHub repository. Query param: filter (glob against the release tag, e.g. v2.*)

data is sourced from GitHub Releases, Docker Hub, go.dev, nodejs.org, npm, Maven Central and services.gradle.org. may be up to 24h old.

any request under /api/ that doesn't match a known route also returns JSON — 404 with {"error":"unknown endpoint"} — instead of the HTML 404 page, so a wrong URL form is distinguishable from a valid route with a nonexistent ID ({"error":"not found"}).

some images (nginx being the canonical example) mark unstable "mainline" releases with an odd minor version instead of a prerelease suffix (e.g. 1.31.x is mainline, 1.30.x is stable) — plain version sorting alone can't tell the two apart. Pass ?even_minor=true for those images to only match even-minor tags.

/api/v1/dockerhub/{name} returns 404 (not 502) when the image doesn't exist on Docker Hub or no tag matches your filter/name_filter — a 502 means latester itself failed to reach Docker Hub.

GET /api/v1/github/{owner}/{repo}

highest stable release among the repository's 100 most recent GitHub releases — drafts, releases flagged as prerelease and tags like -rc1/-beta are skipped. ranked by version, not by date: GitHub's own "latest release" is simply the most recently published one, so a project patching an older branch (e.g. traefik shipping v2.11.x after v3.7.x) would otherwise report the older line.

GET /api/v1/github/k3s-io/k3s

{
  "id":             "adhoc-gh-k3s-io~k3s",
  "owner":          "k3s-io",
  "name":           "k3s",
  "version":        "v1.37.1+k3s1",
  "arch":           "",
  "source":         "github",
  "updatedAgo":     "16d ago",
  "freshnessClass": "age-stale",
  "publishedAt":    "2026-09-30T16:10:38Z",
  "url":            "https://github.com/k3s-io/k3s/releases/tag/v1.37.1%2Bk3s1"
}
  • ?filter=v2.* — follow one branch (filepath.Match glob against the tag)
  • ?filter=release-* — required for tags with a text prefix (release-1.26.1, or kube-prometheus-stack-92.10.1 in a repo publishing several charts): the literal part of the filter is stripped before the version is read
  • 400 — invalid owner/repo (letters, digits, _ . -, max 100 chars, no ..) or malformed filter
  • 404 — repository doesn't exist, or no stable release matches among the 100 most recent (repos publishing git tags without GitHub Releases also land here)
  • 429 — rate limit exceeded (20 req/min/IP)
  • 502 — latester failed to reach GitHub

MCP server

the same lookups are also exposed as typed MCP tools over Streamable HTTP — for AI agents that would otherwise reach for a generic fetch-and-summarize tool, which can silently drop a field along the way. read-only, same public/no-auth posture as the JSON API above.

claude mcp add --transport http latester https://latester.euflow.fr/mcp
  • list_tracked_versions — equivalent to GET /api/v1/versions
  • get_version(id) — equivalent to GET /api/v1/versions/{id}
  • lookup_dockerhub(name, owner?, filter?, name_filter?, even_minor?) — equivalent to GET /api/v1/dockerhub/{name}
  • lookup_github(owner, repo, filter?) — equivalent to GET /api/v1/github/{owner}/{repo}

GET /api/v1/versions

{
  "generated_at": "2026-05-21T10:30:00Z",
  "note": "Stable release versions sourced from official upstreams (GitHub, Docker Hub, go.dev). May be up to 24h old.",
  "versions": [
    {
      "id":             "php",
      "owner":          "library",
      "name":           "php-fpm",
      "version":        "8.4.7-fpm",
      "arch":           "",
      "source":         "dockerhub",
      "updatedAgo":     "2d ago",
      "freshnessClass": "age-stale",
      "url":            "https://hub.docker.com/_/php/tags"
    },
    {
      "id":             "golang",
      "owner":          "golang",
      "name":           "go",
      "version":        "go1.24.3",
      "arch":           "linux/amd64",
      "source":         "godev",
      "updatedAgo":     "5d ago",
      "freshnessClass": "age-stale",
      "url":            "https://go.dev/dl/go1.24.3.linux-amd64.tar.gz"
    },
    {
      "id":             "node-alpine",
      "owner":          "library",
      "name":           "node-alpine (lts)",
      "version":        "24-alpine3.24",
      "pinnedVersion":  "24.18.0-alpine3.24",
      "arch":           "",
      "source":         "dockerhub",
      "updatedAgo":     "2d ago",
      "freshnessClass": "age-stale",
      "url":            "https://hub.docker.com/_/node/tags?name=24-alpine"
    }
  ]
}

pinnedVersion is present only when version is itself a floating "line" tag (e.g. Docker Hub's 24-alpine3.24, re-pointed to a new patch on every release) — it's the fully pinned tag sharing the same image, e.g. 24.18.0-alpine3.24. Use pinnedVersion over version when writing a Dockerfile FROM line.

publishedAt (RFC 3339) is present when the source provides a date: release date for GitHub, npm, Maven Central and Gradle, day-only for nodejs.org, and the tag's last push for Docker Hub — which moves every time a floating tag is re-pushed, so it's not a release date there.

GET /api/v1/versions/{id}

returns a single entry. id matches the id field in the list above.

{
  "id":             "traefik",
  "owner":          "traefik",
  "name":           "traefik",
  "version":        "v3.4.1",
  "arch":           "linux/amd64",
  "source":         "github",
  "updatedAgo":     "3d ago",
  "freshnessClass": "age-stale",
  "url":            "https://github.com/traefik/traefik/releases/download/v3.4.1/traefik_v3.4.1_linux_amd64.tar.gz"
}

returns 404 with {"error":"not found"} if the ID doesn't exist.

available IDs

  • woodpecker-agent — Woodpecker CI agent
  • woodpecker-server — Woodpecker CI server
  • opentofu — OpenTofu
  • gitea — Gitea
  • traefik — Traefik
  • golang — Go (go.dev official release)
  • golang-alpine — Go Docker image (Alpine)
  • alpine — Alpine Linux Docker image
  • php — PHP-FPM Docker image
  • node-lts — Node.js latest LTS (nodejs.org)
  • node-alpine — Node.js LTS Docker image (Alpine)
  • postgres-alpine — PostgreSQL Docker image (Alpine)
  • nginx-alpine — nginx Docker image (Alpine, stable line only — even-minor filter excludes mainline)
  • maven — Apache Maven (Maven Central)
  • gradle — Gradle (services.gradle.org)
  • spring-boot — Spring Boot (Maven Central)
  • junit — JUnit 5 / Jupiter (Maven Central)
  • angular — Angular (npm)
  • jest — Jest (npm)
  • playwright — Playwright (npm)
  • cypress — Cypress (npm)
  • sonarqube — SonarQube Community Docker image
← back to tracker