The plugin provides an interface for its own frontend. It runs through the file scp/ajax-subticket.php, which the plugin copies there on activation. All actions require a staff login (the session cookie of the staff area). There is no API key access. For access from outside use the API Endpoints plugin.
The interface is built for the plugin's own JavaScript files. The parameter names and responses are not meant as a stable public API.
The action is selected with the action parameter.
| Action | Method | Parameters | CSRF | Access check | Purpose |
|---|---|---|---|---|---|
children |
GET | tid (ticket ID) |
no | Staff login | Children of a ticket |
link |
POST | child_id (ticket ID), parent_id (ticket number of the parent) |
yes | Department of the child ticket | Link a child to a parent |
unlink |
POST | child_id (ticket ID) |
yes | Department of the child ticket | Remove the link |
create |
POST | parent_id (ticket ID), subject, dept_id, message |
yes | Department of the parent ticket | Create a new ticket and link it |
batch_parent_status |
GET | ticket_ids (comma-separated, at most 100) |
no | Staff login | Parent status for several tickets |
version |
GET | none | no | Staff login | Diagnostics: plugin version, paths, file sizes, PHP version |
Pass the CSRF token as __CSRFToken__ or csrf_token. The plugin's JavaScript sends csrf_token.
The actions children, link, unlink, create and batch_parent_status answer with JSON in this format:
{
"success": true,
"message": "Found 2 children",
"data": []
}
Business errors come back with HTTP 200 and "success": false. Technical errors use HTTP status codes:
| Status | Cause |
|---|---|
| 403 | Not logged in as staff (Access denied) |
| 400 | Action missing or unknown (Invalid action), for children the tid is missing (Missing ticket ID) |
| 500 | Plugin folder not found, present more than once or controller missing, or an exception in the handler |
GET /scp/ajax-subticket.php?action=children&tid=15
data is a list of the children sorted by creation date:
{
"success": true,
"message": "Found 1 children",
"data": [
{ "id": 123, "number": "181752", "subject": "Switch DNS", "status": "Open", "created": "2026-01-15 10:30:00" }
]
}
If the ticket has no children, the message is No children found and data is empty.
POST /scp/ajax-subticket.php?action=link
child_id=123&parent_id=181752&csrf_token=...
parent_id is the ticket number of the parent, not the internal ID, and must be numeric. On success the message is Tickets successfully linked, otherwise Failed to link tickets. Linking fails for an unknown number, self-linking and loops. The plugin does not check whether the agent has access to the parent's department or whether the parent is closed.
POST /scp/ajax-subticket.php?action=unlink
child_id=123&csrf_token=...
On success the message is Ticket successfully unlinked.
POST /scp/ajax-subticket.php?action=create
parent_id=15&subject=Switch DNS&dept_id=2&message=Please ...&csrf_token=...
The plugin creates a new ticket through Ticket::create() and links it to the parent. The plugin's user interface does not use this action; the Create Subticket button opens the regular ticket form instead.
| Field | Rule |
|---|---|
subject |
Required, at most 50 bytes (umlauts count twice), HTML tags are stripped |
message |
Required |
dept_id |
Required, positive number |
| Name, email | Taken from the parent ticket |
| Help topic | The parent's. If the parent has none, the first active help topic of the department, otherwise the first active one overall, finally help topic ID 1 |
| Priority, SLA, due date | Taken from the parent ticket |
| Source | Staff; autoresponse and staff alert are off |
| Note | Created as subticket of #<parent number> |
On success data contains the new ticket number: {"ticket_number": "181800"}. If only the linking fails, the message is Ticket created but linking failed and the ticket exists anyway.
GET /scp/ajax-subticket.php?action=batch_parent_status&ticket_ids=15,16,17
{
"success": true,
"message": "Parent status retrieved",
"data": {
"15": { "is_parent": true, "child_count": 3 },
"16": { "is_parent": false, "child_count": 0 }
}
}
Unknown IDs appear with is_parent: false. More than 100 IDs produce the error Too many ticket IDs (max 100).
children, link, unlink and create are subject to a per-session limit of at most 100 requests within 60 seconds. When it is exceeded, the plugin blocks the session for 60 seconds and answers with Too many requests. batch_parent_status and version do not count.
| Message | Meaning |
|---|---|
Invalid ticket ID |
For children: tid is not numeric or smaller than 1 |
Invalid child ticket ID / Invalid parent ticket ID/number / Invalid parent ticket ID |
The value is not numeric or smaller than 1 |
Invalid subject |
Subject missing or empty |
Subject too long (max 50 characters) |
Subject longer than 50 bytes (the message says "characters" but bytes are counted) |
Invalid department ID |
dept_id is not numeric or smaller than 1 |
Invalid message |
Message missing or empty |
Failed to create ticket |
Ticket::create() returned no ticket |
Failed to unlink ticket |
The UPDATE for unlinking failed |
No valid ticket IDs provided |
For batch_parent_status, ticket_ids contains no valid ID |
Missing CSRF token / Invalid CSRF token |
Token missing or rejected by osTicket |
Permission denied |
No staff object in the session |
You do not have access to this ticket |
No access to the ticket's department |
Ticket not found |
The ticket ID does not exist |