Skip to content

Latest commit

 

History

History
113 lines (87 loc) · 9.78 KB

File metadata and controls

113 lines (87 loc) · 9.78 KB

Zammad integration

Windshift can create a Zammad ticket from an item and keep the remote ticket state visible on the item. An administrator owns each connection and explicitly grants it to selected workspaces or to all workspaces.

API and authentication

The routes in this integration use the application API prefix /api and the same authenticated session or bearer-token authentication as the rest of the application. Administration routes require a system administrator. Workspace and item routes require the caller to have view or edit permission for the referenced workspace or item.

Admin connection endpoints are GET|POST /api/admin/zammad-connections, GET|PUT|DELETE /api/admin/zammad-connections/{id}, POST /api/admin/zammad-connections/{id}/test, and POST /api/admin/zammad-connections/{id}/oauth/start. They list, create, inspect, update, delete, test, and authorize connections without returning any token or client secret. The OAuth callback is GET /api/integrations/zammad/oauth/callback. The explicit administrator retry is POST /api/admin/zammad-ticket-links/{linkId}/retry-create. POST /api/admin/zammad-ticket-links/refresh queues an asynchronous synchronization of every complete ticket link on enabled, authorized connections. Concurrent system-wide refresh requests are coalesced into the already queued or running job.

Workspace and item routes are GET /api/workspaces/{workspaceId}/zammad-connections, GET /api/workspaces/{workspaceId}/zammad-connections/{id}/metadata, GET /api/workspaces/{workspaceId}/zammad-connections/{id}/owners?group_id={groupId}, and GET /api/workspaces/{workspaceId}/zammad-overview?limit={limit}. Ticket routes are GET /api/items/{id}/zammad-links, GET /api/items/{id}/zammad-history?limit={limit}, GET /api/zammad-ticket-links/resolve/{correlationKey}, POST /api/items/{id}/zammad-tickets, POST /api/items/{id}/zammad-ticket-links, PUT /api/zammad-ticket-links/{linkId}, DELETE /api/zammad-ticket-links/{linkId}, and POST /api/zammad-ticket-links/{linkId}/refresh. The optional history and overview limit is an integer from 1 through 100 and defaults to 6 for item history and 5 for the workspace overview. Item history returns an events array containing only status, group, and owner changes observed during Windshift synchronization, including old and new IDs and point-in-time names, the ticket number, item identity, and observation time. The workspace overview returns current linked-ticket totals, active, closed, unassigned, unknown-status, synchronization-failure, and uncertain-creation counts, a per-connection status distribution, and the most recent observed changes. These responses are a polling-derived Windshift observation and are not a complete Zammad audit trail, so they do not claim the original Zammad change time, actor, or intermediate states between polls.

Create-ticket requests contain connection_id and may contain group_id. Link-existing requests contain connection_id and ticket_number. Link updates accept optional state_id, group_id, and owner_id, with at least one required. The create and link responses contain the link ID, ticket identity and URL when known, group and owner snapshot, synchronization state, last remote status, timestamps, and a sanitized error when applicable.

OAuth callback setup

Register this exact public callback URL in the Zammad OAuth application, replacing only the hostname with the public HTTPS hostname of the Windshift installation:

https://<public-hostname>/api/integrations/zammad/oauth/callback

Do not append a slash, query string, or fragment. The URL configured in Zammad must exactly match the URL generated by Windshift, including any configured public path prefix. Create the connection with auth_method: "oauth", the OAuth client ID, client secret, and a Zammad base URL without /api/v1. Start OAuth from the admin endpoint and complete authorization in Zammad. The callback intentionally does not require a session because its one-time, short-lived state is bound to the initiating administrator and atomically consumed. Access and refresh tokens are stored encrypted and never returned by the API.

If the callback fails, the administration UI receives an error result and the connection remains unavailable until authorization succeeds. Changing OAuth client configuration invalidates an in-flight attempt.

Zammad service account and permissions

