Skip to content

OTOBO / Znuny Web Services – REST API

OTOBO REST API

In this detailed guide, you will learn how to activate, configure, and integrate the OTOBO REST API (part of the Generic Interface) into your own applications.

1. Architecture & Basics

OTOBO provides its Generic Interface via REST and SOAP web services. The REST API communicates via HTTP(S)/JSON and allows for:

  • Ticket Operations: Create, retrieve, modify, delete
  • Article Operations: Post, manage attachments
  • History & Search: Ticket history and complex search queries

Note: A standard installation does not include any pre-configured web services – you create them yourself in the admin module "Processes & Automation → Web Services".

2. Configuration

2.1 Activating the Generic Interface

  1. In the admin area → SysConfigGenericInterface.Transport, switch to REST (HTTP).
  2. Under AdminGenericInterfaceTransportHTTPREST, set timeouts, host headers, and the debug level.
  3. In GenericInterface.Operation, create and activate the desired operations (e.g., TicketCreate, TicketSearch, TicketGet, TicketUpdate, TicketDelete, TicketHistoryGet).

Add Web ServiceWeb Service Provider

2.2 Base URL & Authentication

  • Base URL

    https://YOUR-SERVER/otobo/nph-genericinterface.pl/Webservice/<YourServiceName>/
  • Authentication

    • OTOBO session cookies
    • API Keys / Tokens (create via SysConfig)
    • Always use HTTPS!

Set up REST Requester

3. Endpoints & HTTP Methods (Details)

For each endpoint, you will find a detailed overview of parameters, possible responses, and practical examples.

3.1 TicketCreate (POST)

URL: /Webservice/<ServiceName>/TicketCreateMethod: POST

Description: Creates a new ticket and an initial article.

ParameterTypeRequiredDescription
SessionIDIntegerYes¹Session ID or UserLogin+Password
UserLoginStringYes²Agent login (in combination with Password)
PasswordStringYes²Password (in combination with UserLogin)
Ticket.TitleStringYesSubject of the ticket
Ticket.QueueStringYesQueue name or Ticket.QueueID
Ticket.StateStringYesInitial state (e.g., new)
Ticket.PriorityStringYesPriority (e.g., 3 normal)
Ticket.CustomerUserStringYesCustomer email or login
Article.SubjectStringYesSubject of the first article
Article.BodyStringYesContent of the first article
Article.MimeTypeStringYestext/plain or text/html

¹ Either SessionID OR UserLogin+Password is required. ² If no SessionID token is provided.

Example 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":        "New Order",
      "Queue":        "Sales",
      "State":        "new",
      "Priority":     "3 normal",
      "CustomerUser": "max.mustermann@example.com"
    },
    "Article": {
      "Subject":  "Purchase Inquiry – Product XY",
      "Body":     "Please provide a price quote…",
      "MimeType": "text/plain"
    }
  }
}

Example Response:

json
{
  "Success":      1,
  "ErrorMessage": "",
  "Data": {
    "TicketID":     "12345",
    "ArticleID":    "67890"
  }
}

3.2 TicketSearch (GET)

URL: /Webservice/<ServiceName>/TicketSearchMethod: GET

Description: Searches for tickets based on various filter criteria.

ParameterTypeRequiredDescription
UserLogin, PasswordString,StringYes¹Agent credentials or SessionID²
SessionIDIntegerYes²Token for authenticated sessions
TitleString/String[]NoWildcard search in the title (%Order%)
TicketNumberString/String[]NoTicket number(s)
QueueIDsInteger[]NoQueue IDs
StatesString[]NoStates (new, open, …)
StateTypeString/String[]NoOpen/Closed category
DynamicField_Name.OpMixedNoDynamic fields with an operator (Equals, Like, GreaterThan…)

¹ Either UserLogin+Password OR SessionID. ² If no login pair is provided.

Example Request:

http
GET /Webservice/MyConnectorREST/TicketSearch?UserLogin=agent1&Password=secret&Title=%25Order%25 HTTP/1.1
Host: demo.otobo.org

Example Response:

json
{
  "Success": 1,
  "Data": {
    "TicketID": [1001,1005,1012]
  }
}

3.3 TicketGet (GET)

URL: /Webservice/<ServiceName>/TicketGetMethod: GET

Description: Returns detailed ticket data including articles, attachments, and dynamic fields.

ParameterTypeRequiredDescription
UserLogin, PasswordString,StringYes¹Agent credentials or SessionID²
SessionIDIntegerYes²Token for authenticated sessions
TicketIDString/String[]YesOne or more Ticket IDs (comma-separated or as an array)
DynamicFieldsBoolean (0/1)No1 = Include dynamic fields in the result, Default = 0
ExtendedBooleanNo1 = Extended metadata (e.g., FirstResponse)
AllArticlesBooleanNo1 = Return all articles
ArticleLimitIntegerNoMax. number of articles to return
AttachmentsBooleanNo1 = Embed attachments in Base64
GetAttachmentContentsBooleanNo1 = Also load the content of the attachments
HTMLBodyAsAttachmentBooleanNo1 = Append the HTML version of the article as an attachment

