- Docs
- Troy Server
- Server API
API Reference
Troy Server exposes public REST endpoints for plugin distribution and PHP API classes for server-side integrations.
Constants
Troy Server defines these constants in the Troy\Server namespace:
| Constant | Type | Description |
|---|---|---|
VERSION | string | Plugin version (e.g., '0.0.1184') |
DB_VERSION | int | Database schema version |
ABSPATH | string | Plugin directory path |
PLUGIN_BASENAME | string | Plugin basename for WordPress |
PLUGIN_SLUG | string | Plugin slug |
PLUGINS_CPT | string | Custom post type for plugins ('troy-server-plugins') |
PACKAGES_CPT | string | Custom post type for packages ('troy-server-packages') |
REST Endpoints
All endpoints are relative to your Troy Server URL (e.g., https://repo.deploytroy.org/). All endpoints include CORS headers, so browsers can call them directly from other origins (e.g., for a public stats dashboard).
Ping
GET /ping
Returns server status. Useful for connectivity checks.
Response: 200 OK
{
"status": "ok",
"message": "pong",
"time": "2026-03-01 17:03:42"
}
Plugin Endpoints
These endpoints serve plugin data to Troy Client and other consumers. For managing plugins on your server, see Plugin Management.
Plugin Updates
POST /plugin/get/updates
Check for available plugin updates. This is the primary endpoint Troy Client calls.
Request Body (JSON):
{
"active_plugins": {
"my-plugin/my-plugin.php": "1.0.0"
},
"inactive_plugins": {},
"php_version": "8.2",
"wp_version": "6.8",
"troy_version": "0.0.1184",
"channel": "tag",
"locales": ["en_US"]
}
Response:
{
"update": {
"my-plugin": {
"id": "repo.deploytroy.org",
"slug": "my-plugin",
"new_version": "1.1.0",
"url": "https://repo.example.org/my-plugin",
"package": "https://repo.deploytroy.org/plugin/get/zip/my-plugin/1.1.0/",
"icons": { "1x": "" },
"banners": [],
"banners_rtl": [],
"requires": "6.7",
"tested": "6.8",
"requires_php": "7.4",
"requires_plugins": [],
"compatibility": [],
"upgrade_notice": "",
"autoupdate": false
}
},
"no_update": {},
"translations": []
}
Plugin Information
GET /plugin/get/info?slug={slug}
Get detailed plugin information for the WordPress plugin modal.
Plugin Download
GET /plugin/get/zip/{slug}
GET /plugin/get/zip/{slug}/{version}
Download a plugin ZIP file. Without {version}, returns the latest stable release.
Plugin Tags
GET /plugin/get/tags/{slug}
Returns a list of available versions (tags) for a plugin, sorted by release date (newest first). Useful for version selection UI, build scripts, or checking available releases.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
include_beta | boolean | false | Include beta releases in results |
limit | integer | 100 | Maximum number of tags to return (max: 100) |
Response: 200 OK
[
{
"version": "0.0.1184",
"zip_url": "https://repo.deploytroy.org/plugin/get/zip/troy-client/0.0.1184/",
"file_size": 36019,
"tested_wp": "6.9",
"requires_wp": "6.7",
"requires_php": "7.4",
"checksum": "27b360e365eadd9eaa6f5532efbfa3f51cc19c154e1715b06fbebcdb79c43042",
"checksum_version": "sha256",
"checksum_origin": "repo.deploytroy.org",
"updated_at": "2025-12-03 03:17:39"
}
]
Response Fields:
| Field | Type | Description |
|---|---|---|
version | string | Semantic version number |
zip_url | string | Direct download URL for this version |
file_size | integer | ZIP file size in bytes |
tested_wp | string | WordPress version tested up to |
requires_wp | string | Minimum WordPress version required |
requires_php | string | Minimum PHP version required |
checksum | string | File integrity checksum |
checksum_version | string | Checksum algorithm (e.g., sha256) |
checksum_origin | string | Server that generated the checksum |
updated_at | string | Release timestamp (UTC) |
Example with beta releases and limit:
curl "https://repo.deploytroy.org/plugin/get/tags/troy-server?include_beta=1&limit=5"
Plugin Stats
GET /plugin/get/stats/{slug}
Returns public statistics for a plugin, including download counts, active installations, and ratings. Available for plugins with active or unlisted status.
Response: 200 OK
{
"slug": "my-plugin",
"downloads": 1234,
"active_installs": 567,
"rating": 0,
"num_ratings": 0,
"ratings": {
"5": 0,
"4": 0,
"3": 0,
"2": 0,
"1": 0
}
}
Response Fields:
| Field | Type | Description |
|---|---|---|
slug | string | The plugin slug |
downloads | integer | Total download count |
active_installs | integer | Current active installation count |
rating | integer | Average rating (0–100 scale) |
num_ratings | integer | Total number of ratings |
ratings | object | Rating breakdown by star count (1–5) |
Ratings Coming Soon:
We have plans for a better review system that helps authors and keeps users anonymous.
Join the discussion →Error Responses:
| Status | Reason |
|---|---|
403 Forbidden | Plugin is protected, pending, or disabled |
404 Not Found | Plugin does not exist |
Multi-Plugin Stats
POST /plugin/get/stats
Retrieve stats for multiple plugins in a single request. Accepts a JSON array of slugs (up to 69) and returns an object keyed by slug.
Request Body:
["my-plugin", "another-plugin"]
Response: 200 OK
{
"my-plugin": {
"slug": "my-plugin",
"downloads": 1234,
"active_installs": 567,
"rating": 0,
"num_ratings": 0,
"ratings": {
"5": 0,
"4": 0,
"3": 0,
"2": 0,
"1": 0
}
},
"another-plugin": {
"slug": "another-plugin",
"downloads": 42,
"active_installs": 10,
"rating": 0,
"num_ratings": 0,
"ratings": {
"5": 0,
"4": 0,
"3": 0,
"2": 0,
"1": 0
}
}
}
Each value uses the same fields as the single-plugin GET response. Slugs that don't exist or aren't accessible are omitted from the response.
Error Responses:
| Status | Reason |
|---|---|
400 Bad Request | Body is not a valid JSON array of slugs |
400 Bad Request | More than 69 slugs in the request |
Package Endpoints
For background on packages and how they bundle plugins with Troy Client, see Packages.
Package Download
GET /package/get/zip/{slug}
Download a Troy Package (installer bundle).
Channels
The channel parameter in update requests:
| Channel | Behavior |
|---|---|
tag | Only stable releases (default) |
beta | Include beta releases |
Resource Lookup
Troy Server provides API classes in the Troy\Server\API namespace. These classes retrieve plugin, package, and server data. For how plugins and packages are managed, see Plugin Management and Packages.
Server Class
Server-wide operations and configuration.
use Troy\Server\API\Server;
get_db_version()
Returns the current database version.
Server::get_db_version(): int
get_repo_url()
Returns the bare repository URL (without scheme).
Server::get_repo_url(): string
// Returns: 'repo.example.org/repo'
get_full_repo_url()
Returns the fully-qualified repository URL.
Server::get_full_repo_url(): string
// Returns: 'https://repo.example.org/repo/'
get_server_settings()
Returns the plugin settings array.
Server::get_server_settings(): array
Plugin Class
Plugin lookup and management operations.
use Troy\Server\API\Plugin;
get_plugin_id_by_slug()
Finds a plugin's internal ID by its slug.
Plugin::get_plugin_id_by_slug( string $slug ): ?int
Returns: The plugin ID or null if not found.
get_plugin_id_by_post_id()
Finds a plugin's internal ID by its WordPress post ID.
Plugin::get_plugin_id_by_post_id( int $post_id ): ?int
get_post_id_by_plugin_id()
Finds the WordPress post ID for a plugin.
Plugin::get_post_id_by_plugin_id( int $plugin_id ): ?int
Package Class
Package lookup operations.
use Troy\Server\API\Package;
get_package_id_by_slug()
Finds a package's internal ID by its slug.
Package::get_package_id_by_slug( string $slug ): ?int
get_package_id_by_post_id()
Finds a package's internal ID by its WordPress post ID.
Package::get_package_id_by_post_id( int $post_id ): ?int
get_post_id_by_package_id()
Finds the WordPress post ID for a package.
Package::get_post_id_by_package_id( int $package_id ): ?int
Input Handling
Sanitize Class
Input sanitization utilities.
use Troy\Server\API\Sanitize;
semver()
Extracts and sanitizes a SemVer version string.
Sanitize::semver( string $version ): string
Requires three-part versioning (major.minor.patch). Returns empty string if invalid.
slug()
Sanitizes a slug for URLs and database storage.
Sanitize::slug( string $slug ): string
- Converts to lowercase.
- Replaces non-alphanumeric characters with hyphens.
- Collapses multiple hyphens.
- Limits to 191 characters.
sql_date()
Sanitizes a date for SQL storage.
Sanitize::sql_date( string $date ): string
// Returns: 'Y-m-d' format
bare_repo_url()
Strips a URL to its bare form (no scheme, no trailing slash).
Sanitize::bare_repo_url( string $url ): string
fully_qualified_repo_url()
Reconstructs a full HTTPS URL from a bare URL.
Sanitize::fully_qualified_repo_url( string $url ): string
file_path()
Sanitizes a file path for safe storage and retrieval.
Sanitize::file_path( string $file_path ): string
docblock_content()
Sanitizes content extracted from docblocks (plugin headers, etc.).
Sanitize::docblock_content( string $value ): string
var_export()
Exports a variable to a formatted string representation.
Sanitize::var_export( mixed $value, int $tab_count = 0 ): string
Useful for generating PHP code from dynamic values.
Utilities
Utils Class
General utilities.
use Troy\Server\API\Utils;
get_epoch()
Returns the current or previous epoch for UUID rotation.
Utils::get_epoch( string $offset = 'current' ): int
Parameters:
$offset—'current'or'last'for previous epoch
An epoch is floor(unix_timestamp / 604800) — the number of complete weeks since January 1, 1970. Each Troy Client generates a random anonymous ID prefixed with the current epoch. When the epoch increments, every client generates a new ID, making previous data ephemeral.
Current epoch:
Troy Server uses the max() of the current and previous epoch's distinct UUID count as the public active_installs value. This smooths the transition when a new epoch starts and not all clients have checked in yet.
extract_latest_version()
Finds the latest version from an array of version objects.
Utils::extract_latest_version( array $versions ): ?string
Prioritizes by type: tag > beta > unreleased.
get_latest_public_wordpress_version()
Returns the latest public WordPress version (from GitHub API).
Utils::get_latest_public_wordpress_version( string $from_version = '' ): string
Results are cached for 6 hours.
Slug Class
Slug conflict detection and resolution.
use Troy\Server\API\Slug;
Unlike other API classes, Slug is instantiated:
$slug = new Slug(
slug: 'my-plugin',
for_type: 'plugin', // 'plugin' or 'package'
exclude_id: 0 // ID to exclude from conflict checks
);
// Properties (read-only, lazily computed)
$slug->conflict_type; // 'plugin', 'package', or null
$slug->unique_slug; // Original slug or suffixed version
Source Code
For implementation details, see the Troy Server source:
