The public manifest
Every i3deploy project that publishes releases gets a public, unauthenticated JSON feed — one file per project, readable directly from a browser or a static site. Read this and you never depend on our server's uptime: the feed is a static object on Google Cloud Storage, it works even while the API is scaled to zero, and there's no API key, no CORS preflight dance, and no rate limit to worry about.
Location
https://storage.googleapis.com/i3deploy-public/<org-slug>/projects/<project-slug>/releases.json
One file per project, generated automatically every time a release for that project is
created, updated, or (un)published. The URL is stable from the moment the project exists —
even a project with zero published releases returns {"releases": []} rather than a 404, so
you can point a consumer at it before you've shipped anything.
What's in it — and what isn't
This feed is a product changelog, not an infrastructure dashboard. It lists published
ProjectRelease rows only — releases with published: true (the default) appear in the feed;
set published: false to keep a release staged before it goes live (see Cutting releases). There's no commit_sha, no
per-environment deploy state, and no technical changelog — just the user-facing version, name,
date, and Markdown notes.
That's a deliberate contrast with i3deploy's internal manifest (schema 2.0, private bucket),
which does track live deploy state per environment — current_version there means "the
release of the most recent deploy, by time, whose status is finished" (a rollback or hotfix
that redeploys an older version is reported correctly because it's ordered by time, not by
version number). That internal manifest isn't public. The releases.json feed documented here
is a separate, independently-versioned public contract — currently schema_version: "1.0" —
scoped to "what did we ship and when," not "what's running right now."
Sample (real, trimmed)
This is an actual, live response from https://storage.googleapis.com/i3deploy-public/i3/projects/i3deploy/releases.json,
trimmed to one release for brevity (the real file can hold up to 50):
{
"schema_version": "1.0",
"organization_slug": "i3",
"project": {
"slug": "i3deploy",
"display_name": "i3deploy"
},
"generated_at": "2026-07-18T16:04:59.594495+00:00",
"releases": [
{
"version": "1.1.0",
"name": "Public release feed (embeddable changelog) + public releases by default",
"released_at": "2026-07-12T17:45:11.629828+00:00",
"short_summary": "Public per-project \"what's new\" feed, CORS-enabled, consumable from the browser",
"changelog_markdown": "**Public what's-new feed.** Every project now has a public JSON URL with its own changelog (published releases only), readable directly by a frontend — no auth, no API calls — great for a \"what's new\" panel or toast, and it works even while the backend is scaled to zero. New releases are published automatically.",
"authored_by": "ai",
"service_versions": {
"i3deploy-back": "1.2.0"
}
}
]
}
Field reference
| Field | Meaning |
|---|---|
schema_version | This feed's own contract version ("1.0" today). Bumped independently of i3deploy's internal manifest schema — a version bump here is a breaking change for consumers. |
organization_slug / project | Which org and project this feed belongs to. |
generated_at | When this file was last regenerated (ISO 8601, UTC). |
releases[].version | The project release's version string. |
releases[].name | The release's headline/title. |
releases[].released_at | When the release was published (set the first time published flips to true; never overwritten after). |
releases[].short_summary | One line, good for a toast or badge. |
releases[].changelog_markdown | The full user-facing changelog, in Markdown. |
releases[].authored_by | "human" or "ai" — whether a person or Claude (via MCP) wrote the changelog. |
releases[].service_versions | Map of {service_slug: version} for the service releases bundled into this project release. |
Releases are ordered newest first, by released_at (falling back to version ordering for
releases published at the same time).
CORS: wildcard, but simple requests only
The bucket serves Access-Control-Allow-Origin: *, so any origin can read it. The catch:
GCS's CORS support only answers simple requests — a plain GET with no custom request
headers. Send a preflighted request (e.g. add a custom header like X-Requested-With) and the
OPTIONS preflight comes back with no CORS headers at all, so the browser blocks the actual
request. In practice this means: fetch it with a bare fetch(url) or curl, don't add
headers, and don't send credentials — you don't need any of that anyway, the feed is fully
public.
Next
- Open-source clients — a minimal consumer snippet, and where django-i3version fits in.
- Cutting releases — how a
ProjectReleasegets created and published in the first place.