Extends osTicket's REST API with powerful endpoints for advanced ticket management. Enables ticket creation with Markdown formatting, department routing, subticket support, and comprehensive ticket management (update, retrieve, search, delete, statistics).
Perfect for integrations that need granular control beyond osTicket's standard API capabilities - ideal for support portals, bug trackers, automation platforms (Zapier/Make.com), and custom workflows.
| Requirement | Version | Notes |
|---|---|---|
| osTicket | 1.18.x | Plugin extends API via Signal system |
| PHP | 8.1+ | Uses modern PHP features: enums, union types, named arguments |
| Web Server | Apache 2.4+ or NGINX 1.18+ | Apache: .htaccess support required |
| Parsedown | Automatic | Included in Composer lock |
Optional Dependencies:
| Plugin | Purpose | Link |
|---|---|---|
| Markdown Support | Markdown rendering in tickets | GitHub |
| Subticket Manager | UI for subticket management | GitHub |
| API Key Wildcard | Wildcard IP validation for API keys | GitHub |
api-endpoints folder to /include/plugins/ on your osTicket serverFinal path: /path/to/osticket/include/plugins/api-endpoints/
cd /path/to/osticket/include/plugins
git clone https://github.com/markus-michalski/osticket-api-endpoints.git
The plugin automatically configures:
On activation, the plugin automatically deploys /api/.htaccess:
# osTicket API Endpoints Plugin - Apache Configuration
<IfModule mod_rewrite.c>
RewriteEngine On
# Enable PATH_INFO for all API endpoints
AcceptPathInfo On
# Rewrite rules for endpoints with path info
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(tickets-update|tickets-get|tickets-delete)\.php/(.+)$ $1.php [L,QSA]
</IfModule>
# Allow PATH_INFO for endpoints
<Files "tickets-update.php">
AcceptPathInfo On
</Files>
<Files "tickets-get.php">
AcceptPathInfo On
</Files>
<Files "tickets-delete.php">
AcceptPathInfo On
</Files>
Verify .htaccess is working:
curl -I "https://your-domain.com/api/tickets-get.php/123456.json" \
-H "X-API-Key: YOUR_API_KEY"
# Should return 200 OK (not 404)
Add the following configuration to your NGINX server block:
# osTicket API Endpoints Plugin - NGINX Configuration
# Endpoints with PATH_INFO (e.g., /api/tickets-update.php/123456.json)
location ~ ^/api/tickets-(update|get|delete)\.php/ {
fastcgi_split_path_info ^(/api/tickets-(update|get|delete)\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php-fpm.sock; # Or 127.0.0.1:9000
}
# Endpoints without PATH_INFO (e.g., /api/tickets-search.php?query=test)
location ~ ^/api/tickets-(search|stats|statuses)\.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
}
# Subticket endpoints with PATH_INFO
location ~ ^/api/tickets-subtickets-(parent|list)\.php/ {
fastcgi_split_path_info ^(/api/tickets-subtickets-(parent|list)\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
}
# Subticket endpoints without PATH_INFO
location ~ ^/api/tickets-subtickets-(create|unlink)\.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
}
After adding configuration:
# Test configuration
sudo nginx -t
# Reload NGINX
sudo systemctl reload nginx
# Test endpoint
curl "https://your-domain.com/api/tickets-stats.php" \
-H "X-API-Key: YOUR_API_KEY"
After plugin installation, you need to configure API Key permissions to grant access to the new endpoints.
Configure API Key Permissions:
POST /tickets)PATCH /tickets/:id)GET /tickets/:number)GET /tickets/search)DELETE /tickets/:number) - Optional, disabled by default for securityGET /tickets-stats)Screenshot Example:
The API Key configuration shows permissions like:
β Create Tickets (can_create_tickets)
β Read Tickets (can_read_tickets)
β Update Tickets (can_update_tickets)
β Search Tickets (can_search_tickets)
β Delete Tickets (can_delete_tickets) [Disabled for security]
β Read Statistics (can_read_stats)
β Manage Subtickets (can_manage_subtickets)
After plugin installation, a new configuration page appears under Admin Panel β Plugins β API Endpoints β Configure, displaying all available endpoints with their associated permissions:
Available API Endpoints:
can_create_tickets permissioncan_read_tickets permissioncan_update_tickets permissioncan_search_tickets permissioncan_delete_tickets permissioncan_read_stats permissioncan_read_stats permissioncan_manage_subtickets permissionImportant: The plugin configuration page is informational only and shows which endpoints are available. Actual access to each endpoint is controlled individually per API Key via the API Key permissions system (see API Key Permissions).
The plugin provides 11 REST endpoints:
| Endpoint | Method | Description |
|---|---|---|
/api/tickets.json |
POST | Extended ticket creation (Markdown, Department, Subticket) |
/api/tickets-get.php/{number}.json |
GET | Retrieve ticket details |
/api/tickets-update.php/{number}.json |
PATCH | Update ticket (Status, Department, SLA, dueDate, etc.) |
/api/tickets-search.php |
GET | Search tickets |
/api/tickets-delete.php/{number}.json |
DELETE | Permanently delete ticket |
/api/tickets-stats.php |
GET | Ticket statistics (global, Department, Staff) |
/api/tickets-statuses.php |
GET | List available ticket statuses |
/api/tickets-subtickets-parent.php/{id}.json |
GET | Get parent ticket of a subticket |
/api/tickets-subtickets-list.php/{id}.json |
GET | Get all child tickets of a parent |
/api/tickets-subtickets-create.php |
POST | Create parent-child relationship |
/api/tickets-subtickets-unlink.php |
DELETE | Remove parent-child relationship |
All GET endpoints support both JSON and XML:
.json for JSON response.xml for XML responseUpdate ticket properties such as status, department, priority, SLA plan, staff assignment, and due date.
URL: PATCH /api/tickets-update.php/{number}.{format}
Updatable Fields:
| Field | Type | Description | Example |
|---|---|---|---|
statusId |
string/int | Status name or ID | "Resolved" or 3 |
departmentId |
string/int | Department name or ID | "Sales" or 7 |
topicId |
int | Help Topic ID | 15 |
slaId |
string/int | SLA Plan name or ID | "Premium Support" or 2 |
staffId |
string/int | Staff username or ID | "john.doe" or 5 |
teamId |
int | Team ID for assignment | 3 |
priority |
string/int | Priority name or ID | "Urgent", "High" or 4 |
dueDate |
string/null | Due date (ISO 8601) or null to clear |
"2026-01-31" or "2026-01-31T17:30:00" |
note |
string | Add internal note (staff only) | "Customer called for status update" |
The dueDate parameter allows you to set, update, or clear the ticket's due date.
Behavior:
null to remove the due dateisOverdue flag is automatically clearedExamples:
Set due date:
curl -X PATCH "https://osticket.local/api/tickets-update.php/123456.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"dueDate": "2026-01-31"
}'
Set due date with time:
curl -X PATCH "https://osticket.local/api/tickets-update.php/123456.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"dueDate": "2026-01-31T17:30:00"
}'
Clear due date:
curl -X PATCH "https://osticket.local/api/tickets-update.php/123456.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"dueDate": null
}'
Combined with other fields:
curl -X PATCH "https://osticket.local/api/tickets-update.php/123456.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"statusId": "Open",
"priority": "High",
"dueDate": "2026-02-15",
"note": "Due date updated, priority raised"
}'
Response:
{
"success": true,
"message": "Ticket updated successfully",
"ticket_id": 123456,
"number": "ABC123",
"updated_fields": ["dueDate", "priority"]
}
Error Response (invalid date):
{
"error": "Invalid date format for dueDate. Expected ISO 8601 format (e.g., \"2025-01-31\" or \"2025-01-31T17:30:00\")"
}
When you set a dueDate that is in the future (greater than current time), the plugin automatically calls clearOverdue() on the ticket. This:
isOverdue flag from 1 to 0This behavior only triggers when:
dueDate is different from the current due datedueDate is in the futureisOverdue = 1The plugin extends osTicket's API key permission system with granular permissions.
| Permission | Database Field | Grants Access To |
|---|---|---|
| Create Tickets | can_create_tickets |
POST /tickets |
| Read Tickets | can_read_tickets |
GET /tickets/:number |
| Update Tickets | can_update_tickets |
PATCH /tickets/:number |
| Search Tickets | can_search_tickets |
GET /tickets/search |
| Delete Tickets | can_delete_tickets |
DELETE /tickets/:number |
| Read Statistics | can_read_stats |
GET /tickets-stats, GET /tickets-statuses |
| Manage Subtickets | can_manage_subtickets |
All subticket endpoints |
Screenshot:
The plugin config adds a new tab "API Endpoints Permissions" with the following options:
β Create Tickets (can_create_tickets)
β Read Tickets (can_read_tickets)
β Update Tickets (can_update_tickets)
β Search Tickets (can_search_tickets)
β Delete Tickets (can_delete_tickets) [Disabled for security]
β Read Statistics (can_read_stats)
β Manage Subtickets (can_manage_subtickets)
The plugin supports legacy API keys (without new permissions):
can_create_tickets missing β fallback to canCreateTickets() (osTicket standard)can_read_tickets missing β fallback to canCreateTickets() (READ = CREATE allowed)can_update_tickets missing β fallback to canCreateTickets()Recommendation: Migrate to new permissions for fine-grained control.
Principle of Least Privilege:
can_read_statscan_create_ticketsRotation & Revocation:
Audit Logging:
Symptoms:
curl "https://osticket.local/api/tickets-get.php/123456.json"
# HTTP 404 Not Found
Cause: Apache/NGINX not configured for PATH_INFO.
Solution (Apache):
Check if /api/.htaccess exists:
ls -la /path/to/osticket/api/.htaccess
If missing, re-enable plugin (deploys .htaccess automatically)
Check Apache configuration:
# In VirtualHost or .conf
<Directory /path/to/osticket/api>
AllowOverride All
</Directory>
Reload Apache:
sudo systemctl reload apache2
Solution (NGINX):
Add PATH_INFO configuration (see Installation β NGINX)
Test configuration:
sudo nginx -t
Reload NGINX:
sudo systemctl reload nginx
Symptoms:
**bold** instead of bold)Check:
Markdown Support Plugin installed?
ls /path/to/osticket/include/plugins/markdown-support
Plugin enabled?
API request correct?
curl -X POST "https://osticket.local/api/tickets.json" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Test",
"email": "test@example.com",
"subject": "Markdown Test",
"message": "## Heading\n\n**Bold text**",
"format": "markdown" # β Important!
}'
Plugin configuration:
Workaround: If Markdown Support Plugin unavailable:
format: "html" instead of format: "markdown"Symptoms:
{
"error": "API key not authorized for this operation"
}
Cause: API key has missing permissions.
Solution:
Check API key permissions:
can_create_ticketscan_read_ticketscan_update_ticketscan_delete_ticketscan_search_ticketscan_read_statscan_manage_subticketsRe-enable plugin after update:
Check fallback permission:
canCreateTickets() as fallbackThis Plugin is released under the GNU General Public License v2, compatible with osTicket core.
See LICENSE for details.
For questions or issues, please create an issue on GitHub:
Issue Tracker: https://github.com/markus-michalski/osticket-api-endpoints/issues
When reporting issues, please include:
php -v)Developed by Markus Michalski
Contributions welcome!
Development Setup:
# Clone repository
git clone https://github.com/markus-michalski/osticket-api-endpoints.git
cd osticket-api-endpoints
# Install dependencies
composer install
# Run tests
composer test
# Check code style
composer cs-check
See CHANGELOG.md for version history.