Diese Dokumentation bezieht sich immer auf die aktuellste veröffentlichte Version.
Diese Seite beschreibt alle 12 Endpunkte des Plugins: Pfade, Methoden, Parameter, nötige API-Key-Berechtigungen, Antworten und Fehlercodes. Installation und Webserver-Einrichtung stehen auf Installation, die Berechtigungen auf Konfiguration.
| # | Methode | Pfad | Berechtigung |
|---|---|---|---|
| 1 | POST | /api/tickets.json |
siehe POST Ticket erstellen |
| 2 | GET | /api/tickets-get.php/{number}.{format} |
can_read_tickets |
| 3 | PATCH, PUT | /api/tickets-update.php/{number}.{format} oder /api/tickets/{number}.{format} |
can_update_tickets |
| 4 | GET | /api/tickets-search.php |
can_search_tickets oder can_read_tickets |
| 5 | DELETE | /api/tickets-delete.php/{number}.{format} |
can_delete_tickets |
| 6 | GET | /api/tickets-stats.php |
can_read_stats oder can_read_tickets |
| 7 | GET | /api/tickets-statuses.php |
can_read_stats oder can_read_tickets |
| 8 | GET | /api/tickets-subtickets-parent.php/{number}.{format} |
can_manage_subtickets |
| 9 | GET | /api/tickets-subtickets-list.php/{number}.{format} |
can_manage_subtickets |
| 10 | POST | /api/tickets-subtickets-create.php/{parentNumber}.{format} |
can_manage_subtickets |
| 11 | DELETE | /api/tickets-subtickets-unlink.php/{number}.{format} |
can_manage_subtickets |
| 12 | GET | /api/tickets-attachment-download.php/{file_id}.{format} |
can_read_tickets |
{format} ist json oder xml. Die Berechtigungsnamen sind die Spalten der API-Key-Tabelle, siehe Konfiguration.
Jede Anfrage trägt den API-Key im Header X-API-Key.
X-API-Key: YOUR_API_KEY
Die eigenständigen Endpunkte (2 bis 12) lehnen einen fehlenden oder ungültigen Key mit 401 ab. Ein API-Key ohne die für den Endpunkt nötige Berechtigung erhält 401 mit einer Meldung wie API key not authorized to read tickets. Nur die Subticket-Endpunkte und der Attachment-Download antworten in bestimmten Fällen mit 403, siehe Statuscodes. Endpunkt 1 wird anders behandelt, siehe den zugehörigen Abschnitt.
can_read_ticketsgewährt auch Suche, Statistiken und die Statusliste. Ein Key, der nurcan_search_ticketsodercan_read_statshat, kann nur genau diesen einen Endpunkt nutzen. Alle anderen Berechtigungen haben keinen Fallback: Eine fehlende oder deaktivierte Berechtigung bedeutet verweigerten Zugriff.
https://your-domain.com/api
| Endpunkt-Typ | Erfolgsantwort |
|---|---|
| Erstellen (1), Aktualisieren (3), Löschen (5) | Ticketnummer als Klartext (text/plain) |
Endpunkte mit {number}.{format} (2, 8, 9, 10, 11, 12) |
JSON, oder XML wenn der Pfad auf .xml endet |
| Suche, Statistik, Statusliste (4, 6, 7) | JSON. Die Pfadinfo hinter dem Skriptnamen ist optional und darf .json oder .xml sein, bei .xml ist die Antwort XML |
XML-Antworten haben response als Wurzelelement, Listeneinträge heißen item. Fehler, die das Plugin selbst auslöst, sind immer JSON, auch bei .xml-Anfragen:
{
"error": true,
"message": "Description of what went wrong"
}
Fehler der API-Key-Prüfung (fehlender oder ungültiger Key, IP-Beschränkung) stammen aus dem osTicket-Core oder dem Plugin API Key Wildcard und haben deren Format.
Fehler der beiden über das Signal registrierten Routen (Erstellen und PATCH /api/tickets/{number}.{format}) kommen als Klartext, der nur die Meldung enthält.
| Code | Bedeutung | Wann |
|---|---|---|
200 |
OK | Anfrage erfolgreich |
201 |
Created | Ticket erstellt (Endpunkt 1) |
400 |
Bad Request | Ungültiges URL-Format, ungültige oder fehlende Parameter, Validierung fehlgeschlagen |
401 |
Unauthorized | Eigenständige Endpunkte und Update-Route: fehlender oder ungültiger API-Key, oder dem Key fehlt die nötige Berechtigung |
403 |
Forbidden | Subticket-Endpunkte: can_manage_subtickets fehlt, oder das API-Key-Objekt liefert Abteilungsbeschränkungen, die die Abteilung des Tickets ausschließen. Attachment-Download: kein Anhang-Eintrag zur Datei |
404 |
Not Found | Ticket, Abteilung, Status, Hilfethema, SLA, Mitarbeiter oder Datei nicht gefunden |
405 |
Method Not Allowed | Falsche HTTP-Methode für einen eigenständigen Endpunkt (Method Not Allowed. Use GET) |
422 |
Unprocessable Entity | Subticket-Verknüpfung existiert schon, oder das Kind hat bereits ein anderes Elternticket |
500 |
Internal Server Error | Vorgang auf dem Server fehlgeschlagen |
501 |
Not Implemented | Subticket plugin not available |
departmentId, statusId, topicId und slaId akzeptieren einen Namen oder eine ID. Ein nicht numerischer Wert wird als Name gesucht (ohne Beachtung der Groß-/Kleinschreibung) und liefert 404, wenn nichts passt. Ein numerischer Wert, auch als String gesendet, wird immer als ID verwendet. staffId akzeptiert die Mitarbeiter-ID, den Benutzernamen oder die E-Mail-Adresse, nicht den Anzeigenamen.
Erstellt ein Ticket. Das Plugin ergänzt die Erstellungsparameter von osTicket um format, departmentId und parentTicketNumber.
POST /api/tickets.json
Berechtigung: Für diese Signal-Route prüft das Plugin selbst weder den API-Key noch die Berechtigung can_create_tickets. Ob der osTicket-Core den Key prüft, bevor er das Signal auslöst, lässt sich aus dem Code dieses Plugins nicht ableiten.
Sende den Body als JSON mit Content-Type: application/json.
| Parameter | Typ | Beschreibung | Beispiel |
|---|---|---|---|
format |
string | Nachrichtenformat: text, html oder markdown. Aliase: md für markdown, plain und txt für text |
"markdown" |
departmentId |
string oder int | Abteilungsname oder ID. Nur aktive Abteilungen, Unterabteilungen werden über ihren Namen gefunden | "Support" oder 5 |
parentTicketNumber |
string oder int | Nummer des Elterntickets (eine interne ID wird als Fallback akzeptiert). Das Elternticket muss existieren und darf selbst kein Kind sein | "181752" |
Alle anderen Felder verarbeitet die Ticketerstellung von osTicket selbst, zum Beispiel name, email, subject, message, topicId und attachments. Welche davon Pflicht sind, hängt vom Ticketformular deiner osTicket-Installation ab.
Anhänge werden als Array von Objekten übergeben, jeweils mit dem Dateinamen als Schlüssel und einer Base64-Data-URI als Wert:
{
"attachments": [
{"screenshot.png": "data:image/png;base64,iVBORw0KGgo..."},
{"report.pdf": "data:application/pdf;base64,JVBERi0xLjQ..."}
]
}
201 Created: die Ticketnummer als Klartext.
781258
# Einfaches Ticket
curl -X POST "https://osticket.local/api/tickets.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"subject": "Login Issue",
"message": "I cannot access my account"
}'
# Markdown-Nachricht, in eine Abteilung geroutet
curl -X POST "https://osticket.local/api/tickets.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Smith",
"email": "jane@example.com",
"subject": "Bug Report: Payment Failed",
"message": "## Problem\n\nPayment fails with error CARD_DECLINED.",
"format": "markdown",
"departmentId": "Billing"
}'
# Als Subticket eines bestehenden Tickets erstellen
curl -X POST "https://osticket.local/api/tickets.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Developer",
"email": "dev@example.com",
"subject": "Subtask: Database Migration",
"message": "Migrate the production database",
"parentTicketNumber": "181752",
"departmentId": "Development"
}'
format, unbekannte oder inaktive Abteilung, unbekanntes Elternticket) kommen als 400 mit einer Klartext-Meldung zurück, auch Fälle, die anderswo 404 wären.201.format=markdown ein 400 (Markdown Support plugin is required but not active), solange das Plugin Markdown Support nicht aktiv ist. Ist die Einstellung aus, wird der Wert ohne diese Prüfung durchgereicht.parentTicketNumber setzt nur den Verweis auf das Elternticket. Die eigenen Subticket-Endpunkte prüfen zusätzlich die Berechtigung can_manage_subtickets.Liefert ein Ticket samt Thread.
GET /api/tickets-get.php/{number}.{format}
Berechtigung: can_read_tickets
| Parameter | Typ | Beschreibung |
|---|---|---|
number |
string oder int | Ticketnummer. Hat kein Ticket diese Nummer, wird der Wert als interne Ticket-ID versucht |
format |
string | json oder xml |
{
"id": 123,
"number": "781258",
"subject": "Login Issue",
"statusId": 1,
"status": "Open",
"priorityId": 2,
"priority": "Normal",
"departmentId": 5,
"department": "IT Support",
"topicId": 10,
"topic": "Technical Support",
"userId": 45,
"user": {
"name": "John Doe",
"email": "john@example.com"
},
"staffId": 3,
"staff": "Jane Smith",
"teamId": 2,
"team": "Level 1 Support",
"slaId": 1,
"sla": "Standard SLA",
"created": "2025-11-08 10:30:00",
"updated": "2025-11-08 14:20:00",
"duedate": "2025-11-15 10:30:00",
"closed": null,
"isOverdue": false,
"isAnswered": true,
"source": "API",
"ip": "192.168.1.100",
"children": [124, 125],
"thread": [
{
"id": 456,
"type": "M",
"poster": "John Doe",
"timestamp": "2025-11-08 10:30:00",
"body": "I cannot access my account",
"userId": 45,
"attachments": [
{
"id": 12,
"file_id": 29,
"filename": "screenshot.png",
"size": 45320,
"mime_type": "image/png",
"inline": false
}
],
"attachment_count": 1
}
]
}
| Feld | Beschreibung |
|---|---|
thread[].type |
Thread-Eintragstyp, wie osTicket ihn speichert: M Nachricht, R Antwort, N interne Notiz |
thread[].staffId, thread[].staff |
Nur bei Einträgen eines Mitarbeiters vorhanden |
thread[].userId |
Nur bei Einträgen eines Benutzers vorhanden |
thread[].attachments, thread[].attachment_count |
Nur vorhanden, wenn der Eintrag Anhänge hat. file_id ist der Wert für den Attachment-Download |
children |
Interne IDs (nicht Nummern) der Kindtickets |
closed |
Schließdatum, nur wenn das Ticket geschlossen ist, sonst null |
curl "https://osticket.local/api/tickets-get.php/781258.json" \
-H "X-API-Key: YOUR_API_KEY"
Ändert Eigenschaften eines Tickets und fügt optional eine interne Notiz mit Anhängen hinzu.
PATCH /api/tickets-update.php/{number}.{format}
PUT /api/tickets-update.php/{number}.{format}
Dasselbe Update steht über die Route PATCH /api/tickets/{number}.json zur Verfügung (auch PUT, .xml wird akzeptiert). Diese Route antwortet bei Fehlern mit Klartext statt JSON.
Berechtigung: can_update_tickets
Sende den Body als JSON mit Content-Type: application/json. Gib nur die Felder an, die sich ändern sollen.
| Feld | Typ | Beschreibung |
|---|---|---|
statusId |
string oder int | Statusname oder ID |
departmentId |
string oder int | Abteilungsname oder ID |
topicId |
string oder int | Hilfethema-Name oder ID |
slaId |
string oder int | SLA-Plan-Name oder ID |
staffId |
string oder int | Mitarbeiter-ID, Benutzername oder E-Mail-Adresse |
dueDate |
string oder null | Fälligkeitsdatum in einem Format, das PHPs DateTime versteht, etwa 2025-12-31 oder 2025-12-31T17:30:00. null oder ein leerer String entfernt das Datum |
parentTicketNumber |
string | Ticketnummer des Elterntickets (macht das Ticket zum Subticket) |
note |
string | Interne Notiz. Wird als API gepostet und ist nur für Mitarbeiter sichtbar |
noteTitle |
string | Titel der Notiz, Standard API Update |
noteFormat |
string | Format der Notiz, Standard markdown |
attachments |
array | Anhänge der Notiz, gleiches Format wie beim Erstellen. Wird nur zusammen mit note verwendet, sonst stillschweigend ignoriert |
Andere Felder, auch priority, werden ohne Fehlermeldung ignoriert.
200 OK: die Ticketnummer als Klartext.
# Status ändern
curl -X PATCH "https://osticket.local/api/tickets-update.php/781258.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"statusId": "Resolved"}'
# Einem Mitarbeiter zuweisen, mit Notiz
curl -X PATCH "https://osticket.local/api/tickets-update.php/781258.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"staffId": "john.doe", "note": "Assigned to John for follow-up"}'
# Fälligkeitsdatum entfernen
curl -X PATCH "https://osticket.local/api/tickets-update.php/781258.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"dueDate": null}'
400. Ein Elternticket, das selbst ein Kind ist, liefert 400 (Parent ticket cannot be a child of another ticket).GET /api/tickets-search.php
Berechtigung: can_search_tickets oder can_read_tickets
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
query |
string | Suche im Ticket-Betreff, ohne Beachtung der Groß-/Kleinschreibung | |
status |
string oder int | Statusname oder ID | |
department |
string oder int | Abteilungsname, ID oder Pfad wie Development / osTicket |
|
limit |
int | 20 | Maximale Treffer. Werte unter 1 werden zu 20, Werte über 100 zu 100 |
offset |
int | 0 | Offset für die Paginierung |
sort |
string | created |
created (neueste zuerst), updated (zuletzt aktualisierte zuerst) oder number (aufsteigend). Andere Werte fallen auf created zurück |
Ein status- oder department-Name, der nichts trifft, wird ignoriert und filtert nicht.
Ein JSON-Array, nicht in ein Objekt verpackt. Die Einträge enthalten keinen Thread:
[
{
"id": 123,
"number": "781258",
"subject": "Login Issue",
"statusId": 1,
"status": "Open",
"priorityId": 2,
"priority": "Normal",
"departmentId": 5,
"department": "IT Support",
"topicId": 10,
"topic": "Technical Support",
"created": "2025-11-08 10:00:00",
"updated": "2025-11-08 14:30:00",
"dueDate": "2025-11-15 10:00:00",
"staffId": 3,
"staff": "Jane Smith",
"teamId": 2,
"team": "Level 1 Support",
"slaId": 1,
"sla": "Standard SLA",
"isOverdue": false,
"isAnswered": true
}
]
curl "https://osticket.local/api/tickets-search.php?query=login" \
-H "X-API-Key: YOUR_API_KEY"
curl "https://osticket.local/api/tickets-search.php?query=payment&status=Open&department=Support&limit=50&offset=50" \
-H "X-API-Key: YOUR_API_KEY"
Löscht ein Ticket endgültig.
Diese Aktion lässt sich nicht rückgängig machen. Das Ticket und sein Thread werden aus der Datenbank entfernt.
DELETE /api/tickets-delete.php/{number}.{format}
Berechtigung: can_delete_tickets, für jeden API-Key standardmäßig deaktiviert.
200 OK: die Nummer des gelöschten Tickets als Klartext.
curl -X DELETE "https://osticket.local/api/tickets-delete.php/781258.json" \
-H "X-API-Key: YOUR_API_KEY"
Erwäge statt des Löschens ein
PATCHauf einen geschlossenen Status.
GET /api/tickets-stats.php
Berechtigung: can_read_stats oder can_read_tickets
{
"total": 150,
"open": 45,
"closed": 105,
"overdue": 3,
"by_department": {
"Billing": {"total": 70, "open": 25, "closed": 45, "overdue": 2},
"Support": {"total": 80, "open": 20, "closed": 60, "overdue": 1}
},
"by_staff": [
{
"staff_id": 1,
"staff_name": "John Smith",
"total": 35,
"departments": {
"Support": {"open": 10, "closed": 20, "overdue": 0}
}
}
]
}
by_department ist ein Objekt mit dem Abteilungsnamen als Schlüssel, alphabetisch sortiert.by_staff ist ein nach Mitarbeitername sortiertes Array. Gezählt werden nur zugewiesene Tickets.GET /api/tickets-statuses.php
Berechtigung: can_read_stats oder can_read_tickets
[
{"id": 1, "name": "Open", "state": "open"},
{"id": 3, "name": "Closed", "state": "closed"}
]
Die Liste ist nach der Status-Reihenfolge sortiert und enthält auch eigene Status. state ist der osTicket-Zustand des Status.
Die Endpunkte 8 bis 11 setzen das Plugin Subticket Manager (Klasse SubticketPlugin) und die Berechtigung can_manage_subtickets voraus. Sie prüfen in dieser Reihenfolge: zuerst die Eingabe (eine ungültige Ticketnummer liefert 400, Endpunkt 10 liefert zusätzlich 400 bei fehlendem childId und beim Verknüpfen eines Tickets mit sich selbst), dann die Berechtigung (403, API key not authorized for subticket operations), dann das Plugin (501, Subticket plugin not available), dann die Ticket-Suche. Die Endpunkte 10 und 11 prüfen zusätzlich die Abteilung des Tickets, aber nur, wenn das API-Key-Objekt Abteilungsbeschränkungen liefert. Standard-API-Keys von osTicket haben keine.
GET /api/tickets-subtickets-parent.php/{number}.{format}
number ist die Nummer des Kindtickets.
{
"parent": {
"ticket_id": 100,
"number": "781200",
"subject": "Parent Ticket",
"status": "Open"
}
}
Liefert {"parent": null}, wenn das Ticket kein Elternticket hat. 404 (Child ticket not found), wenn das Ticket nicht existiert.
GET /api/tickets-subtickets-list.php/{number}.{format}
number ist die Nummer des Elterntickets.
{
"children": [
{"ticket_id": 124, "number": "781259", "subject": "Child Ticket 1", "status": "Open"},
{"ticket_id": 125, "number": "781260", "subject": "Child Ticket 2", "status": "Closed"}
]
}
Liefert {"children": []}, wenn es keine gibt. 404 (Parent ticket not found), wenn das Ticket nicht existiert.
Verknüpft zwei bestehende Tickets.
POST /api/tickets-subtickets-create.php/{parentNumber}.{format}
| Body-Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
childId |
string | Ja | Ticketnummer des Kindtickets |
curl -X POST "https://osticket.local/api/tickets-subtickets-create.php/781200.json" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"childId": "781259"}'
{
"success": true,
"message": "Subticket relationship created successfully",
"parent": {"ticket_id": 100, "number": "781200", "subject": "Parent Ticket", "status": "Open"},
"child": {"ticket_id": 124, "number": "781259", "subject": "Child Ticket", "status": "Open"}
}
| Code | Meldung | Ursache |
|---|---|---|
400 |
Missing childId in request body |
childId fehlt |
400 |
Cannot link ticket to itself |
Eltern- und Kindticket sind dasselbe Ticket |
403 |
Access denied to parent ticket department oder ... child ticket department |
Nur wenn das API-Key-Objekt Abteilungsbeschränkungen liefert, die die Abteilung ausschließen |
404 |
Parent ticket not found oder Child ticket not found |
Ticket existiert nicht |
422 |
Subticket relationship already exists |
Die Verknüpfung besteht schon |
422 |
Child ticket already has a different parent |
Das Kind hat ein anderes Elternticket |
Entfernt die Eltern-Verknüpfung eines Kindtickets.
DELETE /api/tickets-subtickets-unlink.php/{number}.{format}
number ist die Nummer des Kindtickets.
{
"success": true,
"message": "Subticket relationship removed successfully",
"child": {"ticket_id": 124, "number": "781259", "subject": "Child Ticket", "status": "Open"}
}
| Code | Meldung | Ursache |
|---|---|---|
403 |
Access denied to child ticket department |
Nur wenn das API-Key-Objekt Abteilungsbeschränkungen liefert, die die Abteilung ausschließen |
404 |
Child ticket not found |
Ticket existiert nicht |
404 |
Child has no parent to unlink |
Das Ticket hat kein Elternticket |
Liefert eine Datei als Base64 zusammen mit ihren Metadaten.
GET /api/tickets-attachment-download.php/{file_id}.{format}
Berechtigung: can_read_tickets
| Parameter | Typ | Beschreibung |
|---|---|---|
file_id |
integer | file_id aus den Anhang-Metadaten eines Thread-Eintrags, siehe GET Ticket abrufen |
format |
string | json oder xml |
{
"file_id": 29,
"filename": "screenshot.png",
"mime_type": "image/png",
"size": 45320,
"content": "iVBORw0KGgoAAAANSUhEUgAA..."
}
| Code | Meldung | Ursache |
|---|---|---|
400 |
Invalid file ID |
file_id kleiner als 1 |
403 |
Attachment not accessible |
In der Anhang-Tabelle existiert kein Eintrag mit dieser file_id |
404 |
File not found |
Datei existiert nicht |
500 |
Failed to read file content |
Dateiinhalt konnte nicht gelesen werden |
Bevor der Endpunkt eine Datei ausliefert, prüft er, dass in der Anhang-Tabelle ein Eintrag mit dieser
file_idexistiert. Die Prüfung filtert nicht nach dem Typ des Objekts, zu dem der Anhang gehört.
curl -s "https://osticket.local/api/tickets-attachment-download.php/29.json" \
-H "X-API-Key: YOUR_API_KEY" \
| jq -r '.content' \
| base64 -d > screenshot.png
Die ganze Datei wird in den Speicher gelesen und Base64-kodiert, wodurch die Antwort etwa ein Drittel größer ist als die Datei.
Das Plugin implementiert kein Rate Limiting. Wenn du es brauchst, richte es auf dem Webserver ein.