API Reference

Base URL: {APP_URL}/api/v1. Every client — the website, a future desktop app, a future CLI — talks to this exact API; there is no separate internal interface.

Response envelope

Success:

{ "success": true, "data": { }, "meta": { } }

meta is present only for paginated/list endpoints. Error:

{ "success": false, "error": { "code": "PLUGIN_NOT_FOUND", "message": "Plugin not found." } }

error.code is a stable, machine-readable string — branch on it, not on the HTTP status or the message text. A validation error additionally includes error.details, a map of field → array of messages.

Authentication

Bearer JWT access tokens (short-lived, 15 min by default) plus opaque refresh tokens (14 days, stored hashed, rotated on every use).

Authorization: Bearer <access_token>
EndpointAuthDescription
POST /auth/registerCreate an account, returns a token pair
POST /auth/login{ email, password } → token pair
POST /auth/refresh{ refresh_token } → a new, rotated token pair
POST /auth/logoutRevokes the given refresh token
POST /auth/forgot-passwordAlways returns success (doesn't leak whether the email exists)
POST /auth/reset-password{ token, password }
POST /auth/verify-email{ token }

Rate-limited more aggressively than the general API (RATE_LIMIT_AUTH_PER_MINUTE).

Current user

EndpointAuthDescription
GET /merequiredThe signed-in user
PATCH /merequiredUpdate display_name, bio, website_url, github_url
POST /me/change-passwordrequired{ current_password, new_password }

Catalog

EndpointAuthDescription
GET /categoriesAll categories with live plugin counts
GET /pluginsoptionalBrowse. Query: category, pricing (free|paid|freemium), min_rating, platform (macos|windows|linux), q, sort (popular|trending|newest|recently_updated|highest_rated), page, per_page
GET /plugins/search?q=Lightweight typeahead search
GET /plugins/{slug}Full detail: developer, categories, screenshots, latest version, permissions
GET /plugins/{slug}/versionsPublished version history
GET /plugins/{id}/latest-versionJust the newest published version
GET /plugins/{id}/updates?current_version=1.0.0{ update_available, latest_version } — the desktop update checker
GET /plugins/{id}/reviewsPaginated reviews (with developer replies)
POST /plugins/{id}/reviewsrequired{ rating, title?, body? } — upsert (one review per user per plugin)
POST /plugins/{id}/downloadoptionalMints a 5-minute signed download token
GET /downloads/{token}Streams the .pluginpackage
POST /reportsrequired{ reportable_type, reportable_id, reason, details? }

Library (the signed-in user's collection)

EndpointAuth
GET /libraryrequired
POST /library/{pluginId}required
PATCH /library/{pluginId}required — { auto_update: bool }
DELETE /library/{pluginId}required

Future desktop app support

These exist today so a desktop client can be built against a stable contract without another API version bump.

EndpointAuth
GET /devices / POST /devices / DELETE /devices/{id}required
POST /installationsrequired — reports a local install
PATCH /installations/{id}required — updates install status

Developer API

All under /developer, requiring the developer role (or higher). Becoming a developer: POST /developer/profile (any signed-in user).

EndpointDescription
GET/PATCH /developer/profileStudio name, support/payout email
GET /developer/pluginsEvery one of your plugins, any status
POST /developer/pluginsCreate a draft plugin
GET/PATCH /developer/plugins/{id}
POST /developer/plugins/{id}/submitdraft/rejected → submitted
POST /developer/plugins/{id}/icon | /screenshotsmultipart image upload
GET/POST /developer/plugins/{id}/versions
POST /developer/plugins/{id}/versions/{versionId}/packagemultipart .pluginpackage upload
POST /developer/plugins/{id}/versions/{versionId}/submitRequires a package already uploaded
GET /developer/permissionsThe permission catalog to build a submission form against
GET /developer/analytics | /developer/plugins/{id}/analyticsInstalls, downloads, ratings over time
GET/POST /developer/api-keys, DELETE /developer/api-keys/{id}Raw key shown once on creation only
POST /developer/reviews/{reviewId}/reply

Versioning

The v1 in /api/v1 is a hard contract: existing fields don't change shape or meaning. New optional fields may be added; breaking changes would ship as /api/v2. Semantic versioning of plugin releases is separate and described in docs/plugin-manifest.md.

Couldn't find the desktop app

If it's already installed, this can happen the first time your browser asks for permission to open it — try the button again. Otherwise, download it below and Get will open plugins directly from then on.

Download for macOS