Zammad Integration
The Zammad integration is a read-only connection for service-desk reporting. It supports Zammad Cloud and self-hosted Zammad instances that are reachable from the public internet over HTTPS.
Private or firewall-only Zammad instances are not supported in this release. The Zammad integration does not run through the Resplendent Sync Agent.
Before you begin
Section titled “Before you begin”You need:
- A dedicated Zammad service user. Avoid tying the connection to a person’s account.
- Agent access to every Zammad group whose tickets should be available to Resplendent.
- The
ticket.agentpermission for core ticket access. - The
user_preferences.access_tokenpermission while creating the token. - A public Zammad Instance URL with a certificate trusted by standard public certificate authorities.
The integration never creates, updates, or deletes records in Zammad.
Permissions
Section titled “Permissions”Give the service user’s role only the permissions needed for the Datasets you plan to sync.
| Permission | Required? | What it enables |
|---|---|---|
ticket.agent |
Yes | Core ticket, tag, user, organization, article, time-accounting, state, and priority access |
admin.group |
Optional | Groups Dataset |
admin.sla |
Optional | SLAs Dataset |
admin.role |
Optional | Roles Dataset |
The service user also needs read access to the appropriate Zammad groups. Zammad only returns records that the token user is allowed to see.
Missing an optional permission does not break the connection or other Datasets. Resplendent shows a warning on the affected Groups, SLAs, or Roles Dataset instead.
You do not need admin.object. Custom fields returned by the normal Tickets, Users, and Organizations APIs are discovered automatically.
See Zammad’s documentation for the current permission reference and group access levels.
Create the service user and access token
Section titled “Create the service user and access token”1. Create a dedicated role and user
Section titled “1. Create a dedicated role and user”- In Zammad, open Admin → Manage → Roles.
- Create a role for Resplendent and grant
ticket.agent. - Add
admin.group,admin.sla, oradmin.roleonly if you want the corresponding optional Dataset. - Give the role read access to the Zammad groups that should be included in reporting.
- Create or select a dedicated service user and assign the role.
If the service user cannot open a ticket in the Zammad interface, its access token will not be able to sync that ticket either.
2. Create an API access token
Section titled “2. Create an API access token”- Sign in to Zammad as the service user.
- Open the user’s profile from the avatar menu and select Token Access.
- Create a token named
Resplendent Data. - Select
ticket.agentand any optional permissions you chose above. - Set an expiration date that matches your credential-rotation policy.
- Copy the token when Zammad displays it. Zammad displays a newly created token only once.
Resplendent uses Zammad’s HTTP access-token authentication. Do not provide a Zammad password or an OAuth token. For more detail, see Zammad’s API authentication guide and access-token reference.
Connect Zammad to Resplendent Data
Section titled “Connect Zammad to Resplendent Data”- In Resplendent Data, go to Settings → Integrations.
- Find Zammad and select Connect.
- Enter the two fields shown in the setup form:
- Instance URL: the public HTTPS root of your Zammad instance, such as
https://support.example.com. Do not include/api/v1, credentials, a query string, or a fragment. - Access Token: the token created for the service user.
- Instance URL: the public HTTPS root of your Zammad instance, such as
- Test and save the connection.
- Select the Datasets and columns you want to sync.
The connection test makes a small Tickets request. A successful test proves that the token is valid and can read the core ticket API. Each selected Dataset then runs independently and reports its own permission or response error.
The Instance URL must remain on the same HTTPS origin if Zammad redirects an API request. Its DNS records must resolve only to public network addresses. Private, loopback, link-local, and embedded-credential destinations are rejected.
Datasets and default cadence
Section titled “Datasets and default cadence”These are the defaults requested by the integration. Your Resplendent subscription tier can impose a longer effective minimum interval.
| Dataset | Core or optional | Daytime sync | Nightly replacement |
|---|---|---|---|
| Tickets | Core | Every 5 minutes, incremental | Yes |
| Ticket Articles | Core | Every 5 minutes, incremental | Yes |
| Ticket Tags | Core | Every 5 minutes, incremental | Yes |
| Time Accounting | Core | Every 15 minutes, incremental | Yes |
| Users | Core | Every 60 minutes, incremental | Yes |
| Organizations | Core | Every 60 minutes, incremental | Yes |
| Ticket States | Core | Every 1,440 minutes, full | Yes |
| Ticket Priorities | Core | Every 1,440 minutes, full | Yes |
| Groups | Optional; admin.group |
Every 1,440 minutes, full | Yes |
| SLAs | Optional; admin.sla |
Every 1,440 minutes, full | Yes |
| Roles | Optional; admin.role |
Every 1,440 minutes, full | Yes |
Initial history is downloaded in bounded, resumable batches. Daytime incremental reads use a small timestamp overlap and primary-key deduplication so records sharing the same update time are retained. Requests use bounded ticket-level concurrency so large instances do not create an unbounded request burst.
Ticket deletion and lifecycle behavior
Section titled “Ticket deletion and lifecycle behavior”During the day, changed records are added or updated. Hard deletions converge through independent nightly replacements:
- Tickets replaces itself from the complete current Tickets endpoint.
- Ticket Articles separately replaces itself from the complete current Ticket Articles endpoint.
- Ticket Tags separately replaces itself by reading the complete current tag list for every visible ticket.
- Time Accounting separately replaces itself from the complete current Time Accounting endpoint.
The Datasets do not inspect or modify one another. Their nightly runs can finish at different times, so a temporary cross-Dataset mismatch is expected after a source deletion. Each Dataset converges when its own next replacement succeeds. If one replacement fails or is interrupted, Resplendent keeps that Dataset’s previous complete data without affecting any other Dataset.
A closed ticket is not a deleted ticket. Closed tickets, inactive users, inactive organizations, and inactive lookup values remain in their Datasets while Zammad continues to return them. Only absence from a completed authoritative source snapshot is treated as a hard deletion.
Ticket tag changes touch their related ticket in Zammad. Daytime Ticket Tags syncs therefore fetch the current tag associations for tickets inside the timestamp overlap window. A removed or renamed association can remain temporarily until Ticket Tags completes its own nightly replacement; it does not inspect or mutate the stored Tickets Dataset.
Ticket Tags
Section titled “Ticket Tags”Ticket Tags contains one row per ticket-and-tag association. Each row has a deterministic relationship ID, the source Ticket ID, the tag text, and the related ticket’s update timestamp. The Ticket ID and tag columns link to the corresponding ticket in Zammad.
Tag text is limited to 32,000 Unicode characters. Longer values retain a visible ellipsis inside the limit and set tag_truncated; original_tag_length records the source length. The relationship ID is derived from the complete source value, so truncation cannot merge two distinct tags.
Ticket Articles and sensitive content
Section titled “Ticket Articles and sensitive content”Ticket Articles includes both public replies and internal notes that the service user is allowed to see. The internal column distinguishes the two. Restrict the service user’s group access and select Dataset columns deliberately because internal notes may contain sensitive information.
Article content is selectable rather than mandatory:
bodycontains bounded source content.body_textcontains a safely derived plain-text representation for search and analysis.body_truncatedandoriginal_body_lengthdescribe truncation ofbody.body_text_truncatedandoriginal_body_text_lengthdescribe truncation ofbody_text.
Both content columns have a limit of 32,000 Unicode characters. When content exceeds the limit, Resplendent keeps a visible ellipsis within the 32,000-character value and sets the corresponding truncation flag.
If you do not want message content stored in Resplendent, omit body and body_text when selecting Ticket Articles columns. You can still analyze metadata such as direction, sender, recipient, subject, content type, timestamps, and whether an article is internal.
Attachment handling is metadata-only. Resplendent can retain attachment ID, filename, size, content type, and attachment count. The Ticket Articles Dataset does not create an attachment URL or link column in this release. It does not download or store attachment files, inline images, base64 payloads, or other attachment contents. Remote HTML is parsed as text without running scripts, loading embedded resources, or rendering remote content.
Request and retry behavior
Section titled “Request and retry behavior”Each API request has one 30-second end-to-end deadline covering DNS resolution, validated-address failover, redirects, retry delays, and response streaming, with at most four attempts inside that deadline. JSON response bodies are streamed through a 16 MiB limit before decoding. For throttling and transient Zammad server failures, Resplendent honors a numeric Retry-After value within the remaining deadline and the 30-second delay cap. When that header is absent or invalid, it uses bounded exponential backoff with jitter.
After the bounded attempts are exhausted, the sync stops with an actionable rate-limit, remote-server, or network error. A later scheduled sync can retry without replacing a complete Dataset with partial data.
Troubleshooting
Section titled “Troubleshooting”| Error category | What it means | What to do |
|---|---|---|
| Invalid credentials | Zammad rejected the Access Token, usually with HTTP 401. | Create or rotate the service user’s API access token, then update Access Token in Resplendent. Do not use a password or OAuth bearer token. |
| Missing core permission | The token cannot read Tickets and the connection reports that ticket.agent is required. |
Add ticket.agent to the service user’s role and token, confirm group read access, then test again. |
| Missing optional permission | Groups, SLAs, or Roles shows a Dataset warning naming admin.group, admin.sla, or admin.role. |
Add only that permission if the Dataset is needed. Otherwise leave the optional Dataset unselected. Core syncs continue. |
| Unsafe URL | The URL is not HTTPS, contains credentials/query/fragment data, resolves to a non-public address, or redirects to another origin. | Enter the public root URL only. Private-network and firewall-only instances are unsupported in this release. |
| TLS failure | The certificate could not be validated. | Install a certificate with a complete chain trusted by public certificate authorities. Certificate verification cannot be disabled. |
| Network failure | DNS did not resolve, the public host could not be reached, or requests timed out after bounded retries. | Confirm public DNS, firewall rules, and Zammad availability from outside the Zammad network. |
| Throttling | Zammad kept returning HTTP 429 after Resplendent honored bounded retry delays. | Reduce competing API traffic, review Zammad capacity, and let the next scheduled sync retry. |
| Unsupported response shape | Zammad returned invalid JSON, a non-array Dataset response, or fields that do not match the supported schema. | Record the Dataset name, Zammad version, timestamp, and safe error text, then contact support. Do not send the response body if it contains ticket content. |
| Transient Zammad failure | Zammad kept returning HTTP 5xx after bounded retries. | Check Zammad health and server logs, then retry after the incident. Existing complete Dataset data remains available. |
Safe information to collect for support
Section titled “Safe information to collect for support”Share the affected Dataset, approximate timestamp, Zammad version, Resplendent source identifier, and the exact safe error category. Never share the Access Token, an Authorization header, article bodies, attachment contents, or a raw API response containing customer data.
Security notes
Section titled “Security notes”- The Access Token is stored through Resplendent’s encrypted credential-key path and is not returned in visible connection metadata.
- API requests are read-only and keep the Authorization header on the configured origin.
- User-facing errors describe the failure category without copying Zammad response bodies.
- Operational sync logs contain bounded identifiers and counts, not article bodies or attachment contents.
- Custom fields keep their stable Zammad API names. Sparse values become null, and nested values are serialized deterministically.