OTOBO / Znuny Web Services – REST API
In dieser ausführlichen Anleitung erfahren Sie, wie Sie die OTOBO REST API (Teil des Generischen Interface) aktivieren, konfigurieren und in eigene Anwendungen integrieren.
1. Architektur & Grundlagen
OTOBO stellt sein Generisches Interface über REST- und SOAP‑Webservices bereit. Die REST API kommuniziert via HTTP(S)/JSON und ermöglicht:
- Ticket‑Operationen: Anlegen, Abrufen, Ändern, Löschen
- Artikel‑Operationen: Posten, Anhänge verwalten
- Historie & Suche: Ticket‑Verlauf und komplexe Suchanfragen
Hinweis: Eine Standard‑Installation enthält keine vorkonfigurierten Webservices – Sie legen diese selbst im Admin‑Modul „Prozesse & Automation → Web Services“ an.
2. Konfiguration
2.1 Generic Interface aktivieren
- Im Admin‑Bereich → SysConfig → GenericInterface.Transport auf REST (HTTP) umstellen.
- Unter AdminGenericInterfaceTransportHTTPREST Timeouts, Host‑Header und Debug‑Level einstellen.
- In GenericInterface.Operation gewünschte Operationen (z. B.
TicketCreate
,TicketSearch
,TicketGet
,TicketUpdate
,TicketDelete
,TicketHistoryGet
) anlegen und aktivieren.
2.2 Basis‑URL & Authentifizierung
Basis‑URL
https://IHR-SERVER/otobo/nph-genericinterface.pl/Webservice/<IhrServiceName>/
Authentifizierung
- OTOBO‑Session‑Cookies
- API‑Keys / Token (über SysConfig anlegen)
- Immer HTTPS verwenden!
3. Endpunkte & HTTP‑Methoden (Detail)
Für jeden Endpunkt finden Sie hier eine detaillierte Übersicht zu Parametern, möglichen Antworten und Praxis‑Beispielen.
3.1 TicketCreate (POST)
URL: /Webservice/<ServiceName>/TicketCreate
Methode: POST
Beschreibung: Legt ein neues Ticket an und erstellt gleich einen Artikel.
Parameter | Typ | Pflicht | Beschreibung |
---|---|---|---|
SessionID | Integer | Ja¹ | Session-ID oder UserLogin+Password |
UserLogin | String | Ja² | Agenten-Login (in Kombination mit Password) |
Password | String | Ja² | Passwort (in Kombination mit UserLogin) |
Ticket.Title | String | Ja | Betreff des Tickets |
Ticket.Queue | String | Ja | Queue-Name oder Ticket.QueueID |
Ticket.State | String | Ja | Anfangszustand (z. B. new ) |
Ticket.Priority | String | Ja | Priorität (z. B. 3 normal ) |
Ticket.CustomerUser | String | Ja | Kunden-E-Mail oder Login |
Article.Subject | String | Ja | Betreff des ersten Artikels |
Article.Body | String | Ja | Inhalt des ersten Artikels |
Article.MimeType | String | Ja | text/plain oder text/html |
¹ Entweder SessionID ODER UserLogin+Password erforderlich. ² Wenn kein SessionID-Token vorliegt.
Beispiel Request:
http
POST /Webservice/MyConnectorREST/TicketCreate HTTP/1.1
Host: demo.otobo.org
Content-Type: application/json
X-API-Key: abc123
{
"Data": {
"SessionID": 42,
"Ticket": {
"Title": "Neue Bestellung",
"Queue": "Sales",
"State": "new",
"Priority": "3 normal",
"CustomerUser": "max.mustermann@example.com"
},
"Article": {
"Subject": "Kaufanfrage – Produkt XY",
"Body": "Bitte um Preisangebot…",
"MimeType": "text/plain"
}
}
}
Beispiel Antwort:
json
{
"Success": 1,
"ErrorMessage": "",
"Data": {
"TicketID": "12345",
"ArticleID": "67890"
}
}
3.2 TicketSearch (GET)
URL: /Webservice/<ServiceName>/TicketSearch
Methode: GET
Beschreibung: Sucht Tickets anhand vielfältiger Filterkriterien.
Parameter | Typ | Pflicht | Beschreibung |
---|---|---|---|
UserLogin, Password | String,String | Ja¹ | Agenten-Credentials oder SessionID² |
SessionID | Integer | Ja² | Token für authentifizierte Sitzungen |
Title | String/String[] | Nein | Wildcard-Suche im Titel (%Bestellung% ) |
TicketNumber | String/String[] | Nein | Ticketnummer(n) |
QueueIDs | Integer[] | Nein | Queue-IDs |
States | String[] | Nein | Zustände (new , open , …) |
StateType | String/String[] | Nein | Open/Closed-Kategorie |
DynamicField_Name.Op | Mixed | Nein | Dynamische Felder mit Operator (Equals, Like, GreaterThan …) |
¹ Entweder UserLogin+Password ODER SessionID. ² Wenn kein Login-Paar übergeben wird.
Beispiel Request:
http
GET /Webservice/MyConnectorREST/TicketSearch?UserLogin=agent1&Password=geheim&Title=%25Bestellung%25 HTTP/1.1
Host: demo.otobo.org
Beispiel Antwort:
json
{
"Success": 1,
"Data": {
"TicketID": [1001,1005,1012]
}
}
3.3 TicketGet (GET)
URL: /Webservice/<ServiceName>/TicketGet
Methode: GET
Beschreibung: Gibt detaillierte Ticket-Daten inklusive Artikel, Anhängen und dynamischen Feldern zurück.
Parameter | Typ | Pflicht | Beschreibung |
---|---|---|---|
UserLogin, Password | String,String | Ja¹ | Agenten-Credentials oder SessionID² |
SessionID | Integer | Ja² | Token für authentifizierte Sitzungen |
TicketID | String/String[] | Ja | Eine oder mehrere Ticket-IDs (komma-getrennt oder Array) |
DynamicFields | Boolean (0/1) | Nein | 1 = Dynamische Felder im Ergebnis, Default = 0 |
Extended | Boolean | Nein | 1 = Erweiterte Metadaten (z. B. FirstResponse) |
AllArticles | Boolean | Nein | 1 = Alle Artikel zurückliefern |
ArticleLimit | Integer | Nein | Max. Anzahl der zurückgegebenen Artikel |
Attachments | Boolean | Nein | 1 = Anhänge in Base64 einbetten |
GetAttachmentContents | Boolean | Nein | 1 = Inhalte der Anhänge ebenfalls laden |
HTMLBodyAsAttachment | Boolean | Nein | 1 = HTML-Version des Artikels als Attachment anfügen |
¹ Entweder UserLogin+Password ODER SessionID. ² Wenn kein Login-Paar übergeben wird.
Beispiel Request:
http
GET /Webservice/MyConnectorREST/TicketGet?SessionID=42&TicketID=12345&AllArticles=1&DynamicFields=1 HTTP/1.1
Host: demo.otobo.org
Beispiel Antwort (gekürzt):
json
{
"Success":1,
"Data":{
"Ticket":[{
"TicketID":12345,
"TicketNumber":"202501230001",
"Title":"Neue Bestellung",
"State":"open",
"DynamicField":[{"Name":"Urgency","Value":"high"}],
"Article":[{
"ArticleID":67890,
"Subject":"Kaufanfrage…",
"Body":"Bitte um Preisangebot…",
"Attachment":[{"Filename":"Angebot.pdf","Content":"JVBERi0x…="}]
}]
}]
}
}
3.4 TicketUpdate (PUT)
URL: /Webservice/<ServiceName>/TicketUpdate
Methode: PUT
Beschreibung: Aktualisiert Felder eines existierenden Tickets und optional einen neuen Artikel erstellt.
Parameter | Typ | Pflicht | Beschreibung |
---|---|---|---|
SessionID | Integer | Ja¹ | Token oder UserLogin+Password² |
TicketID | Integer | Ja | ID des zu aktualisierenden Tickets |
Ticket.Title | String | Nein | Neuer Titel |
Ticket.State | String | Nein | Neuer Status |
Ticket.Owner | String/ID | Nein | Neuer Besitzer |
Ticket.PendingTime | Hash / Diff | Nein | Neue Pending-Zeit |
Article.Subject | String | Nein | Erstellt einen neuen Artikel |
Article.Body | String | Nein | Inhalt des neuen Artikels |
DynamicField… | Array | Nein | Dynamische Felder aktualisieren |
Attachment… | Array | Nein | Neue Anhänge hinzufügen |
¹ Entweder SessionID ODER UserLogin+Password. ² Wenn kein SessionID-Token vorliegt.
Beispiel Request:
http
PUT /Webservice/MyConnectorREST/TicketUpdate HTTP/1.1
Host: demo.otobo.org
Content-Type: application/json
X-API-Key: abc123
{
"Data":{
"SessionID":42,
"TicketID":12345,
"Ticket":{ "State":"pending reminder","PendingTime":{"Diff":1440} },
"Article":{ "Subject":"Reminder gesetzt","Body":"Ticket wird bearbeitet." }
}
}
Beispiel Antwort:
json
{ "Success":1, "ErrorMessage":"", "Data":{ "TicketID":12345, "ArticleID":67891 } }
3.5 TicketDelete (DELETE)
URL: /Webservice/<ServiceName>/TicketDelete
Methode: DELETE
Beschreibung: Löscht ein oder mehrere Tickets endgültig.
Parameter | Typ | Pflicht | Beschreibung |
---|---|---|---|
SessionID | Integer | Ja¹ | Token oder UserLogin+Password² |
TicketID | String/Array | Ja | Ein oder mehrere Ticket-IDs |
Beispiel Request:
http
DELETE /Webservice/MyConnectorREST/TicketDelete?SessionID=42&TicketID=12345 HTTP/1.1
Host: demo.otobo.org
Beispiel Antwort:
json
{ "Success":1, "ErrorMessage":"", "Data":{} }
3.6 TicketHistoryGet (GET)
URL: /Webservice/<ServiceName>/TicketHistoryGet
Methode: GET
Beschreibung: Ruft die Historie eines oder mehrerer Tickets ab.
Parameter | Typ | Pflicht | Beschreibung |
---|---|---|---|
SessionID | Integer | Ja¹ | Token oder UserLogin+Password² |
TicketID | String/Array | Ja | Ein oder mehrere Ticket-IDs |
Beispiel Request:
http
GET /Webservice/MyConnectorREST/TicketHistoryGet?SessionID=42&TicketID=12345,
5. Erweiterung & Anpassung
5.1 WADL‑Definition
Neue Ressourcen in GenericTicketConnectorREST.wadl
:
xml
<resource path="MyTest" id="MyTest">
<method name="GET" id="GET_MyTest">
<response status="200">
<representation mediaType="application/json"/>
</response>
</method>
</resource>
5.2 YAML‑Import
Alternativ per YAML in development/webservices/GenericTicketConnectorREST.yml
:
yaml
Provider:
Operation:
MyTest:
Description: "Testoperation"
MappingInbound: { }
MappingOutbound: { }
Type: Test::Module
Transport:
Config:
RouteOperationMapping:
MyTest:
RequestMethod: [ GET ]
Route: /MyTest
6. Fehlerbehandlung & Logging
- Erfolgsindikator:
Success: 0|1
- Fehlermeldung:
ErrorMessage
im JSON - Debugging: Setzen Sie im Transport‑Dialog
Debug-Level
aufDebug
→ Log‑Einträge in DB sichtbar
7. Anwendungsfälle
Scenario | Beschreibung |
---|---|
Systemübergreifende Automatisierung | Tickets aus Monitoring‑Tools (Nagios, Zabbix) erstellen |
Datensynchronisation | Batch‑Updates von Ticket‑Feldern aus externem CRM |
Self‑Service‑Portale | Kunden legen eigene Tickets via REST an |
Mobile Apps | Native iOS/Android‑Apps kommunizieren per REST |
8. Weitere UI‑Elemente & Integration
Web Service Klonen
Error Handling Modul
Fazit
Die OTOBO REST API ist flexibel, performant und dank Generischem Interface hochgradig erweiterbar. Ob einfache Ticket‑Erstellung oder komplexe Workflow‑Automatisierung – mit wenigen Klicks im Admin und Standard‑JSON‑Requests realisieren Sie nahtlose Integrationen in jede IT‑Landschaft.
Python OTOBO Client Library
An asynchronous Python client for interacting with the OTOBO REST API. Built with httpx
and pydantic
for type safety and ease of use.
Features
Asynchronous HTTP requests using
httpx.AsyncClient
Pydantic models for request and response data validation
Full CRUD operations for tickets:
TicketCreate
TicketSearch
TicketGet
TicketUpdate
TicketHistoryGet
Error handling via
OTOBOError
for API errorsUtility method
search_and_get
to combine search results with detailed retrieval
Installation
Install from PyPI:
bash
pip install otobo
Quickstart
Setup OTOBO Webservices:
Create a new web service in OTOBO with the following configuration:
yaml
---
Debugger:
DebugThreshold: debug
TestMode: '0'
Description: ''
FrameworkVersion: 11.0.5
Provider:
Operation:
session-create:
Description: ''
IncludeTicketData: '0'
MappingInbound:
Type: Simple
MappingOutbound:
Type: Simple
Type: Session::SessionCreate
ticket-create:
Description: ''
IncludeTicketData: '1'
MappingInbound:
Type: Simple
MappingOutbound:
Type: Simple
Type: Ticket::TicketCreate
ticket-get:
Description: ''
IncludeTicketData: '0'
MappingInbound:
Config:
KeyMapDefault:
MapTo: ''
MapType: Keep
ValueMapDefault:
MapTo: ''
MapType: Keep
Type: Simple
MappingOutbound:
Type: Simple
Type: Ticket::TicketGet
ticket-history-get:
Description: ''
IncludeTicketData: '0'
MappingInbound:
Type: Simple
MappingOutbound:
Type: Simple
Type: Ticket::TicketHistoryGet
ticket-search:
Description: ''
IncludeTicketData: '0'
MappingInbound:
Type: Simple
MappingOutbound:
Type: Simple
Type: Ticket::TicketSearch
ticket-update:
Description: ''
IncludeTicketData: '1'
MappingInbound:
Type: Simple
MappingOutbound:
Type: Simple
Type: Ticket::TicketUpdate
Transport:
Config:
AdditionalHeaders: ~
KeepAlive: '1'
MaxLength: '16000'
RouteOperationMapping:
session-create:
RequestMethod:
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
Route: /session
ticket-create:
RequestMethod:
- HEAD
- OPTIONS
- POST
Route: /ticket
ticket-get:
RequestMethod:
- HEAD
- OPTIONS
- POST
Route: /ticket/get
ticket-history-get:
RequestMethod:
- HEAD
- OPTIONS
- POST
Route: /ticket/history
ticket-search:
RequestMethod:
- HEAD
- OPTIONS
- POST
Route: /ticket/search
ticket-update:
RequestMethod:
- HEAD
- OPTIONS
- PATCH
- PUT
Route: /ticket
Type: HTTP::REST
RemoteSystem: ''
Requester:
Transport:
Type: HTTP::REST
Create a new Agent
Create a new Otobo Agent with a secure password and give it the permissions needed for the thing you want to accomplish.
1. Configure the client
python
from otobo import TicketOperation, OTOBOClientConfig
from otobo import AuthData
config = OTOBOClientConfig(
base_url="https://your-otobo-server/nph-genericinterface.pl",
service="OTOBO",
auth=AuthData(UserLogin="user1", Password="SecurePassword"),
operations={
TicketOperation.CREATE.value: "ticket",
TicketOperation.SEARCH.value: "ticket/search",
TicketOperation.GET.value: "ticket/get",
TicketOperation.UPDATE.value: "ticket",
TicketOperation.HISTORY_GET.value: "ticket/history",
}
)
2. Initialize the client
python
import logging
from otobo import OTOBOClient
logging.basicConfig(level=logging.INFO)
client = OTOBOClient(config)
3. Create a ticket
python
from otobo import (TicketOperation, OTOBOClientConfig, AuthData, TicketSearchParams, TicketCreateParams,
TicketHistoryParams, TicketUpdateParams, \
TicketGetParams, OTOBOClient, OTOBOTicketCreateResponse)
payload = TicketCreateParams(
Ticket={
"Title": "New Order",
"Queue": "Sales",
"State": "new",
"Priority": "3 normal",
"CustomerUser": "customer@example.com"
},
Article={
"Subject": "Product Inquiry",
"Body": "Please send pricing details...",
"MimeType": "text/plain"
}
)
response: OTOBOTicketCreateResponse = await client.create_ticket(payload)
print(response.TicketID, response.TicketNumber)
4. Search and retrieve tickets
python
from otobo import TicketSearchParams, TicketGetParams
search_params = TicketSearchParams(Title="%Order%")
search_res = await client.search_tickets(search_params)
ids = search_res.TicketID
for ticket_id in ids:
get_params = TicketGetParams(TicketID=ticket_id, AllArticles=1)
details = await client.get_ticket(get_params)
print(details.Ticket[0])
5. Update a ticket
python
from otobo import TicketUpdateParams
update_params = TicketUpdateParams(
TicketID=response.TicketID,
Ticket={"State": "closed"}
)
await client.update_ticket(update_params)
6. Get ticket history
python
from otobo import TicketHistoryParams
history_params = TicketHistoryParams(TicketID=str(response.TicketID))
history_res = await client.get_ticket_history(history_params)
print(history_res.History)
7. Combined search and get
python
from otobo import FullTicketSearchResponse
full_res: FullTicketSearchResponse = await client.search_and_get(search_params)
License
MIT © Softoft, Tobias A. Bueck