REST API Reference
Every public and authenticated endpoint, with the exact parameters the server accepts.
https://kindhearted-ladybug-387.convex.siteAll responses are JSON. CORS is open, so the endpoints are callable from anywhere. Public endpoints need no authentication.
Identifying an installation
Every public endpoint accepts an optional install_id — a UUID your add-on generates once and stores outside its own folder, so it survives being uninstalled and reinstalled.
It must be a well-formed UUID; anything else is rejected and ignored. Sending it is what lets the service count one machine once instead of once per request, which is what makes community version verification and your unique-install numbers meaningful. Omitting it is fine — the check still works, it just does not count toward any statistic.
"install_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301"
Never derive this from hardware, a username, or an IP address. Generate a random UUID4. See the Privacy Policy for how it is handled.
Public endpoints
/api/checkCheck a single add-on for a newer version.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
addon_id | string | required | Add-on ID from blender_manifest.toml. |
version | string | required | Currently installed version. |
blender_version | string | optional | e.g. "4.2". Used for compatibility limits and adoption stats. |
use_community | boolean | optional | Set "true" to fall back to community-verified versions when the add-on is not registered. |
install_id | uuid | optional | Anonymous installation identifier. See above. |
Response
{
"success": true,
"addon_id": "GeoCables",
"addon_name": "Geo Cables",
"icon_url": "https://...",
"found": true,
"current_version": "1.5.0",
"latest_version": "1.6.0",
"update_available": true,
"changelog": "Fixed cable snapping...",
"update_url": "https://...",
"changelog_url": "https://projectleuc.com/addons/GeoCables/changelog?version=1.6.0",
"update_type": "minor",
"is_critical": false,
"patch_url": null,
"from_community": false
}from_community is true when the version came from crowd-sourced reports rather than the developer. Community results carry no changelog or download URL.
/api/bulk-checkCheck every installed add-on in one request. This is what the Master Add-on uses — one round trip on startup instead of one per add-on.
Body
| Name | Type | Required | Description |
|---|---|---|---|
addons | array | required | Objects with addon_id and version. blender_version may be set per item. |
use_community | boolean | optional | Include community-verified versions. |
blender_version | string | optional | Applies to every item that does not set its own. |
install_id | uuid | optional | Sent once for the whole request, not per add-on. |
Example request
{
"install_id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"blender_version": "4.2",
"use_community": true,
"addons": [
{ "addon_id": "GeoCables", "version": "1.5.0" },
{ "addon_id": "RanTools", "version": "3.2.1" }
]
}Response
{
"success": true,
"checked_at": 1755432000000,
"announcement": {
"title": "Scheduled maintenance",
"message": "The API will be briefly unavailable on Sunday.",
"image_url": null,
"links": [{ "label": "Status", "url": "https://..." }]
},
"results": [
{
"addon_id": "GeoCables",
"addon_name": "Geo Cables",
"found": true,
"current_version": "1.5.0",
"latest_version": "1.6.0",
"official_version": "1.6.0",
"community_version": null,
"update_available": true,
"update_type": "minor",
"is_critical": false,
"patch_url": null,
"from_community": false
}
]
}announcement is null when none is active. It is the same for every caller — nothing about the request selects it.
/api/reportReport installed versions without asking for update information. Use this when your client resolves updates from the static CDN manifests and only needs to contribute version data.
Body
Accepts a single object, a bare array, or { "addons": [...] }. Items missing addon_id or version are skipped.
| Name | Type | Required | Description |
|---|---|---|---|
addons | array | required | Objects with addon_id and version. |
install_id | uuid | optional | Anonymous installation identifier. |
blender_version | string | optional | Global fallback for items that omit it. |
client_hash | string | optional | Legacy name for install_id. Only honoured if it happens to be a valid UUID. |
{ "success": true, "processed": 2 }/api/versionsFull published version history for a registered add-on.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
addon_id | string | required | The add-on ID. |
{
"success": true,
"addon_id": "GeoCables",
"versions": [
{
"version": "1.6.0",
"changelog": "Fixed cable snapping...",
"published_at": 1755432000000,
"is_latest": true
}
]
}Returns 404 if the add-on is not registered.
/api/report-bugFile a bug report against a registered add-on. See Bug Reports for how this fits together end to end. 404 if addon_id is not registered or is inactive — reports can only reach add-ons with a developer to receive them.
Body
| Name | Type | Required | Description |
|---|---|---|---|
addon_id | string | required | The add-on being reported. |
message | string | required | The error text. At least 10 characters. Re-redacted on arrival regardless of client version. |
addon_version | string | optional | Fallback used only if a version cannot be detected from the traceback. |
blender_version | string | optional | Same fallback rule as addon_version. |
name | string | optional | Optional. What the developer should call the reporter. |
email | string | optional | Optional. Only if the reporter wants a direct reply. |
discord_tag | string | optional | Optional. |
{
"success": true,
"ticket": "leuc-XXXX-XXXXXXXX-XXXXXXXX",
"addon_name": "Geo Cables",
"message": "Report sent. Keep the ticket to check its status."
}429 if the sending network is rate limited, with a Retry-After header.
/api/report-statusPoll a report by its ticket. Returns only the status and the developer's note — never the report body or contact details, since a ticket is a receipt, not a login.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
ticket | string | required | The ticket returned by /api/report-bug. |
{
"success": true,
"ticket": "leuc-XXXX-XXXXXXXX-XXXXXXXX",
"addon_id": "GeoCables",
"status": "acknowledged",
"developer_note": null,
"merged": false,
"submitted_at": 1755432000000,
"updated_at": 1755432000000
}merged is true when this ticket was folded into an earlier report of the same bug — the status and note above are the canonical report's, not this ticket's own. Returns 404 if the ticket does not exist.
Management API
These require a Personal Access Token sent as Authorization: Bearer YOUR_TOKEN. Missing or invalid tokens return 401.
/api/v1/addonslockBearer tokenList every add-on owned by the authenticated account.
{
"success": true,
"addons": [
{
"addon_id": "GeoCables",
"name": "Geo Cables",
"current_version": "1.6.0",
"icon_url": "https://...",
"is_verified": true
}
]
}/api/v1/updatelockBearer tokenPublish a new version, or update the changelog of an existing one.
Body
| Name | Type | Required | Description |
|---|---|---|---|
addon_id | string | required | The add-on you own. |
version | string | required | Semantic version string. |
changelog | string | optional | Markdown. Shown to users before they update. |
update_type | enum | optional | major | minor | patch |
is_critical | boolean | optional | Flags the update as urgent in the client UI. |
{ "success": true, "version_id": "..." }Returns 400 with an error string on failure.
/api/v1/patcheslockBearer tokenUpload a differential patch so clients download only what changed between two versions. The file is stored and served from the CDN, and returned as patch_url on future checks.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
addon_id | string | required | The add-on you own. |
from | string | required | Version the patch upgrades from. |
to | string | required | Version the patch upgrades to. |
Body
The raw patch file as the request body. Maximum 1 MB — larger uploads are rejected with 413.
curl -X POST \ "https://kindhearted-ladybug-387.convex.site/api/v1/patches?addon_id=GeoCables&from=1.5.0&to=1.6.0" \ -H "Authorization: Bearer YOUR_TOKEN" \ --data-binary @patch.zip
{
"success": true,
"patch_id": "...",
"url": "https://cdn.../patch.zip",
"message": "Patch uploaded successfully to Cloudflare"
}Status codes
| Code | Meaning |
|---|---|
200 | Success. Check the success field — a found/not-found result is still a 200. |
400 | Missing required parameters, or malformed JSON. |
401 | Missing or invalid Bearer token. |
404 | Add-on not found (/api/versions only). |
413 | Patch upload over 1 MB. |