Skip to content

Extend the Znuny REST API with Custom Generic Interface Operations

In this guide: Add secure custom REST operations to the Znuny Generic Interface, with the OpenTicketAIConnector catalogue operations as a real-world package example.

Related: Znuny REST API · Web Services · Plugin development

Znuny’s Generic Interface includes standard ticket operations, but integrations often need data or actions those operations do not expose: queue details, Dynamic Field option lists, configuration catalogues, or application-specific commands. A maintainable Znuny REST API extension combines Perl code, SysConfig registration, REST routing, package lifecycle management, and permissions.

Need a custom Znuny REST endpoint?

Softoft develops secure Generic Interface operations, Znuny packages, automated tests, deployment, and maintainable API contracts.

Book a 15-minute introductory call to discuss the connected system and required operations.

How a Znuny custom operation fits together

Section titled “How a Znuny custom operation fits together”
flowchart LR
  client[IntegrationClient] --> transport["Generic Interface REST Transport"]
  transport --> mapping[WebserviceRoute]
  mapping --> operation[CustomPerlOperation]
  operation --> znunyCore["Znuny Kernel System APIs"]
  operation --> json[StableJSONContract]

Four artifacts must agree:

  1. Perl operation — receives mapped request data, authenticates, calls Znuny kernel APIs, and returns a stable result.
  2. SysConfig XML — registers the controller and operation so it appears in the admin interface.
  3. Webservice YAML — associates the operation type with a REST path and HTTP methods.
  4. Znuny package — installs every file and imports or upgrades the webservice configuration.

The examples use controller TicketAICatalog from OpenTicketAIConnector. It provides catalogue data that standard ticket operations do not cover well. Your package should use its own controller and webservice name.

Step 1 — Implement the operation backend

Section titled “Step 1 — Implement the operation backend”
Class: Kernel::GenericInterface::Operation::<Controller>::<Name>
File: Kernel/GenericInterface/Operation/<Controller>/<Name>.pm
Type: <Controller>::<Name>

Generic Interface operation classes inherit from Kernel::GenericInterface::Operation::Common. It provides authentication and structured errors.

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 is required for these operation classes. Use a shared base only for behavior genuinely shared by multiple endpoints.

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;

Mapped request fields are available through $Param{Data}. Validate required fields before calling a kernel API and return stable error codes with ReturnError.

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

Read-only catalogue operations are safest. For mutations, enforce type and value checks, make repeated requests idempotent where possible, and use explicit routes.

Step 2 — Register the module in Znuny SysConfig

Section titled “Step 2 — Register the module in Znuny SysConfig”

Znuny looks for settings named:

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

Use the Znuny/OTRS-compatible <otrs_config> root:

<?xml version="1.0" encoding="utf-8"?>
<otrs_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>
</otrs_config>

After package installation and configuration rebuild, verify that TicketAICatalog::QueueList is selectable in Admin → Web Services.

Declare the operation and route in the packaged webservice YAML:

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 queue-list keys must match. Use a dedicated API agent with minimum group and queue permissions. The login rewrite is an additional restriction, not a replacement for HTTPS, strong credentials, network controls, and input validation.

Step 4 — Build the Znuny package lifecycle

Section titled “Step 4 — Build the Znuny package lifecycle”

Znuny package manifests use an <otrs_package> root. Declare Framework versions that match the Znuny releases you actually test and support. Include every backend, XML, YAML, and setup file:

<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/MyZnunyConnector.xml"/>
<File Permission="644"
Location="var/webservices/MyZnunyConnector.yml"/>
</Filelist>

Install, reinstall, and upgrade hooks should call a Znuny-specific setup module:

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

The setup module should create or update the restricted API user and import the YAML through Kernel::System::GenericInterface::Webservice. On package upgrades, update the existing webservice instead of creating a duplicate.

The installation path can be /znuny/ or /otrs/; use the path configured in your environment:

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

Test the package on every claimed Znuny Framework version. Cover valid responses, authentication failure, insufficient queue permissions, invalid input, empty data, response size, reinstall, upgrade, and uninstall.

  1. Add the operation module with authentication, validation, and a stable Data contract.
  2. Register the type in an <otrs_config> SysConfig XML file.
  3. Add matching provider-operation and route keys to the webservice YAML.
  4. Add every file to the <otrs_package> manifest and declare tested Framework versions.
  5. Import or update the webservice during package install and upgrade.
  6. Restrict the API user to required groups, queues, and actions.
  7. Test the package and operation on every supported Znuny release.
  8. Confirm the operation in Admin → Web Services and smoke-test via HTTPS.
  • Operation is absent: Check SysConfig XML, Controller, Name, package file list, and configuration rebuild.
  • Route returns 404: The YAML was not imported or route and operation keys differ.
  • Authentication fails: Basic Auth credentials do not match the mapped API login.
  • Operation returns no data: Check Valid flags and group/queue permissions.
  • Package works only on one release: Review the manifest Framework tags and test kernel API compatibility.
  • Upgrade misses new routes: Ensure setup loads the complete packaged YAML and calls WebserviceUpdate.

A durable extension needs more than a Perl proof of concept: contract design, least-privilege access, package compatibility, automated tests, upgrade handling, and operational documentation.

Let Softoft build your Znuny Generic Interface extension

Custom operation design, Perl implementation, webservice configuration, packaging, deployment, testing, and ongoing maintenance.

Book a 15-minute call to review the endpoints, Znuny version, and connected application.

Frequently asked questions

Can Znuny expose custom REST endpoints?

Yes. Implement a Generic Interface operation, register its module in SysConfig, add it to a REST provider webservice, and deploy the files in a Znuny package.

What package and configuration roots does Znuny use?

Znuny packages use an otrs_package manifest root and SysConfig XML uses otrs_config. Confirm supported Framework versions for your installed Znuny release.

Can Softoft program a custom Znuny API extension?

Yes. Softoft provides operation design, Perl development, webservice configuration, packaging, testing, deployment, and maintenance.