Discovery
API discovery
Cheap entry point listing families, schemas, versions, locales, and documentation links.
PUBLIC API
Interfaces ready — build what you need.
These public interfaces are intended for launchers, bots, mirrors, data tools, and DIY level clients. Clients should send an identifying User-Agent, respect Cache-Control and CDN-Cache-Control, avoid high-frequency polling, and handle failures through HTTP status codes; requests that do not follow the calling conventions may receive 404 or 429.
Command-line, script, official game-client, and server-side clients should send an identifying User-Agent; default tool UAs can receive a plain 404. View header policy
Most clients can start from the API index, then follow latest release and download entry points.
Step 1
Read the API index to confirm families, schemas, locales, and cache policies.
/api/v1/index.jsonStep 2
Request release detail and choose the platform key that matches the device.
/api/v1/releases/latest.jsonStep 3
Download from builds.*.url, then use builds.*.sha256 to confirm that the local file matches the published build.
/download/0.17q/windowsFilter by use case. Every card exposes a copyable concrete example URL.
Discovery
Cheap entry point listing families, schemas, versions, locales, and documentation links.
Release
Current version, platform builds, checksums, and changelog data.
Content
Encyclopedia entries, world regions, DidYouKnow trivia, and localized prose.
DIY
Public level library, detail JSON, GDF downloads, and submission entry point.
Search/news
Stable search corpus, announcement feed, and bot-friendly updates.
Downloads
Server-backed binary downloads with HEAD and Range support.
RSS
RSS 2.0 release feeds for feed readers.
GET · HEAD · DIY
Returns upload configuration that depends on request origin. This response is never publicly cached.
/api/v1/diy/runtime-config.jsonGET · Discovery
Machine-readable discovery entry point for launchers, bots, mirrors, and proxies, avoiding page scraping and hardcoded paths.
/api/v1/index.jsonGET · Release
Recommended release detail for launchers, mirrors, and bots. Includes every platform build.
/api/v1/releases/latest.jsonGET · Release
Updater manifest with backward-compatible top-level Windows x64 fields and a full builds matrix.
/api/v1/updates/latest.jsonGET · Release
Lists public releases with the current latest version and detail links.
/api/v1/releases.jsonGET · Release
Returns both localized changelogs in one payload for announcement bots and launcher news panes.
/api/v1/changelog/0.17q.jsonGET · Content
Localized Field Guide catalog with counts, entry links, portrait assets, and alternate locale links.
/api/v1/encyclopedia/en/index.jsonGET · Content
Localized detail for one plant, zombie, or boss, including mechanics, interactions, portrait, and navigation.
/api/v1/encyclopedia/en/peashooter.jsonGET · Content
Localized world codex. There is no separate region-detail JSON; full paragraphs are included in regions.
/api/v1/world/en/index.jsonGET · Content
Localized trivia and gameplay tips used by the homepage section and external tools.
/api/v1/did-you-know/en/index.jsonGET · HEAD · Content
Server-composed deterministic selection over the static catalog for clients that need one trivia item.
/api/v1/did-you-know/en/random.json?context=homeHero&entry=sunflower&seed=session-42GET · HEAD · DIY
Lists public DIY levels with search, filters, sorting, pagination, and local-favorite batch lookup.
/api/v1/diy/levels.json?sort=hot&tag=conveyor&limit=20GET · HEAD · DIY
Returns one public DIY level with metadata, parsed summary, download link, and client-facing level overview.
/api/v1/diy/levels/sample-level-id.jsonGET · HEAD · DIY
Downloads the GDF file for a public DIY level. HEAD can read filename, size, and validation metadata.
/api/v1/diy/levels/sample-level-id/download.gdfGET · HEAD · DIY
Returns the uploaded icon for a public DIY level. HEAD can read type, size, and dimension metadata.
/api/v1/diy/levels/sample-level-id/iconPOST · DIY
Submits a .gdf file with public metadata. A successful response means the file was received and includes an owner credential.
/api/v1/diy/levelsPOST · DIY
Exchanges the owner secret from an upload response for the website's HttpOnly owner session.
/api/v1/diy/levels/sample-level-id/owner/sessionPOST · DIY
Uses the owner secret from an upload response to inspect or manage the owner's submission; the website can use the same interface through an HttpOnly owner session.
/api/v1/diy/levels/sample-level-id/owner/statusPOST · DIY
Uses the owner secret from an upload response to inspect or manage the owner's submission; the website can use the same interface through an HttpOnly owner session.
/api/v1/diy/levels/sample-level-id/owner/editPOST · DIY
Uses the owner secret from an upload response to inspect or manage the owner's submission; the website can use the same interface through an HttpOnly owner session.
/api/v1/diy/levels/sample-level-id/owner/removePOST · DIY
Uses the owner secret from an upload response to inspect or manage the owner's submission; the website can use the same interface through an HttpOnly owner session.
/api/v1/diy/levels/sample-level-id/owner/updateGET · Search/news
Public wrapper for site-search documents. Do not depend on the root search-index files.
/api/v1/search/en.jsonGET · Search/news
Localized news feed for launchers, bots, and aggregators.
/api/v1/news/en.jsonGET · HEAD · Downloads
Download Windows and Android builds. Supports HEAD and single byte ranges; filenames are returned through Content-Disposition.
/download/0.17q/windowsGET · RSS
RSS 2.0 feed with one item per release, linking to the localized changelog.
/feed.xmlOpen a panel for field summaries, trimmed responses, and curl/server-side fetch examples with the standard User-Agent.
/api/v1/diy/runtime-config.json| Field | Type | Description |
|---|---|---|
| mode | string | disabled, local, or production. |
| turnstileSiteKey | string | null | Public Turnstile site key. |
| turnstileRequired | boolean | Whether this request must provide a Turnstile token. |
{
"schemaVersion": 1,
"kind": "diyRuntimeConfig",
"mode": "production",
"turnstileSiteKey": "0x4AAAAAADr9j5Z_Is8qzs20",
"turnstileRequired": true
} const response = await fetch("https://pvzvoyage.com/api/v1/diy/runtime-config.json");
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const config = await response.json(); /api/v1/index.json| Field | Type | Description |
|---|---|---|
| apiVersion | string | Current public API major version. |
| latestRelease | object | Latest public version, release date, and release/update/changelog links. |
| locales | object | Default locale, supported locales, and localized pages/APIs. |
| cache | object | Caching policy summary for API, download, and error responses. |
| families | array | Interface families, schemaVersion values, example paths, and documentation anchors. |
| documentation | object | Chinese/English API docs and llms.txt links. |
{
"schemaVersion": 1,
"kind": "apiIndex",
"apiVersion": "v1",
"latestRelease": {
"version": "0.17q",
"releasedAt": "2026-07-01",
"detail": {
"path": "/api/v1/releases/latest.json",
"url": "https://pvzvoyage.com/api/v1/releases/latest.json"
}
},
"locales": {
"default": "zh",
"supported": [
"zh",
"en"
]
},
"documentation": {
"en": {
"path": "/en/api-docs/",
"url": "https://pvzvoyage.com/en/api-docs/"
},
"zh": {
"path": "/zh/api-docs/",
"url": "https://pvzvoyage.com/zh/api-docs/"
},
"openapi": {
"path": "/api/openapi.json",
"url": "https://pvzvoyage.com/api/openapi.json"
}
},
"families": [
{
"key": "release",
"schemaVersions": [
1,
2
],
"endpoints": [
{
"id": "releases-latest",
"method": "GET",
"pathTemplate": "/api/v1/releases/latest.json",
"schemaVersion": 1
},
{
"id": "updates-latest",
"method": "GET",
"pathTemplate": "/api/v1/updates/latest.json",
"schemaVersion": 2
}
]
},
{
"key": "diy",
"schemaVersions": [
1
],
"endpoints": [
{
"id": "diy-levels-list",
"method": "GET · HEAD",
"pathTemplate": "/api/v1/diy/levels.json",
"schemaVersion": 1
},
{
"id": "diy-level-detail",
"method": "GET · HEAD",
"pathTemplate": "/api/v1/diy/levels/{public_id}.json",
"schemaVersion": 1
},
{
"id": "diy-level-icon",
"method": "GET · HEAD",
"pathTemplate": "/api/v1/diy/levels/{public_id}/icon",
"schemaVersion": 1
},
{
"id": "diy-runtime-config",
"method": "GET · HEAD",
"pathTemplate": "/api/v1/diy/runtime-config.json",
"schemaVersion": 1
},
{
"id": "diy-level-upload",
"method": "POST",
"pathTemplate": "/api/v1/diy/levels",
"schemaVersion": 1
},
{
"id": "diy-owner-session",
"method": "POST",
"pathTemplate": "/api/v1/diy/levels/{public_id}/owner/session",
"schemaVersion": 1
},
{
"id": "diy-owner-status",
"method": "POST",
"pathTemplate": "/api/v1/diy/levels/{public_id}/owner/status",
"schemaVersion": 1
},
{
"id": "diy-owner-edit",
"method": "POST",
"pathTemplate": "/api/v1/diy/levels/{public_id}/owner/edit",
"schemaVersion": 1
},
{
"id": "diy-owner-remove",
"method": "POST",
"pathTemplate": "/api/v1/diy/levels/{public_id}/owner/remove",
"schemaVersion": 1
},
{
"id": "diy-owner-update",
"method": "POST",
"pathTemplate": "/api/v1/diy/levels/{public_id}/owner/update",
"schemaVersion": 1
}
]
}
]
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/index.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/index.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const apiIndex = await response.json(); /api/v1/releases/latest.json| Field | Type | Description |
|---|---|---|
| version | string | Current release version. |
| platforms | string[] | Available platform keys. |
| builds | object | Build details keyed by platform. |
| builds.*.sha256 | string | SHA-256 digest for the binary. |
| feeds | object | English and Chinese RSS feed links. |
| urls.canonical | Link | Version-pinned detail URL. |
{
"schemaVersion": 1,
"kind": "release",
"version": "0.17q",
"releasedAt": "2026-07-01",
"latest": true,
"primaryPlatform": "windows",
"platforms": [
"windows",
"windows-zip",
"windows-x86",
"windows-x86-zip",
"android"
],
"urls": {
"self": {
"path": "/api/v1/releases/latest.json",
"url": "https://pvzvoyage.com/api/v1/releases/latest.json"
},
"canonical": {
"path": "/api/v1/releases/0.17q.json",
"url": "https://pvzvoyage.com/api/v1/releases/0.17q.json"
}
},
"builds": {
"windows": {
"platformKey": "windows",
"platform": {
"zh": "Windows 64 位(自解压)",
"en": "Windows x64 (self-extracting EXE)"
},
"path": "/download/0.17q/windows",
"url": "https://pvzvoyage.com/download/0.17q/windows",
"aliasPath": "/download/0.17q/windows.exe",
"filename": "PVZ-Voyage-0.17q-Windows-x64.exe",
"size": 151519712,
"sizeMiB": 144.5,
"sha256": "126f641200dba871499c929f20fe2bd92ddbc8f8b051a5f9809764d7a493af57",
"digest": {
"algorithm": "SHA-256",
"hex": "126f641200dba871499c929f20fe2bd92ddbc8f8b051a5f9809764d7a493af57"
},
"mime": "application/vnd.microsoft.portable-executable",
"extension": ".exe",
"minOs": {
"name": "Windows 7",
"build": 7600,
"label": "Windows 7+"
},
"note": "Example shows the Windows x64 build only; the real payload includes every platform."
}
}
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/releases/latest.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/releases/latest.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const release = await response.json(); /api/v1/updates/latest.json| Field | Type | Description |
|---|---|---|
| url | string | Primary build download URL kept for v1 consumers. |
| sha256 | string | Primary build checksum. |
| builds | object | All platform builds. |
| minOs | object | Minimum OS requirement. |
| changelog | object | Human changelog pages and JSON changelog link. |
{
"schemaVersion": 2,
"version": "0.17q",
"releasedAt": "2026-07-01",
"url": "https://pvzvoyage.com/download/0.17q/windows",
"sha256": "126f641200dba871499c929f20fe2bd92ddbc8f8b051a5f9809764d7a493af57",
"size": 151519712,
"filename": "PVZ-Voyage-0.17q-Windows-x64.exe",
"minOs": {
"name": "Windows 7",
"build": 7600
},
"builds": {
"windows": {
"url": "https://pvzvoyage.com/download/0.17q/windows",
"sha256": "126f641200dba871499c929f20fe2bd92ddbc8f8b051a5f9809764d7a493af57",
"size": 151519712,
"filename": "PVZ-Voyage-0.17q-Windows-x64.exe",
"minOs": {
"name": "Windows 7",
"build": 7600
}
}
}
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/updates/latest.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/updates/latest.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const manifest = await response.json(); /api/v1/releases.json| Field | Type | Description |
|---|---|---|
| latest | string | Latest version. |
| releases | array | Published releases. |
| releases[].detail | string | Version-pinned detail API. |
| releases[].latestDetail | string | null | Latest detail alias for the current version. |
{
"schemaVersion": 1,
"latest": "0.17q",
"releases": [
{
"version": "0.17q",
"releasedAt": "2026-07-01",
"url": "https://pvzvoyage.com/download/0.17q/windows",
"sha256": "126f641200dba871499c929f20fe2bd92ddbc8f8b051a5f9809764d7a493af57",
"detail": "https://pvzvoyage.com/api/v1/releases/0.17q.json",
"latestDetail": "https://pvzvoyage.com/api/v1/releases/latest.json"
}
]
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/releases.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/releases.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const index = await response.json(); /api/v1/changelog/{version}.json| Field | Type | Description |
|---|---|---|
| version | string | Version represented by the changelog. |
| locales.zh | object | Chinese changelog. |
| locales.en | object | English changelog. |
| sections | array | Headings, paragraphs, subsections, and items. |
{
"schemaVersion": 1,
"version": "0.17q",
"releasedAt": "2026-07-01",
"locales": {
"en": {
"title": "PVZ: Voyage 0.17q Changelog",
"sections": [
{
"title": "Highlights",
"paragraphs": [
"..."
],
"sections": []
}
]
}
}
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/changelog/0.17q.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/changelog/0.17q.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const changelog = await response.json(); /api/v1/encyclopedia/{locale}/index.json| Field | Type | Description |
|---|---|---|
| locale | 'zh' | 'en' | Current locale. |
| tabs | array | Plant, zombie, and boss categories with counts. |
| entries | array | Entry summaries, page URLs, API URLs, and portraits. |
| alternate | object | Other-locale page and API. |
{
"schemaVersion": 1,
"kind": "encyclopediaIndex",
"locale": "en",
"title": "Field Guide",
"counts": {
"total": 48,
"byKind": {
"plant": 22,
"zombie": 16,
"boss": 10
}
},
"entries": [
{
"slug": "peashooter",
"name": "Peashooter",
"kind": "plant",
"path": "/en/encyclopedia/peashooter/",
"api": {
"path": "/api/v1/encyclopedia/en/peashooter.json",
"url": "https://pvzvoyage.com/api/v1/encyclopedia/en/peashooter.json"
},
"portrait": {
"avif": {
"path": "/media/encyclopedia/peashooter.avif"
},
"width": 1200,
"height": 1185
}
}
]
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/encyclopedia/en/index.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/encyclopedia/en/index.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const fieldGuide = await response.json(); /api/v1/encyclopedia/{locale}/{slug}.json| Field | Type | Description |
|---|---|---|
| entry | object | Entry copy, role, abilities, and advanced mechanics. |
| portrait | object | AVIF/WebP/PNG portrait and dimensions. |
| navigation | object | Previous/next entry summaries. |
| alternate | object | null | Other-locale entry. |
{
"schemaVersion": 1,
"kind": "encyclopediaEntry",
"locale": "en",
"slug": "peashooter",
"entry": {
"slug": "peashooter",
"kind": "plant",
"name": "Peashooter",
"mechanics": {
"role": "Ranged attacker · Crossbreed base",
"abilities": [
"..."
]
},
"interactions": [
{
"target": "Wall-nut",
"targetSlug": "wall-nut",
"effect": "..."
}
]
},
"portrait": {
"png": {
"path": "/media/encyclopedia/peashooter.png"
},
"width": 1200,
"height": 1185
}
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/encyclopedia/en/peashooter.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/encyclopedia/en/peashooter.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const entry = await response.json(); /api/v1/world/{locale}/index.json| Field | Type | Description |
|---|---|---|
| regions | array | Region slug, number, title, summary, paragraphs, and visuals. |
| visual | object | Card/hero images and accent colors. |
| alternate | object | Other-locale world index. |
{
"schemaVersion": 1,
"kind": "worldIndex",
"locale": "en",
"count": 4,
"regions": [
{
"slug": "maple-falls",
"number": "I",
"title": "Maple Falls",
"summary": "...",
"path": "/en/world/maple-falls/",
"visual": {
"accent": "#8da66b",
"motif": "wind / lake / stairway"
}
}
]
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/world/en/index.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/world/en/index.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const world = await response.json(); /api/v1/did-you-know/{locale}/index.json| Field | Type | Description |
|---|---|---|
| counts | object | Total count and counts by trivia, tip, mechanic, and lore. |
| filters | object | Available contexts, kinds, spoiler levels, and tags. |
| selectionDefaults.homeHero | object | Default homepage selection rules. |
| items | array | Localized items with copy, source refs, tags, weight, and related Field Guide entries. |
| items[].sourceRefs | array | Local sources checked before publication. |
{
"schemaVersion": 1,
"kind": "didYouKnowIndex",
"locale": "en",
"counts": {
"total": 36,
"byKind": {
"trivia": 2,
"tip": 22,
"mechanic": 11,
"lore": 1
}
},
"selectionDefaults": {
"homeHero": {
"allowedSpoilerLevels": [
"none",
"mild",
"mechanics"
],
"preferredRelatedSlugs": [
"sunflower",
"peashooter"
],
"maxRecentIds": 12
}
},
"items": [
{
"id": "sunflower-match-inheritance",
"kind": "mechanic",
"text": "Sunflower matching is no longer directional, and CocoBottle Shine can pass its large-sun charge into the kept plant.",
"spoilerLevel": "mechanics",
"contexts": [
"homeHero",
"encyclopedia",
"api"
],
"relatedEntries": [
{
"slug": "sunflower",
"name": "Sunflower",
"path": "/en/encyclopedia/sunflower/"
}
]
}
]
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/did-you-know/en/index.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/did-you-know/en/index.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const didYouKnow = await response.json(); /api/v1/did-you-know/{locale}/random.json| Field | Type | Description |
|---|---|---|
| context | query | homeHero, encyclopedia, api, or any. |
| kind | query | Comma-separated trivia, tip, mechanic, or lore. |
| entry | query | Related Field Guide slug; preferred by default and required with strictEntry=1. |
| strictEntry | query | 0 or 1; when set to 1, entry is required and selection is limited to items related to that entry. |
| tags | query | Comma-separated URL-safe tags, at most 12; matches any supplied tag. |
| spoilerMax | query | Maximum spoiler level; defaults to mechanics for homeHero and lateGame otherwise. |
| exclude | query | Comma-separated item IDs; at most 20 are accepted. |
| seed | query | Up to 128 characters; when omitted, the current UTC hour bucket is used. |
| X-PVZV-DidYouKnow-Cache | response header | HIT or MISS, useful for verifying the random-selection cache. |
| selection | object | Seed, pool size, excluded count, and filters actually used. |
| item | object | Selected DidYouKnow item. |
{
"schemaVersion": 1,
"kind": "didYouKnowSelection",
"locale": "en",
"selection": {
"strategy": "weighted-stable-random",
"seed": "session-42",
"context": "homeHero",
"poolSize": 31,
"excludedCount": 0,
"filters": {
"entry": "sunflower",
"strictEntry": false,
"spoilerMax": "mechanics"
}
},
"item": {
"id": "sunflower-match-inheritance",
"kind": "mechanic",
"text": "Sunflower matching is no longer directional, and CocoBottle Shine can pass its large-sun charge into the kept plant.",
"cta": {
"path": "/en/encyclopedia/sunflower/",
"url": "https://pvzvoyage.com/en/encyclopedia/sunflower/"
}
}
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
"https://pvzvoyage.com/api/v1/did-you-know/en/random.json?context=homeHero&entry=sunflower&seed=session-42" // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/did-you-know/en/random.json?context=homeHero&entry=sunflower&seed=session-42", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const selection = await response.json(); /api/v1/diy/levels.json| Field | Type | Description |
|---|---|---|
| q · optional | query | Search public title, author, or description; up to 60 characters. |
| ids · optional | query | Comma-separated public level IDs, at most 50; useful for local favorite lookup. |
| version · optional | query | Exact game-version filter, such as 0.17q. |
| difficulty · optional | query | Display/design difficulty integer 0..9; this is an independent display scale, not the game environment difficulty. |
| difficultyMin / difficultyMax · optional | query | Display/design difficulty range, integer 0..9. |
| background · optional | query | Background ID. |
| wavesMin / wavesMax · optional | query | Max-wave range, 1..100. |
| subLevelsMin / subLevelsMax · optional | query | Sub-level count range, 1..8. |
| downloadsMin / downloadsMax · optional | query | Approximate download-count range, using non-negative integers. |
| tag · optional | query | Repeatable or comma-separated; multiple tags are matched together. |
| sort · optional | query | latest, hot, name, downloads, or difficulty; defaults to latest. |
| cursor · optional | query | Opaque pagination cursor returned by the previous page. |
| limit · optional | query | 1..50, default 20. |
| mode | string | Public enabled-state marker for this interface. |
| levels | array | Public level summaries. |
| levels[].titleZh | string | Chinese public title. |
| levels[].titleEn | string | English public title. |
| levels[].descriptionZh | string | Chinese public description. |
| levels[].descriptionEn | string | English public description. |
| levels[].icon | object | null | Public level icon link and image metadata; null when no icon was uploaded. |
| levels[].download | Link | GDF download link. |
| pagination.nextCursor | string | null | Cursor for the next page; null means there is no next page. |
| pagination.total | number | null | Total for the current filter set, null when unavailable. |
{
"schemaVersion": 1,
"kind": "diyLevelList",
"mode": "production",
"levels": [
{
"schemaVersion": 1,
"id": "sample-level-id",
"title": "Sample Conveyor Trial",
"description": "Short public description shown in the library.",
"titleZh": "传送带试炼",
"titleEn": "Sample Conveyor Trial",
"descriptionZh": "在关卡库中展示的中文简介。",
"descriptionEn": "Short public description shown in the library.",
"author": "Example Creator",
"gameVersion": "0.17q",
"difficulty": 3,
"way": 0,
"waves": 10,
"background": 1,
"subLevelCount": 1,
"modeTags": [
"conveyor"
],
"sizeBytes": 20480,
"sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"icon": {
"path": "/api/v1/diy/levels/sample-level-id/icon",
"url": "https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/icon",
"contentType": "image/png",
"width": 96,
"height": 96,
"sizeBytes": 8192,
"sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
},
"downloadCountApprox": 42,
"approvedAt": "2026-06-27T01:00:00.000Z",
"detail": {
"path": "/api/v1/diy/levels/sample-level-id.json",
"url": "https://pvzvoyage.com/api/v1/diy/levels/sample-level-id.json"
},
"download": {
"path": "/api/v1/diy/levels/sample-level-id/download.gdf",
"url": "https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/download.gdf"
}
}
],
"pagination": {
"nextCursor": "opaque-cursor",
"total": 128
}
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
"https://pvzvoyage.com/api/v1/diy/levels.json?sort=hot&tag=conveyor&limit=20" // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/diy/levels.json?sort=hot&tag=conveyor&limit=20", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const levels = await response.json(); /api/v1/diy/levels/{public_id}.json| Field | Type | Description |
|---|---|---|
| public_id | path | Public level ID. |
| level.id | string | Public level ID. |
| level.title | string | Compatibility public-title projection; localized clients should use titleZh/titleEn. |
| level.description | string | Compatibility public-description projection; localized clients should use descriptionZh/descriptionEn. |
| level.titleZh | string | Chinese public title. |
| level.titleEn | string | English public title. |
| level.descriptionZh | string | Chinese public description. |
| level.descriptionEn | string | English public description. |
| level.author | string | Author read from the GDF. |
| level.gameVersion | string | null | Game version declared by the GDF. |
| level.difficulty | number | null | Level display/design difficulty value; defaults to the GDF-parsed value and can be manually labeled at upload or in management. |
| level.environmentDifficulty | number | null | Game-internal environment difficulty, usually 0..4 with 5..7 recognized. |
| level.waves | number | null | Maximum wave count. |
| level.background | number | null | Background ID for the first sub-level. |
| level.subLevelCount | number | Number of sub-levels. |
| level.modeTags | string[] | Public mode tags. |
| level.sizeBytes | number | GDF file size. |
| level.sha256 | string | GDF file SHA-256. |
| level.icon | object | null | Level icon link and PNG/JPEG/WebP image metadata; null when no icon was uploaded. |
| level.downloadCountApprox | number | Approximate download count for display. |
| level.gdfName · optional | string | null | Name stored in the GDF. |
| level.gdfDescription · optional | string | null | Description stored in the GDF. |
| level.seed · optional | number | null | GDF random seed. |
| level.crcValid | boolean | GDF CRC validation result. |
| level.subLevels · optional | array | null | Multi-sub-level summary. |
| level.subLevels[].difficulty · optional | number | null | Display/design difficulty for that sub-level. |
| level.summaryJson | object | GDF information summary object extracted and normalized from the GDF JSON payload. It retains the name, author, version, difficulty, waves, background, sub-levels, and zombie overview; it is not the original level JSON that can be packed back into a .gdf file. |
{
"schemaVersion": 1,
"kind": "diyLevelDetail",
"mode": "production",
"level": {
"schemaVersion": 1,
"id": "sample-level-id",
"title": "Sample Conveyor Trial",
"description": "Short public description shown in the library.",
"titleZh": "传送带试炼",
"titleEn": "Sample Conveyor Trial",
"descriptionZh": "在关卡库中展示的中文简介。",
"descriptionEn": "Short public description shown in the library.",
"author": "Example Creator",
"gameVersion": "0.17q",
"difficulty": 3,
"environmentDifficulty": 2,
"way": 0,
"waves": 10,
"background": 1,
"subLevelCount": 2,
"modeTags": [
"conveyor"
],
"sizeBytes": 20480,
"sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"icon": {
"path": "/api/v1/diy/levels/sample-level-id/icon",
"url": "https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/icon",
"contentType": "image/png",
"width": 96,
"height": 96,
"sizeBytes": 8192,
"sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
},
"downloadCountApprox": 42,
"approvedAt": "2026-06-27T01:00:00.000Z",
"detail": {
"path": "/api/v1/diy/levels/sample-level-id.json",
"url": "https://pvzvoyage.com/api/v1/diy/levels/sample-level-id.json"
},
"download": {
"path": "/api/v1/diy/levels/sample-level-id/download.gdf",
"url": "https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/download.gdf"
},
"gdfName": "Sample Conveyor Trial",
"gdfDescription": "GDF-authored description if present.",
"seed": 123,
"crcValid": true,
"subLevels": [
{
"index": 0,
"difficulty": 2,
"waves": 8,
"background": 1,
"zombieSummary": [
"Zombie",
"ConeheadZombie"
]
},
{
"index": 1,
"difficulty": 3,
"waves": 10,
"background": 3,
"zombieSummary": [
"BucketheadZombie",
"FlagZombie"
]
}
],
"summaryJson": {
"gdf_name": "Sample Conveyor Trial",
"extracted_author": "Example Creator",
"gdf_description": "GDF-authored description if present.",
"game_version": "0.17q",
"difficulty": 3,
"environment_difficulty": 2,
"way": 0,
"waves": 10,
"waves_range": "8-10",
"background": 1,
"sub_level_count": 2,
"sub_levels": [
{
"index": 0,
"waves": 8,
"background": 1,
"difficulty": 2,
"zombie_summary": [
"Zombie",
"ConeheadZombie"
]
},
{
"index": 1,
"waves": 10,
"background": 3,
"difficulty": 3,
"zombie_summary": [
"BucketheadZombie",
"FlagZombie"
]
}
]
}
}
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/diy/levels/sample-level-id.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/diy/levels/sample-level-id.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const level = await response.json(); /api/v1/diy/levels/{public_id}/download.gdf| Field | Type | Description |
|---|---|---|
| public_id | path | Public level ID. |
| Content-Type | header | application/octet-stream. |
| Content-Disposition | header | Attachment filename, usually based on the public title. |
| Content-Length | header | GDF file size. |
| ETag | header | File identifier corresponding to sha256 in detail JSON. |
| Cache-Control | header | Cache policy for public versioned files. |
HTTP/2 200
content-type: application/octet-stream
content-disposition: attachment; filename="Sample Conveyor Trial.gdf"
content-length: 20480
etag: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
cache-control: public, max-age=300, stale-while-revalidate=300 curl -I \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/download.gdf curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
-o "Sample Conveyor Trial.gdf" \
https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/download.gdf /api/v1/diy/levels/{public_id}/icon| Field | Type | Description |
|---|---|---|
| public_id | path | Public level ID. |
| Content-Type | header | image/png, image/jpeg, or image/webp. |
| Content-Disposition | header | inline. |
| Content-Length | header | Icon file size. |
| ETag | header | Icon SHA-256 file identifier. |
| X-PVZV-DIY-Icon-Width | header | Icon width in pixels. |
| X-PVZV-DIY-Icon-Height | header | Icon height in pixels. |
| Cache-Control | header | Public icon cache policy. |
HTTP/2 200
content-type: image/png
content-disposition: inline
content-length: 8192
etag: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
x-pvzv-diy-icon-width: 96
x-pvzv-diy-icon-height: 96
cache-control: public, max-age=300 curl -I \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/icon curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
-o "sample-level-icon.png" \
https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/icon /api/v1/diy/levels| Field | Type | Description |
|---|---|---|
| file | multipart field | Required .gdf file, up to 256 KiB. |
| icon · optional | multipart field | Optional level icon. PNG, JPEG, or WebP only, up to 96 KiB, 32..512 px; the full multipart request must stay below 480 KiB. |
| titleZh · optional | multipart field | Chinese public title, 2..80 characters when provided. |
| titleEn · optional | multipart field | English public title, 2..80 characters when provided. |
| descriptionZh · optional | multipart field | Chinese public description, up to 1500 characters. |
| descriptionEn · optional | multipart field | English public description, up to 1500 characters. |
| modeTags · optional | multipart field | Comma-separated or repeated field, at most 5 controlled tags. |
| turnstileToken · optional | multipart field | Verification token supplied by the browser upload widget when needed. |
| status | string | pending after a successful submission. |
| level | object | New level ID, title, author, sha256, and submission time. |
| ownerCredential | object | Owner credential filename, text, and secret; returned once, so keep it safely. |
{
"schemaVersion": 1,
"status": "pending",
"level": {
"id": "sample-level-id",
"title": "Sample Conveyor Trial",
"author": "Example Creator",
"sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"createdAt": "2026-06-27T01:00:00.000Z"
},
"ownerCredential": {
"filename": "pvzvoyage-diy-sample-level-id-owner.txt",
"text": "PVZ: Voyage DIY owner credential\nLevel ID: sample-level-id\nSecret: example_owner_secret",
"secret": "example_owner_secret"
}
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
-F "file=@level.gdf;type=application/octet-stream" \
-F "icon=@icon.png;type=image/png" \
-F "titleZh=传送带试炼" \
-F "titleEn=Sample Conveyor Trial" \
-F "descriptionZh=中文公开简介。" \
-F "descriptionEn=Short public description." \
-F "modeTags=conveyor,puzzle" \
https://pvzvoyage.com/api/v1/diy/levels const formData = new FormData();
formData.set("file", file, file.name);
if (iconFile) formData.set("icon", iconFile, iconFile.name);
formData.set("titleZh", "传送带试炼");
formData.set("titleEn", "Sample Conveyor Trial");
formData.set("descriptionZh", "中文公开简介。");
formData.set("descriptionEn", "Short public description.");
formData.set("modeTags", "conveyor,puzzle");
if (turnstileToken) formData.set("turnstileToken", turnstileToken);
const response = await fetch("https://pvzvoyage.com/api/v1/diy/levels", {
method: "POST",
body: formData,
});
const result = await response.json();
if (!response.ok) {
throw new Error(result?.error?.message ?? "DIY upload failed");
} /api/v1/diy/levels/{public_id}/owner/session| Field | Type | Description |
|---|---|---|
| secret | string | Owner secret returned once at upload. |
{
"schemaVersion": 1,
"ok": true,
"expiresAt": "2026-06-27T02:00:00.000Z"
} const response = await fetch("https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/owner/session", {
method: "POST",
headers: { "Content-Type": "application/json", "X-PVZV-CSRF": "1" },
body: JSON.stringify({ secret: "<owner-secret>" }),
});
const result = await response.json(); /api/v1/diy/levels/{public_id}/owner/status| Field | Type | Description |
|---|---|---|
| Authorization · optional | header | Bearer owner secret; the website may use an owner session. |
| X-PVZV-CSRF · optional | header | Required only for the Cookie browser flow; not required for Bearer clients. |
| body · optional | application/json | Edit fields or an empty object. |
{
"schemaVersion": 1,
"level": {
"id": "sample-level-id",
"status": "pending"
}
} const response = await fetch("https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/owner/status", {
method: "POST",
headers: { Authorization: "Bearer <owner-secret>", "Content-Type": "application/json" },
body: JSON.stringify({}),
});
const result = await response.json(); /api/v1/diy/levels/{public_id}/owner/edit| Field | Type | Description |
|---|---|---|
| Authorization · optional | header | Bearer owner secret; the website may use an owner session. |
| X-PVZV-CSRF · optional | header | Required only for the Cookie browser flow; not required for Bearer clients. |
| body | application/json | Edit fields or an empty object. |
{
"schemaVersion": 1,
"ok": true,
"status": "updated"
} const response = await fetch("https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/owner/edit", {
method: "POST",
headers: { Authorization: "Bearer <owner-secret>", "Content-Type": "application/json" },
body: JSON.stringify({}),
});
const result = await response.json(); /api/v1/diy/levels/{public_id}/owner/remove| Field | Type | Description |
|---|---|---|
| Authorization · optional | header | Bearer owner secret; the website may use an owner session. |
| X-PVZV-CSRF · optional | header | Required only for the Cookie browser flow; not required for Bearer clients. |
| body · optional | application/json | Edit fields or an empty object. |
{
"schemaVersion": 1,
"ok": true,
"status": "removed"
} const response = await fetch("https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/owner/remove", {
method: "POST",
headers: { Authorization: "Bearer <owner-secret>", "Content-Type": "application/json" },
body: JSON.stringify({}),
});
const result = await response.json(); /api/v1/diy/levels/{public_id}/owner/update| Field | Type | Description |
|---|---|---|
| Authorization · optional | header | Bearer owner secret; the website may use an owner session. |
| X-PVZV-CSRF · optional | header | Required only for the Cookie browser flow; not required for Bearer clients. |
| body | multipart/form-data | Complete .gdf with optional metadata. |
{
"schemaVersion": 1,
"ok": true,
"status": "pending_update"
} const response = await fetch("https://pvzvoyage.com/api/v1/diy/levels/sample-level-id/owner/update", {
method: "POST",
headers: { Authorization: "Bearer <owner-secret>", "Content-Type": "application/json" },
body: JSON.stringify({}),
});
const result = await response.json(); /api/v1/search/{locale}.json| Field | Type | Description |
|---|---|---|
| documentCount | number | Number of documents. |
| source | object | Source file note for the internal search index. |
| documents | array | Normalized documents. |
| documents[].kind | string | nav, changelog, world, encyclopedia, mechanics, channel, faq, and more. |
{
"schemaVersion": 1,
"kind": "searchIndex",
"locale": "en",
"documentCount": 100,
"documents": [
{
"id": "encyclopedia:en:peashooter",
"kind": "encyclopedia",
"title": "Peashooter",
"subtitle": "Plant file · Owned by default",
"path": "/en/encyclopedia/peashooter/",
"url": "https://pvzvoyage.com/en/encyclopedia/peashooter/",
"aliases": [
"peashooter",
"Peashooter",
"plant"
]
}
]
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/search/en.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/search/en.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const searchIndex = await response.json(); /api/v1/news/{locale}.json| Field | Type | Description |
|---|---|---|
| latestVersion | string | Latest version. |
| links | object | Home, download, changelog, RSS, and release API links. |
| items | array | Announcement items. |
| items[].highlights | array | Structured highlights. |
{
"schemaVersion": 1,
"kind": "newsFeed",
"locale": "en",
"latestVersion": "0.17q",
"items": [
{
"id": "release-0.17q",
"kind": "release",
"version": "0.17q",
"title": "PVZ: Voyage 0.17q released",
"publishedAt": "2026-07-01",
"api": {
"path": "/api/v1/releases/0.17q.json",
"url": "https://pvzvoyage.com/api/v1/releases/0.17q.json"
}
}
]
} curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/api/v1/news/en.json // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/api/v1/news/en.json", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
if (!response.ok) {
throw new Error(`PVZ: Voyage API failed: ${response.status}`);
}
const news = await response.json(); /download/{version}/{platform}| Field | Type | Description |
|---|---|---|
| Content-Type | header | Build MIME type, such as application/zip or the APK MIME type. |
| Content-Disposition | header | Attachment filename. |
| Content-Length | header | Byte size of the full file or single-range response. |
| Accept-Ranges | header | Supports bytes. |
| Range | request header | Request a single byte range. |
| Retry-After | header | Returned on 429 responses. |
HTTP/2 200
content-type: application/vnd.microsoft.portable-executable
content-length: 151519712
content-disposition: attachment; filename="PVZ-Voyage-0.17q-Windows-x64.exe"
accept-ranges: bytes
cache-control: public, max-age=3600, s-maxage=86400, immutable curl -I \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/download/0.17q/windows curl -L \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
-H "Range: bytes=0-1048575" \
-o pvzvoyage.part \
https://pvzvoyage.com/download/0.17q/windows // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const head = await fetch("https://pvzvoyage.com/download/0.17q/windows", {
method: "HEAD",
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
const size = Number(head.headers.get("content-length") ?? 0);
const filename = head.headers.get("content-disposition"); /feed.xml| Field | Type | Description |
|---|---|---|
| channel | RSS | Release channel. |
| item | RSS | Release item. |
| link | RSS | Localized changelog link. |
| pubDate | RSS | Release date. |
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>PVZ: Voyage</title>
<item>
<title>PVZ: Voyage 0.17q released</title>
<link>https://pvzvoyage.com/en/version/0.17q/</link>
</item>
</channel>
</rss> curl -fsSL \
-A "PVZVoyage/0.17q (+https://pvzvoyage.com/)" \
https://pvzvoyage.com/feed.xml // Server-side fetch example. Browser fetch sends a browser User-Agent automatically.
const response = await fetch("https://pvzvoyage.com/feed.xml", {
headers: {
"User-Agent": "PVZVoyage/0.17q (+https://pvzvoyage.com/)",
},
});
const xml = await response.text(); Do not hardcode binary paths in clients. Read latest release detail first, then choose a platform from builds. Download routes support HEAD probes, GET downloads, and single-range resumes; invalid ranges return 416, and rate limiting returns 429 with Retry-After. After completion, use SHA-256 to check whether the local file matches the build published by this site; that check does not prove runtime compatibility, antivirus decisions, or game behavior.
Both are generated by the same static build pipeline, but they serve different consumers.
Use News JSON
Structured fields, CTAs, images, tags, and release API links are better for software.
Use RSS
RSS 2.0 is better for feed readers and generic subscription services.
Command-line, script, official game-client, and server-side clients should send a User-Agent that identifies the integration, for example: PVZVoyage/0.17q (+https://pvzvoyage.com/). If you maintain your own client, you may replace the product/version and support URL. Public read APIs support this shape and remain subject to rate limits and abuse controls; browser fetch uses the browser User-Agent automatically; requests with default tool UAs may receive a plain 404 instead of a JSON error.
JSON API responses are readable cross-origin with Access-Control-Allow-Origin: *. This means browsers may read the response; it does not mean a third-party page is endorsed by this site.
API JSON uses Cache-Control for short browser caching and CDN-Cache-Control for longer shared-cache intent; version-pinned release/changelog JSON is more cacheable than latest/update JSON. DidYouKnow random selections enter the shared cache under a normalized effective query. DIY public GDF/icon GET responses use short TTL caching, while HEAD requests do not fill the edge cache and binary downloads use immutable versioned-path caching. Clients should respect these headers and avoid replacing cache with high-frequency polling. On 429, read Retry-After before retrying.
Unknown .json paths usually return JSON 404, and bad parameters may return JSON 400. Download routes return 416 for invalid Range requests; requests sent too frequently return 429. Some requests that do not follow public calling conventions may receive a plain 404, and that response may not use the JSON error shape.
builds.*.sha256 is used to confirm that the completed local file matches the build published by this site. It does not prove that the file will run on every system, and it does not replace operating-system permissions, antivirus decisions, or your own source checks.
/api/v1 is the breaking-change compatibility boundary. Within v1, schemaVersion only identifies backward-compatible payload evolution; additive fields may raise it, and clients must ignore unknown fields. Any incompatible change moves to /api/v2.