¹ Either UserLogin+Password OR SessionID. ² If no login pair is provided.

Example Request:

http
GET /Webservice/MyConnectorREST/TicketGet?SessionID=42&TicketID=12345&AllArticles=1&DynamicFields=1 HTTP/1.1
Host: demo.otobo.org

Example Response (abbreviated):

json
{
  "Success":1,
  "Data":{
    "Ticket":[{  
      "TicketID":12345,
      "TicketNumber":"202501230001",
      "Title":"New Order",
      "State":"open",
      "DynamicField":[{"Name":"Urgency","Value":"high"}],
      "Article":[{  
        "ArticleID":67890,
        "Subject":"Purchase Inquiry…",
        "Body":"Please provide a price quote…",
        "Attachment":[{"Filename":"Offer.pdf","Content":"JVBERi0x…="}]
      }]
    }]
  }
}

3.4 TicketUpdate (PUT)

URL: /Webservice/<ServiceName>/TicketUpdateMethod: PUT

Description: Updates fields of an existing ticket and optionally creates a new article.

ParameterTypeRequiredDescription
SessionIDIntegerYes¹Token or UserLogin+Password²
TicketIDIntegerYesID of the ticket to be updated
Ticket.TitleStringNoNew title
Ticket.StateStringNoNew status
Ticket.OwnerString/IDNoNew owner
Ticket.PendingTimeHash / DiffNoNew pending time
Article.SubjectStringNoCreates a new article
Article.BodyStringNoContent of the new article
DynamicField…ArrayNoUpdate dynamic fields
Attachment…ArrayNoAdd new attachments

¹ Either SessionID OR UserLogin+Password. ² If no SessionID token is provided.

Example 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 set","Body":"Ticket is being processed." }
  }
}

Example Response:

json
{ "Success":1, "ErrorMessage":"", "Data":{ "TicketID":12345, "ArticleID":67891 } }

3.5 TicketDelete (DELETE)

URL: /Webservice/<ServiceName>/TicketDeleteMethod: DELETE

Description: Permanently deletes one or more tickets.

ParameterTypeRequiredDescription
SessionIDIntegerYes¹Token or UserLogin+Password²
TicketIDString/ArrayYesOne or more Ticket IDs

Example Request:

http
DELETE /Webservice/MyConnectorREST/TicketDelete?SessionID=42&TicketID=12345 HTTP/1.1
Host: demo.otobo.org

Example Response:

json
{ "Success":1, "ErrorMessage":"", "Data":{} }

3.6 TicketHistoryGet (GET)

URL: /Webservice/<ServiceName>/TicketHistoryGetMethod: GET

Description: Retrieves the history of one or more tickets.

ParameterTypeRequiredDescription
SessionIDIntegerYes¹Token or UserLogin+Password²
TicketIDString/ArrayYesOne or more Ticket IDs

Example Request:

http
GET /Webservice/MyConnectorREST/TicketHistoryGet?SessionID=42&TicketID=12345,

5. Extension & Customization

5.1 WADL Definition

New resources 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

Alternatively, via YAML in development/webservices/GenericTicketConnectorREST.yml:

yaml
Provider:
  Operation:
    MyTest:
      Description: "Test operation"
      MappingInbound: { }
      MappingOutbound: { }
      Type: Test::Module
Transport:
  Config:
RouteOperationMapping:
  MyTest:
    RequestMethod: [ GET ]
    Route: /MyTest

Add SOAP Provider


6. Error Handling & Logging

  • Success Indicator: Success: 0|1
  • Error Message: ErrorMessage in the JSON
  • Debugging: In the transport dialog, set Debug-Level to Debug → Log entries become visible in the DB

Web Service Debugger


7. Use Cases

ScenarioDescription
Cross-System AutomationCreate tickets from monitoring tools (Nagios, Zabbix)
Data SynchronizationBatch updates of ticket fields from an external CRM
Self-Service PortalsCustomers create their own tickets via REST
Mobile AppsNative iOS/Android apps communicate via REST

8. Additional UI Elements & Integration

Clone Web Service

Clone Web Service

Error Handling Module

Error Handling Module

Conclusion

The OTOBO REST API is flexible, performant, and highly extensible thanks to the Generic Interface. Whether for simple ticket creation or complex workflow automation, you can achieve seamless integrations into any IT landscape with just a few clicks in the admin panel and standard JSON requests.

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 errors

  • Utility 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