The plugin registers purely through osTicket's Signal system and makes no core modifications:
bootstrap(), the plugin calls Signal::connect('api', ...) β this works with both the standard API and the API Key Wildcard pluginExtendedTicketApiController extends osTicket's own TicketApiController with the additional parameters and endpointsSubticketApiController encapsulates the subticket endpoints as a separate controllerapi-endpoints/
βββ api/ # Endpoint entry points
β βββ tickets-get.php
β βββ tickets-update.php
β βββ tickets-delete.php
β βββ tickets-search.php
β βββ tickets-stats.php
β βββ tickets-statuses.php
β βββ tickets-attachment-download.php
β βββ tickets-subtickets-*.php
βββ assets/ # Admin UI JavaScript/CSS
βββ controllers/
β βββ ExtendedTicketApiController.php
β βββ SubticketApiController.php
βββ lib/
β βββ ApiBootstrap.php
β βββ Enums/
β βββ Services/
βββ tests/ # PHPUnit tests
βββ docs/
βββ class.ApiEndpointsPlugin.php # Main plugin class
βββ config.php # ApiEndpointsConfig
βββ plugin.php # Plugin manifest
βββ htaccess.template # Template for /api/.htaccess
βββ openapi.yaml # OpenAPI specification
The extra permission checkboxes on the API key management page don't come from osTicket core β the plugin injects them itself:
injectAdminUi() injects a JavaScript snippet on requests to /scp/apikeys.php that adds the extra permission fields (can_create_tickets, can_read_tickets, etc.) into the existing formhandleApiKeyFormSubmission() picks up those fields and saves them to the database when the API key form is submittedThis keeps the osTicket core UI untouched while still showing the additional options.
file_id is actually linked in ost_ticket_attachment. Arbitrary file IDs from ost_file (e.g. logos, canned responses, knowledgebase files) are rejected with 403All GET endpoints support both JSON (.json) and XML (.xml) via the URL's file extension. XML output is handled by lib/XmlHelper.php.
The plugin is tested with PHPUnit (composer test). Validation logic deliberately lives in the controllers rather than the API entry points, so it can be tested in isolation.