Skip to content

Extend the OTOBO REST API with Custom Generic Interface Operations

In this guide: Extend the OTOBO Generic Interface with secure custom REST operations, using the OpenTicketAIConnector catalogue endpoints as a practical package pattern.

Related: OTOBO REST API · Web Services · Plugin development

The standard OTOBO REST API covers common ticket operations such as TicketCreate, TicketGet, and TicketSearch. A custom integration may also need endpoints for queue metadata, Dynamic Field values, configuration data, or domain-specific actions. Those endpoints belong in a packaged OTOBO Generic Interface extension—not in a YAML mapping alone.

Need a custom OTOBO REST API operation?

Softoft develops Generic Interface operations, secure webservices, OTOBO packages, tests, deployment, and handover documentation.

Book a 15-minute introductory call if you already know which data or action your endpoint must expose.

A custom REST surface consists of four connected layers:

LayerWhat you addWhen it runs
OperationKernel/GenericInterface/Operation/<Controller>/<Name>.pmEvery request
RegistrationGenericInterface::Operation::Module###… in SysConfig XMLConfiguration reload
WebserviceProvider operation and RouteOperationMapping in YAMLREST request routing
Package.sopm file list and install/upgrade hooksPackage lifecycle
flowchart LR
  client[HTTPClient] --> gi["Generic Interface HTTP REST"]
  gi --> route[WebserviceRoute]
  route --> operation[PerlOperation]
  operation --> core["OTOBO Kernel System APIs"]
  operation --> response[JSONResponse]

Skip one layer and the operation either does not appear in Admin → Web Services, returns a 404, or disappears after the next package installation.

The examples below use TicketAICatalog::QueueList, a real pattern from OpenTicketAIConnector. Replace the controller, operation name, user, and webservice name with values owned by your package.

  • Package: Kernel::GenericInterface::Operation::<Controller>::<Name>
  • File: Kernel/GenericInterface/Operation/<Controller>/<Name>.pm
  • Generic Interface type: <Controller>::<Name>

Operation classes inherit from Kernel::GenericInterface::Operation::Common, which provides Auth and ReturnError. A shared base class is useful once multiple operations need the same authentication and validation.

package Kernel::GenericInterface::Operation::TicketAICatalog::Base;
use strict;
use warnings;
use parent qw(Kernel::GenericInterface::Operation::Common);
our $ObjectManagerDisabled = 1;
sub new {
my ( $Type, %Param ) = @_;
my $Self = {};
bless $Self, $Type;
for my $Needed (qw(DebuggerObject WebserviceID)) {
return if !$Param{$Needed};
$Self->{$Needed} = $Param{$Needed};
}
return $Self;
}
sub _AuthOrError {
my ( $Self, %Param ) = @_;
my ( $UserID, $UserType ) = $Self->Auth(%Param);
return ( $UserID, undef ) if $UserID;
return (
undef,
$Self->ReturnError(
ErrorCode => 'TicketAICatalog.AuthFail',
ErrorMessage => 'Authentication failed!',
),
);
}
1;

$ObjectManagerDisabled = 1 matters because Generic Interface operation objects are created outside the normal object-manager factory path.

Use OTOBO kernel APIs through $Kernel::OM. Keep request validation and response shapes explicit.

