Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
Z
zunny_api
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Victor Kiprotich
zunny_api
Commits
7e6ed2c6
Commit
7e6ed2c6
authored
Aug 26, 2025
by
Victor Kiprotich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
initial commit
parents
Pipeline
#658
canceled with stages
Changes
1
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
542 additions
and
0 deletions
+542
-0
znuny_api_reference.md
znuny_api_reference.md
+542
-0
No files found.
znuny_api_reference.md
0 → 100644
View file @
7e6ed2c6
# Znuny 6.5 – REST API (CustomerUser & Ticket) Guide
This document consolidates:
-
✅
**Session-based auth**
(SessionCreate/Get/Delete)
-
✅
**CustomerUser**
operations (Create/Get/Update/Search)
-
✅
**Ticket**
operations (Create/Get/Update/Search/History)
-
✅
**Attachment**
upload & download
-
✅
**YAML configuration**
for a single webservice exposing both domains
-
✅
**Mermaid sequence diagrams**
showing full request/response flows
-
✅
**Copy‑pasteable cURL examples**
---
## 1) Webservice YAML (single file)
> Save as `/opt/otrs/znuny_portal.yml` (or any name you prefer). Then run:
>
> ```bash
> /opt/otrs/bin/otrs.Console.pl Admin::WebService::Add \
> --name znuny_portal \
> --source-path /opt/otrs/znuny_portal.yml
> ```
```
yaml
---
Debugger
:
DebugThreshold
:
error
TestMode
:
'
0'
Description
:
"
Portal
REST
for
CustomerUser
&
Ticket
(Znuny
6.5)"
Provider
:
Operation
:
# ========== Session ==========
SessionCreate
:
Description
:
Create a session (returns SessionID)
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
Session::SessionCreate
SessionGet
:
Description
:
Get session info
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
Session::SessionGet
SessionDelete
:
Description
:
Delete a session
Type
:
Session::SessionRemove
# ========== CustomerUser ==========
CustomerUserCreate
:
Description
:
Create customer user
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
CustomerUser::CustomerUserCreate
CustomerUserGet
:
Description
:
Get a customer user by login
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
CustomerUser::CustomerUserGet
CustomerUserUpdate
:
Description
:
Update customer user
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
CustomerUser::CustomerUserUpdate
CustomerUserSearch
:
Description
:
Search customer users (by PostMasterSearch/email or generic fields)
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
CustomerUser::CustomerUserSearch
# ========== Ticket core ==========
TicketCreate
:
Description
:
Create ticket (with optional first article & attachments)
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
Ticket::TicketCreate
TicketGet
:
Description
:
Get base ticket info
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
Ticket::TicketGet
TicketUpdate
:
Description
:
Update ticket (and add note article/attachments)
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
Ticket::TicketUpdate
TicketSearch
:
Description
:
Search tickets
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
Ticket::TicketSearch
TicketHistoryGet
:
Description
:
Get ticket history
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
Ticket::TicketHistoryGet
# ========== Attachments (download only; upload happens via Article.Attachment array) ==========
ArticleAttachmentGet
:
Description
:
Download a specific attachment by ArticleID & AttachmentID
MappingInbound
:
{}
MappingOutbound
:
{}
Type
:
Ticket::ArticleAttachmentGet
Transport
:
Type
:
HTTP::REST
Config
:
KeepAlive
:
'
1'
MaxLength
:
'
100000000'
AdditionalHeaders
:
~
RouteOperationMapping
:
# ----- Session -----
SessionCreate
:
ParserBackend
:
JSON
RequestMethod
:
[
POST
]
Route
:
/Session
SessionGet
:
ParserBackend
:
JSON
RequestMethod
:
[
GET
]
Route
:
/Session/:SessionID
SessionDelete
:
ParserBackend
:
JSON
RequestMethod
:
[
DELETE
]
Route
:
/Session/:SessionID
# ----- CustomerUser -----
CustomerUserCreate
:
ParserBackend
:
JSON
RequestMethod
:
[
POST
]
Route
:
/CustomerUser
CustomerUserGet
:
ParserBackend
:
JSON
RequestMethod
:
[
POST
]
Route
:
/CustomerUser/Get
CustomerUserUpdate
:
ParserBackend
:
JSON
RequestMethod
:
[
POST
]
Route
:
/CustomerUser/Update
CustomerUserSearch
:
ParserBackend
:
JSON
RequestMethod
:
[
POST
]
Route
:
/CustomerUser/Search
# ----- Ticket -----
TicketCreate
:
ParserBackend
:
JSON
RequestMethod
:
[
POST
]
Route
:
/Ticket
TicketGet
:
ParserBackend
:
JSON
RequestMethod
:
[
GET
]
# NOTE: SessionID must be passed as a query parameter (?SessionID=...)
Route
:
/Ticket/:TicketID
TicketUpdate
:
ParserBackend
:
JSON
RequestMethod
:
[
PATCH
]
Route
:
/Ticket/:TicketID
TicketSearch
:
ParserBackend
:
JSON
RequestMethod
:
[
POST
]
Route
:
/Ticket/Search
TicketHistoryGet
:
ParserBackend
:
JSON
RequestMethod
:
[
GET
]
# NOTE: SessionID must be passed as a query parameter (?SessionID=...)
Route
:
/Ticket/History/:TicketID
# ----- Attachment download -----
ArticleAttachmentGet
:
ParserBackend
:
JSON
RequestMethod
:
[
GET
]
# NOTE: returns JSON { Filename, ContentType, Content } where Content is base64
Route
:
/Ticket/Article/:ArticleID/Attachment/:AttachmentID
```
> **Why GET passes `SessionID` as query?**
> Znuny’s REST GET handlers do not parse JSON request bodies. Always pass `?SessionID=...` for **GET** routes.
---
## 2) CustomerUser – cURL Examples
### Create
```
bash
curl
-k
-sS
-X
POST
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/CustomerUser'
\
-H
'Content-Type: application/json'
\
-d
'{
"UserLogin": "jane.doe",
"UserEmail": "jane.doe@example.com",
"UserFirstname": "Jane",
"UserLastname": "Doe",
"UserCustomerID": "Servernah",
"UserPassword": "S3cr3t!2025",
"ValidID": 1
}'
# => {"UserLogin":"jane.doe"}
```
### Get
```
bash
curl
-k
-sS
-X
POST
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/CustomerUser/Get'
\
-H
'Content-Type: application/json'
\
-d
'{"UserLogin":"jane.doe"}'
```
### Update
```
bash
curl
-k
-sS
-X
POST
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/CustomerUser/Update'
\
-H
'Content-Type: application/json'
\
-d
'{
"UserLogin": "jane.doe",
"UserEmail": "jane+1@example.com",
"UserFirstname": "Janet",
"UserLastname": "Doe",
"UserCustomerID": "Servernah",
"ValidID": 1
}'
# => {"UserLogin":"jane.doe"}
```
### Search (by email)
```
bash
curl
-k
-sS
-X
POST
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/CustomerUser/Search'
\
-H
'Content-Type: application/json'
\
-d
'{"PostMasterSearch":"jane.doe@example.com"}'
# => {"CustomerUsers":["jane.doe","\"Jane Doe\" <jane.doe@example.com>"]}
```
---
## 3) Session – cURL Examples
### Create Session
```
bash
curl
-k
-sS
-X
POST
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Session'
\
-H
'Content-Type: application/json'
\
-d
'{"UserLogin":"Toney.Webala","Password":"<PASSWORD>"}'
# => {"SessionID":"<token>"}
```
### Get Session
```
bash
curl
-k
-sS
-G
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Session/<SessionID>'
\
-H
'Accept: application/json'
```
### Delete Session
```
bash
curl
-k
-sS
-X
DELETE
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Session/<SessionID>'
```
---
## 4) Ticket – cURL Examples
### Create (with first article & attachments)
```
bash
# Prepare base64 file content
FILE64
=
"
$(
openssl
base64
-A
-in
./screenshot.png
)
"
curl
-k
-sS
-X
POST
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Ticket'
\
-H
'Content-Type: application/json'
\
-d
"{
\"
SessionID
\"
:
\"
<SessionID>
\"
,
\"
Ticket
\"
: {
\"
Title
\"
:
\"
Portal: cannot access service catalog
\"
,
\"
Queue
\"
:
\"
Raw
\"
,
\"
State
\"
:
\"
new
\"
,
\"
Priority
\"
:
\"
3 normal
\"
,
\"
CustomerUser
\"
:
\"
jane.doe
\"
},
\"
Article
\"
: {
\"
Subject
\"
:
\"
Login issue
\"
,
\"
Body
\"
:
\"
User reports SSO success, but portal shows empty page.
\"
,
\"
ContentType
\"
:
\"
text/plain; charset=utf-8
\"
,
\"
Attachment
\"
: [
{
\"
Filename
\"
:
\"
screenshot.png
\"
,
\"
ContentType
\"
:
\"
image/png
\"
,
\"
Content
\"
:
\"
${
FILE64
}
\"
}
]
}
}"
# => {"ArticleID":123,"TicketID":"99","TicketNumber":"2025..."}
```
### Get (note the `-G` & query param)
```
bash
curl
-k
-sS
-G
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Ticket/99'
\
--data-urlencode
'SessionID=<SessionID>'
\
-H
'Accept: application/json'
```
### Update (change priority/state and add a note with attachment)
```
bash
NOTE64
=
"
$(
printf
'Investigating; appears VPN-related'
| openssl
base64
-A
)
"
curl
-k
-sS
-X
PATCH
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Ticket/99'
\
-H
'Content-Type: application/json'
\
-d
"{
\"
SessionID
\"
:
\"
<SessionID>
\"
,
\"
Ticket
\"
: {
\"
State
\"
:
\"
open
\"
,
\"
Priority
\"
:
\"
4 high
\"
},
\"
Article
\"
: {
\"
Subject
\"
:
\"
Follow-up
\"
,
\"
Body
\"
:
\"
Customer confirmed the issue is VPN-only.
\"
,
\"
ContentType
\"
:
\"
text/plain; charset=utf-8
\"
,
\"
Attachment
\"
: [
{
\"
Filename
\"
:
\"
note.txt
\"
,
\"
ContentType
\"
:
\"
text/plain
\"
,
\"
Content
\"
:
\"
${
NOTE64
}
\"
}
]
}
}"
# => {"ArticleID":..., "TicketID":"99", "TicketNumber":"..."}
```
### Search
```
bash
# ARRAY of TicketIDs for a customer & queue set
curl
-k
-sS
-X
POST
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Ticket/Search'
\
-H
'Content-Type: application/json'
\
-d
'{
"SessionID": "<SessionID>",
"CustomerUserLogin": "jane.doe",
"Queues": ["Raw"],
"StateType": ["new", "open", "pending reminder", "pending auto"],
"OrderBy": ["Created"],
"SortBy": "Down",
"Limit": 50,
"Result": "ARRAY"
}'
# => {"TicketID":["19","18","17"]}
# HASH (full details) – keep volume in mind
curl
-k
-sS
-X
POST
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Ticket/Search'
\
-H
'Content-Type: application/json'
\
-d
'{
"SessionID": "<SessionID>",
"Queues": ["Raw"],
"States": ["new","open"],
"OrderBy": ["Created"],
"SortBy": "Down",
"Limit": 20,
"Result": "HASH"
}'
```
### History
```
bash
curl
-k
-sS
-G
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Ticket/History/99'
\
--data-urlencode
'SessionID=<SessionID>'
\
-H
'Accept: application/json'
```
### Attachment Download
```
bash
# Returns JSON with base64 content
curl
-k
-sS
-G
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Ticket/Article/<ArticleID>/Attachment/<AttachmentID>'
\
--data-urlencode
'SessionID=<SessionID>'
\
-H
'Accept: application/json'
# Save the file locally (requires jq)
curl
-k
-sS
-G
\
'https://<host>/otrs/nph-genericinterface.pl/Webservice/znuny_portal/Ticket/Article/<ArticleID>/Attachment/<AttachmentID>'
\
--data-urlencode
'SessionID=<SessionID>'
\
-H
'Accept: application/json'
\
| jq
-r
'.Content'
|
base64
--decode
>
downloaded.bin
```
---
## 5) REST Sequence Diagrams
> **Note:** These diagrams assume the webservice name `znuny_portal` and show session auth + common flows.
### 5.1 Session + Ticket Create
```
mermaid
sequenceDiagram
autonumber
participant C as Client
participant Z as Znuny Provider (znuny_portal)
C->>Z: POST /Session {UserLogin, Password}
Z-->>C: {SessionID}
C->>Z: POST /Ticket {SessionID, Ticket{...}, Article{...,[Attachment]}}
Z-->>C: {TicketID, TicketNumber, ArticleID}
```
### 5.2 Ticket Get (GET with query param)
```
mermaid
sequenceDiagram
autonumber
participant C as Client
participant Z as Znuny Provider
C->>Z: GET /Ticket/:TicketID?SessionID=...
Z-->>C: {Ticket:[{...}]}
```
### 5.3 Ticket Update + Note + Attachment
```
mermaid
sequenceDiagram
autonumber
participant C as Client
participant Z as Znuny Provider
C->>Z: PATCH /Ticket/:TicketID {SessionID, Ticket{State,Priority}, Article{Subject,Body,[Attachment]}}
Z-->>C: {ArticleID, TicketID, TicketNumber}
```
### 5.4 Ticket Search
```
mermaid
sequenceDiagram
autonumber
participant C as Client
participant Z as Znuny Provider
C->>Z: POST /Ticket/Search {SessionID, filters... Result: ARRAY|HASH}
Z-->>C: {TicketID:[...]} or {Ticket:[...]}
```
### 5.5 Ticket History
```
mermaid
sequenceDiagram
autonumber
participant C as Client
participant Z as Znuny Provider
C->>Z: GET /Ticket/History/:TicketID?SessionID=...
Z-->>C: {TicketHistory:[{History:[...]...}]}
```
### 5.6 Attachment Download
```
mermaid
sequenceDiagram
autonumber
participant C as Client
participant Z as Znuny Provider
C->>Z: GET /Ticket/Article/:ArticleID/Attachment/:AttachmentID?SessionID=...
Z-->>C: {Filename, ContentType, Content(base64)}
```
---
## 6) Request/Response Parameters (at a glance)
| Operation | Method & Route | Auth | Request Body (key fields) | Response (key fields) |
|---|---|---|---|---|
|
**SessionCreate**
|
`POST /Session`
| none |
`UserLogin, Password`
|
`SessionID`
|
|
**SessionGet**
|
`GET /Session/:SessionID`
| query |
*(none)*
| Session info |
|
**SessionDelete**
|
`DELETE /Session/:SessionID`
| query |
*(none)*
|
*(empty)*
|
|
**CustomerUserCreate**
|
`POST /CustomerUser`
| body |
`UserLogin, UserEmail, UserFirstname, UserLastname, UserCustomerID, [UserPassword], ValidID`
|
`UserLogin`
|
|
**CustomerUserGet**
|
`POST /CustomerUser/Get`
| body |
`UserLogin`
| Full user record |
|
**CustomerUserUpdate**
|
`POST /CustomerUser/Update`
| body |
`UserLogin, [fields…]`
|
`UserLogin`
|
|
**CustomerUserSearch**
|
`POST /CustomerUser/Search`
| body |
`PostMasterSearch`
(email) or other filters |
`CustomerUsers: [Login, "Full Name <email>"]`
|
|
**TicketCreate**
|
`POST /Ticket`
| body |
`SessionID, Ticket{Title,Queue,State,Priority,CustomerUser}, Article{Subject,Body,ContentType,[Attachment[]]}`
|
`TicketID, TicketNumber, ArticleID`
|
|
**TicketGet**
|
`GET /Ticket/:TicketID`
| query |
`?SessionID=...`
|
`Ticket:[{...}]`
|
|
**TicketUpdate**
|
`PATCH /Ticket/:TicketID`
| body |
`SessionID, Ticket{State,Priority,...}, [Article{...,[Attachment[]]}]`
|
`ArticleID, TicketID, TicketNumber`
|
|
**TicketSearch**
|
`POST /Ticket/Search`
| body |
`SessionID, filters..., Result=ARRAY|HASH`
|
`TicketID:[...]`
or
`Ticket:[...]`
|
|
**TicketHistoryGet**
|
`GET /Ticket/History/:TicketID`
| query |
`?SessionID=...`
|
`TicketHistory:[{History:[...]...}]`
|
|
**ArticleAttachmentGet**
|
`GET /Ticket/Article/:ArticleID/Attachment/:AttachmentID`
| query |
`?SessionID=...`
|
`{Filename, ContentType, Content(base64)}`
|
**Notes**
-
For
**GET**
routes, pass
`SessionID`
as a
**query**
parameter.
-
Attachment
**upload**
only via
`Article.Attachment[]`
when creating/updating tickets.
-
Attachment
**download**
uses the dedicated
`ArticleAttachmentGet`
route.
-
Email validations and customer company must be valid (
`CustomerUserEmailUniqCheck`
,
`CustomerCompanyValid`
).
---
## 7) Common Errors
| ErrorCode | Meaning | Typical Fix |
|---|---|---|
|
`*.AuthFail`
| User/session not authenticated or session missing on GET | Create session; pass
`?SessionID=...`
on GET. |
|
`*.MissingParameter`
| Required field absent | Add required JSON field(s). |
|
`CustomerUserCreate.EmailInvalid`
| Email blocked by config | Use an allowed domain or relax validation. |
|
`TicketCreate.InvalidParameter`
| Wrong field shape (e.g., DynamicField format) | Follow documented JSON structure. |
---
## 8) Operational Tips
-
After editing YAML or Custom modules:
```bash
/opt/otrs/bin/otrs.Console.pl Maint::Config::Rebuild
/opt/otrs/bin/otrs.Console.pl Maint::Cache::Delete
sudo systemctl reload apache2
```
-
Use
`Dev::Tools::GenericInterface::DebugRead`
to trace requests:
```
bash
/opt/otrs/bin/otrs.Console.pl Dev::Tools::GenericInterface::DebugRead
\
--webservice-id
<ID>
--with-data
\
--created-at-or-after "$(date -u --date='5 minutes ago' '+%Y-%m-%d %H:%M:%S')"
\
--limit 20
```
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment