API Endpoints: Technical Details
Technical details of the osTicket API Endpoints plugin: signal routes, standalone endpoint files, request flow, directory structure, database columns, security and tests.
API Endpoints: Technical Details
This documentation always describes the latest published version.
Architecture
The plugin uses two paths into osTicket's API:
- Signal routes. In
bootstrap(), the plugin connects to osTicket'sapisignal when the setting Enable API Endpoints is on. The handleronApiRequest()prepends two routes:POST /tickets.(xml|json|email)for extended ticket creation andPATCH/PUT /tickets/{number}.(json|xml)for updates. - Standalone endpoint files. All other endpoints are PHP files from the plugin's
api/folder. On enabling, they are copied to/api/. They load osTicket's bootstrap themselves, do not use the signal and are let through by rewrite rules in/api/.htaccess.
| Signal | Handler | Purpose |
|---|---|---|
api |
onApiRequest() |
Registers the two routes for ticket creation and update |
graph TD
A["Client request"] --> B["POST /api/tickets.json or PATCH /api/tickets/:number.json"]
A --> C["Endpoint files in /api/, for example tickets-get.php"]
B --> D["Signal api, onApiRequest"]
D --> E["ExtendedTicketApiController"]
C --> F["ApiBootstrap"]
F --> E
F --> G["SubticketApiController"]
E --> H["Services and osTicket core"]
G --> H
H --> I["JSON, XML or plain text response"]
Request Flow of a Standalone Endpoint
sequenceDiagram
participant C as Client
participant E as Endpoint file
participant B as ApiBootstrap
participant K as Controller
participant P as PermissionChecker
participant S as Service
C->>E: GET /api/tickets-get.php/781258.json
E->>B: parse path and check method
E->>K: getTicket(number)
K->>P: require can_read_tickets
P-->>K: allowed or 401
K->>S: TicketService.getTicket
S-->>K: ticket data
K-->>B: array
B-->>C: JSON or XML
ApiBootstrap is the shared base of all endpoint files: it parses the path with a regular expression, checks the HTTP method (405), parses the JSON body and sends successful responses and errors. Exceptions carry the HTTP status code.
Layers
| Part | File | Task |
|---|---|---|
| Controllers | controllers/ExtendedTicketApiController.php |
Extends osTicket's TicketApiController: creation, update, API key check |
controllers/SubticketApiController.php |
Subticket operations, optional department check, plugin check | |
| Services | lib/Services/TicketService.php |
Retrieval, search, statistics, statuses, deletion |
lib/Services/TicketValidatorService.php |
Validation and name lookup of format, department, topic, status, SLA, staff, parent, due date | |
lib/Services/PermissionChecker.php |
Reads the permission columns of the API key | |
lib/Services/AttachmentService.php |
Attachment download with a check against the attachment table | |
| Enums | lib/Enums/ |
Permission, MessageFormat, SortField |
| Helpers | lib/ApiBootstrap.php, lib/XmlHelper.php |
Request handling and XML output |
Directory Structure
api-endpoints/
βββ api/ # Endpoint files, copied to /api/
β βββ tickets-get.php
β βββ tickets-update.php
β βββ tickets-delete.php
β βββ tickets-search.php
β βββ tickets-stats.php
β βββ tickets-statuses.php
β βββ tickets-attachment-download.php
β βββ tickets-subtickets-{parent,list,create,unlink}.php
βββ assets/
β βββ admin-apikey-extension.js # Admin script, not loaded by the plugin code
βββ controllers/
βββ lib/
β βββ ApiBootstrap.php
β βββ XmlHelper.php
β βββ Enums/
β βββ Services/
βββ tests/ # PHPUnit tests (Unit, Integration)
βββ docs/
βββ class.ApiEndpointsPlugin.php # Plugin class ApiEndpointsPlugin
βββ config.php # Config class ApiEndpointsConfig
βββ plugin.php # Plugin manifest
βββ htaccess.template # Rewrite rules for /api/.htaccess
βββ openapi.yaml # OpenAPI description
Database
The plugin adds six columns of type TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 to osTicket's API key table: can_update_tickets, can_read_tickets, can_search_tickets, can_delete_tickets, can_read_stats and can_manage_subtickets. The columns are created if they are missing, existing data is not touched. Disabling or removing the plugin does not drop them.
Behaviour Worth Knowing
- Permission check: For the standalone endpoints,
PermissionCheckerreads the column of the API key. Missing or0means denied. Onlycan_search_ticketsandcan_read_statsfall back tocan_read_tickets. A failed check throws an exception with code401. - Create route: The handler of
POST /tickets.jsonvalidates the plugin parameters and then calls the controller with the API key check switched off. The plugin itself therefore does not check the key orcan_create_ticketson this route. - Wildcard plugin: If
include/plugins/api-key-wildcard/api.wildcard.inc.phpexists, the controller validates the API key with itsWildcardApiController, otherwise with osTicket's standard check. - Creation: The plugin consumes
departmentIdandparentTicketNumber, removes its own fields before passing the data to osTicket and applies department and parent after the ticket exists. - Update: Fields are applied one after another without a transaction.
- Errors: Errors the plugin raises in the standalone endpoints are answered as
{"error": true, "message": ...}, the signal routes answer with plain text. Errors of the API key check use the format of osTicket core or API Key Wildcard.
Security
- Attachment access: The download endpoint checks that a row with the requested
file_idexists in the attachment table before serving the file, and rejects it with403otherwise. The check does not filter by the type of the object the attachment belongs to. - Permission default: All permission columns start disabled.
- SQL: Dynamically built queries cast IDs to integers, escape values and check column names against a fixed list.
- XML: Values are escaped when XML is generated.
- JSON input: The nesting depth of the parsed body is limited.
Tests
The tests run with PHPUnit:
composer install
composer test # all tests
composer test:unit # unit tests only
composer test:integration # integration tests only
composer test:coverage # HTML coverage report
OpenAPI
The repository contains openapi.yaml with an OpenAPI description of the endpoints. This documentation is the reference where the two differ.