package Kernel::GenericInterface::Operation::TicketAICatalog::QueueList;
use strict;
use warnings;
use parent qw(Kernel::GenericInterface::Operation::TicketAICatalog::Base);
our $ObjectManagerDisabled = 1;
sub Run {
my ( $Self, %Param ) = @_;
my ( $UserID, $Error ) = $Self->_AuthOrError(%Param);
return $Error if $Error;
my $QueueObject = $Kernel::OM->Get('Kernel::System::Queue');
my %Queues = $QueueObject->QueueList( Valid => 0 );
my @Items;
for my $QueueID ( sort { $a <=> $b } keys %Queues ) {
my %Queue = $QueueObject->QueueGet( ID => $QueueID );
next if !%Queue;
push @Items, {
ID => $QueueID + 0,
Name => $Queue{Name} // $Queues{$QueueID},
Comment => $Queue{Comment} // '',
Valid => ( ( $Queue{ValidID} // 1 ) == 1 ) ? 1 : 0,
};
}
return { Success => 1, Data => { Item => \@Items } };
}
1;

Read decoded JSON or query parameters from $Param{Data}. Credentials remain sibling keys consumed by Auth.

my $Data = $Param{Data} || {};
my $Name = $Data->{Name} // '';
return $Self->ReturnError(
ErrorCode => 'TicketAICatalog.MissingName',
ErrorMessage => 'Name is required.',
) if !$Name;

Prefer idempotent, read-only operations. Put mutations behind explicit routes, validate every field, and restrict them to a dedicated API user.

Step 2 — Register the operation in SysConfig

Section titled “Step 2 — Register the operation in SysConfig”

OTOBO discovers operation modules through settings named:

GenericInterface::Operation::Module###<Controller>::<Name>

Register each type in an XML file under Kernel/Config/Files/XML/:

<?xml version="1.0" encoding="utf-8"?>
<otobo_config version="2.0" init="Application">
<Setting Name="GenericInterface::Operation::Module###TicketAICatalog::QueueList"
Required="0" Valid="1">
<Description Translatable="1">Catalogue: list queues.</Description>
<Navigation>GenericInterface::Operation::ModuleRegistration</Navigation>
<Value>
<Hash>
<Item Key="Name">QueueList</Item>
<Item Key="Controller">TicketAICatalog</Item>
<Item Key="ConfigDialog">AdminGenericInterfaceOperationDefault</Item>
</Hash>
</Value>
</Setting>
</otobo_config>

After installation and configuration rebuild, TicketAICatalog::QueueList should appear as an operation type in the webservice administration screen.

Step 3 — Map the operation to a REST route

Section titled “Step 3 — Map the operation to a REST route”

Registration makes the backend selectable. The webservice YAML exposes it over HTTP:

Provider:
Operation:
queue-list:
Type: TicketAICatalog::QueueList
Description: Lists queues with ID, name, comment, and validity.
MappingInbound:
Type: Simple
Config:
KeyMapDefault:
MapTo: ""
MapType: Keep
ValueMap:
UserLogin:
ValueMapRegEx:
.*: custom-api-user
MappingOutbound:
Type: Simple
Config:
KeyMapDefault:
MapTo: ""
MapType: Keep
Transport:
Type: HTTP::REST
Config:
MaxLength: "1000000"
RouteOperationMapping:
queue-list:
Route: /queue-list
RequestMethod:
- GET
- POST

The operation key under Provider.Operation must exactly match the key under RouteOperationMapping. An inbound login rewrite can force every request to use a restricted API agent, but it does not replace HTTPS, a strong password, group permissions, input validation, and network controls.

Step 4 — Package and install the extension

Section titled “Step 4 — Package and install the extension”

Every Perl, XML, and YAML file must be listed in the .sopm; otherwise it never reaches the target system.

<Filelist>
<File Permission="644"
Location="Kernel/GenericInterface/Operation/TicketAICatalog/Base.pm"/>
<File Permission="644"
Location="Kernel/GenericInterface/Operation/TicketAICatalog/QueueList.pm"/>
<File Permission="644"
Location="Kernel/Config/Files/XML/MyConnector.xml"/>
<File Permission="644"
Location="var/webservices/examples/MyConnector.yml"/>
</Filelist>

Use package lifecycle hooks to create the restricted API user and import or update the packaged YAML:

<CodeInstall Type="post"><![CDATA[
$Kernel::OM->Get('Kernel::System::MyConnector::Setup')->Install();
]]></CodeInstall>
<CodeReinstall Type="post"><![CDATA[
$Kernel::OM->Get('Kernel::System::MyConnector::Setup')->Install();
]]></CodeReinstall>
<CodeUpgrade Type="post"><![CDATA[
$Kernel::OM->Get('Kernel::System::MyConnector::Setup')->Install();
]]></CodeUpgrade>
<CodeUninstall Type="pre"><![CDATA[
$Kernel::OM->Get('Kernel::System::MyConnector::Setup')->Uninstall();
]]></CodeUninstall>

On upgrades, update the database webservice from the packaged YAML. This ensures new routes arrive without manual admin clicks.

The final URL has this shape:

https://helpdesk.example/otobo/nph-genericinterface.pl/Webservice/MyConnector/queue-list

Smoke-test authentication, method, route, and JSON:

Terminal window
curl -sS -u 'custom-api-user:API_PASSWORD' \
-X POST \
'https://helpdesk.example/otobo/nph-genericinterface.pl/Webservice/MyConnector/queue-list'

Test success and stable errors, unauthorized access, invalid input, empty results, large responses, and package upgrades. Client code should depend on documented response contracts rather than internal Perl classes.

  1. Add the operation .pm with new, Run, authentication, validation, and a stable Data shape.
  2. Register GenericInterface::Operation::Module###<Controller>::<Name> in SysConfig XML.
  3. Add the provider operation and REST route to the packaged YAML.
  4. Add every file to the .sopm and bump the package version.
  5. Import or update the webservice in install and upgrade hooks.
  6. Assign the API user only the groups and queues the endpoint requires.
  7. Add unit, integration, authorization, and upgrade tests.
  8. Verify the operation in Admin → Web Services and smoke-test it over HTTPS.
  • Operation missing in Admin: Check the XML setting name, controller, operation name, package file list, and configuration rebuild.
  • HTTP 404: The YAML was not imported, or the operation key does not match RouteOperationMapping.
  • Authentication failed: Credentials do not match the user forced by inbound mapping, or the API user lacks required permissions.
  • Empty Item: Check Valid filters and the API user’s group and queue permissions.
  • Unexpected response: Use the Generic Interface debugger to inspect mapped request and response data.
  • Upgrade omitted a route: Ensure the upgrade hook reimports the complete packaged YAML through WebserviceUpdate.

Custom operations are production code inside your ticket system. They need secure authorization, stable contracts, package lifecycle handling, tests, and an upgrade strategy—not just a working Perl module.

Let Softoft build and maintain your OTOBO REST extension

From requirements and operation design through package delivery, deployment, documentation, and maintenance.

Book a 15-minute call to discuss the endpoints, connected system, and deployment environment.

Frequently asked questions

Can the OTOBO REST API be extended with custom endpoints?

Yes. Add a Generic Interface operation module, register it in SysConfig, map it to a REST route, and ship all files in an OTOBO package.

Why does a custom operation not appear in Admin → Web Services?

The operation is usually missing its GenericInterface::Operation::Module SysConfig registration, or the package and configuration were not rebuilt after installation.

Can Softoft develop and maintain a custom OTOBO REST API extension?

Yes. Softoft offers custom Generic Interface operation, webservice, package, testing, deployment, and maintenance services.