Use a dedicated active Zammad user with the ticket.agent role for the integration, rather than a human administrator account. Give it read, create, and change group access only for the allowed group(s). This lets Windshift read the required ticket metadata and owners, create tickets, and change state, group, and owner within that boundary. Do not grant administration, user-management, group-management, delete-ticket, or unrestricted access to other groups. Zammad role and group permissions must enforce the same boundary as allowed_group_ids in the Windshift connection. The default group must be active and included in that allowed set.

Create an active text ticket object attribute named windshift_item_key, or configure another valid correlation field name. Windshift writes a deterministic correlation key to this field and uses it to find an already-created ticket safely. The field is the idempotency boundary for create retries and must be readable by the service agent.

For a permission-checked return link from Zammad to the current Windshift item, configure this link template on the same attribute:

https://windshift.example/zammad/#{ticket.windshift_item_key}

Replace the origin and optional path prefix with the browser-visible Windshift base URL. If the connection uses a different correlation field, replace windshift_item_key in the placeholder too. The resolver accepts the correlation value whether Zammad leaves it literal or percent-encodes it in the generated URL. The target keeps working after an item moves because Windshift resolves the stored correlation key to the current workspace and item. Opening the link requires a Windshift session and item.view permission; missing and unauthorized targets are both reported as unavailable.

Create, link, update, and unlink behavior

Creating a ticket first persists a pending link and searches Zammad by the correlation key. If the ticket already exists, Windshift links it instead of creating a duplicate. The item title and description are sent to Zammad, with the initial article created as an internal note. Ticket titles are limited to 200 characters and descriptions to 20,000 characters before transmission. After a successful create, the link becomes linked and the remote ticket snapshot is stored.

If a create request times out, returns a rate-limit or server error, or its response is otherwise ambiguous, the link becomes creation_uncertain. Automatic retries are search-only and never issue another create request while the outcome is unknown. An administrator must verify in Zammad whether the ticket exists and call the admin retry endpoint explicitly only if it does not. That retry searches by correlation key before permitting a new create.

Linking an existing ticket verifies that it exists, belongs to an allowed active group, and is not already associated with another correlation key. Updating a link sends only the requested state, group, and owner changes to Zammad. The selected group and state must be active and allowed, and the selected owner must be able to change tickets in the resulting group. Changing the group without selecting an owner resets the ticket to Zammad's unassigned owner. Unlinking clears the remote correlation field only when it still equals this Windshift link's exact key, removes the local association and visible item link, and never deletes the remote ticket. If the remote result is ambiguous, the local link remains so the operation can be retried safely. Deleting a connection is rejected while ticket links still exist, so each link must be safely unlinked before its correlation context can be removed.

Refresh, backoff, and recovery

POST /api/zammad-ticket-links/{linkId}/refresh performs an immediate remote read and updates the stored snapshot. A background scheduler also polls linked tickets approximately every two minutes after the previous run completes. Successful refreshes and persisted synchronization failures publish an item event so an open item panel reloads its Zammad snapshot without a page refresh. Failed synchronization records a sanitized error and schedules another attempt after a retry delay. Fair ordering by the most recent attempt prevents repeatedly failing links from starving healthy links. Remote response bodies and credentials are never exposed to clients. If a ticket is moved outside the connection's allowed groups in Zammad, synchronization records an error and does not update the local snapshot or apply a completion transition.

An OAuth invalid_grant response while refreshing an expired access token marks the connection as requiring reauthorization. The connection is not ready while reauthorization_required is true. Start OAuth again from the admin endpoint after correcting the Zammad OAuth application or grant. For API-token connections, rotate the token through the admin update endpoint and rerun the connection test.

Disabling a connection stops scheduled synchronization. A missing or unauthorized remote ticket does not mutate the Windshift item. Optional closed-state mapping can transition the Windshift item through its normal workflow, subject to the original administrator's item-edit permission.

The outbound client requires HTTPS, rejects credentials/query/fragment components in the base URL, enforces the shared public-address SSRF policy, checks redirects, limits responses, and applies a 30-second timeout. The integration does not synchronize attachments, comments, or arbitrary ticket fields.