REST API Reference

Every public and authenticated endpoint, with the exact parameters the server accepts.

public
Base URLhttps://kindhearted-ladybug-387.convex.site

All 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

GET/api/check

Check a single add-on for a newer version.

Query parameters

NameTypeRequiredDescription
addon_idstringrequiredAdd-on ID from blender_manifest.toml.
versionstringrequiredCurrently installed version.
blender_versionstringoptionale.g. "4.2". Used for compatibility limits and adoption stats.
use_communitybooleanoptionalSet "true" to fall back to community-verified versions when the add-on is not registered.
install_iduuidoptionalAnonymous 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.

POST/api/bulk-check

Check 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

NameTypeRequiredDescription
addonsarrayrequiredObjects with addon_id and version. blender_version may be set per item.
use_communitybooleanoptionalInclude community-verified versions.
blender_versionstringoptionalApplies to every item that does not set its own.
install_iduuidoptionalSent 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.

POST/api/report

Report 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.

NameTypeRequiredDescription
addonsarrayrequiredObjects with addon_id and version.
install_iduuidoptionalAnonymous installation identifier.
blender_versionstringoptionalGlobal fallback for items that omit it.
client_hashstringoptionalLegacy name for install_id. Only honoured if it happens to be a valid UUID.
{ "success": true, "processed": 2 }
GET/api/versions

Full published version history for a registered add-on.

Query parameters

NameTypeRequiredDescription
addon_idstringrequiredThe 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.

POST/api/report-bug

File 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

NameTypeRequiredDescription
addon_idstringrequiredThe add-on being reported.
messagestringrequiredThe error text. At least 10 characters. Re-redacted on arrival regardless of client version.
addon_versionstringoptionalFallback used only if a version cannot be detected from the traceback.
blender_versionstringoptionalSame fallback rule as addon_version.
namestringoptionalOptional. What the developer should call the reporter.
emailstringoptionalOptional. Only if the reporter wants a direct reply.
discord_tagstringoptionalOptional.
{
  "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.

GET/api/report-status

Poll 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

NameTypeRequiredDescription
ticketstringrequiredThe 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.

GET/api/v1/addonslockBearer token

List 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
    }
  ]
}
POST/api/v1/updatelockBearer token

Publish a new version, or update the changelog of an existing one.

Body

NameTypeRequiredDescription
addon_idstringrequiredThe add-on you own.
versionstringrequiredSemantic version string.
changelogstringoptionalMarkdown. Shown to users before they update.
update_typeenumoptionalmajor | minor | patch
is_criticalbooleanoptionalFlags the update as urgent in the client UI.
{ "success": true, "version_id": "..." }

Returns 400 with an error string on failure.

POST/api/v1/patcheslockBearer token

Upload 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

NameTypeRequiredDescription
addon_idstringrequiredThe add-on you own.
fromstringrequiredVersion the patch upgrades from.
tostringrequiredVersion 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

CodeMeaning
200Success. Check the success field — a found/not-found result is still a 200.
400Missing required parameters, or malformed JSON.
401Missing or invalid Bearer token.
404Add-on not found (/api/versions only).
413Patch upload over 1 MB.