> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/administration-guide/ticketing/operate-ticketing.md).

# Operate ticket integration

For operators — the services and queues behind ticket integration, how deliveries are retried and deferred, every property with its default, the audit actions, which log answers which question, troubl

## What this is, and when you need it <a href="#operate-what-this-is" id="operate-what-this-is"></a>

This page is for the people who keep ticket integration running: which OpenIAM services take part, how a ticket travels from an event to Jira or ServiceNow and back, what OpenIAM does when a delivery fails, which properties change that behaviour, what is audited, and where to look when a ticket does not arrive. It also covers moving from the deprecated Groovy script hook to ticket rules.

To write rules, start at [Write a ticket rule](/administration-guide/ticketing/ticket-rules.md); to connect a ticketing system, at [Connect a ticketing system](/administration-guide/ticketing/connect-a-ticketing-system.md). The vocabulary used here — subject, trigger group, delivery state — is defined in [How ticket integration works](/administration-guide/ticketing/overview.md).

## Moving parts <a href="#operate-moving-parts" id="operate-moving-parts"></a>

| Part                                                         | Runs in                     | What it does                                                                                                                                                                                                                                  |
| ------------------------------------------------------------ | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| User event emitter                                           | ESB                         | Sends **User created**, **User edited** and **User terminated** after the user's save commits                                                                                                                                                 |
| Request event emitter                                        | workflow                    | Sends the request lifecycle triggers and **Access revoked** from the approval flows                                                                                                                                                           |
| Provisioning event emitter                                   | idm                         | Sends **Provisioning failed** and **Provisioning succeeded** when a connector replies for a user or group                                                                                                                                     |
| NHI event emitter                                            | openiam-nhi                 | Sends the NHI triggers, including the expiry warnings and the dormancy check                                                                                                                                                                  |
| `TicketProvisionQueue`                                       | RabbitMQ                    | Carries every event, test, metadata, retry and synchronization request to idm; events are one-way                                                                                                                                             |
| Event intake and dispatcher                                  | idm                         | Loads the event's context, matches the enabled rules, renders the templates, writes OpenIAM's ticket record and sends the request to the connector — or captures it in [simulation](/administration-guide/ticketing/review-before-sending.md) |
| `TICKET_Connector_1_Request` / `TICKET_Connector_1_Response` | RabbitMQ                    | The Ticket Connector's request and reply queues                                                                                                                                                                                               |
| Ticket Connector (`ticket-connector-rabbitmq`)               | Its own container or pod    | Calls the Jira REST API or the ServiceNow Table API, and answers on the reply queue                                                                                                                                                           |
| Reply handler                                                | idm                         | Updates the ticket record from the connector's reply: key, URL, status, or the failure                                                                                                                                                        |
| Retry sweeper                                                | idm                         | Every minute, resends deliveries that are due; one idm node at a time holds the Redisson lock `TICKET_RETRY_SWEEPER_LOCK`                                                                                                                     |
| Ticket records and rules                                     | ESB, OpenIAM database       | The `TICKET`, `TICKET_RULE`, `TICKET_RULE_TRIGGER` and `TICKET_RULE_FIELD` tables                                                                                                                                                             |
| Ticket synchronization                                       | synchronization, batch task | Every 15 minutes, searches the ticketing system for tickets labelled `openiam` and writes their status, resolution and assignee back ([details](/administration-guide/ticketing/policy-map-and-sync.md#sync-ticket-sync))                     |

User, request and NHI events are sent only after the change that caused them is committed, so a rolled-back save never raises a ticket. An event that cannot be sent is logged and dropped; it does not fail the user save or the approval.

{% hint style="warning" %}
The Helm chart `ticket-connector-rabbitmq` ships with `openiam.replicas: 0`. Until you set the replica count, nothing consumes `TICKET_Connector_1_Request`: every ticket stays **Pending** and **Test connection** gets no answer. See [Connect a ticketing system](/administration-guide/ticketing/connect-a-ticketing-system.md).
{% endhint %}

## Delivery and retries <a href="#operate-delivery-and-retries" id="operate-delivery-and-retries"></a>

Every send moves OpenIAM's ticket record to a pending state and then to delivered or failed when the reply arrives. Four mechanisms keep a delivery from being lost or duplicated.

### Pending timeout <a href="#operate-pending-timeout" id="operate-pending-timeout"></a>

A record in **Pending** gets a next attempt 10 minutes ahead (`org.openiam.idm.ticket.pending.timeout.ms`). If no reply has arrived by then, the retry sweeper sends the stored request again. A record whose connector never answers is resent after each pending timeout; the retry count does not grow, because nothing failed. A request captured in simulation has no next attempt and is never resent this way.

### Backoff after a failure <a href="#operate-backoff" id="operate-backoff"></a>

A failed send or a failure reply sets the record to **Failed**, keeps the error in **Last error**, increases the retry count and schedules the next attempt after `org.openiam.idm.ticket.retry.backoff.base.ms × 2^retry count` (the exponent stops at 10). With the defaults — a 5-minute base and five failures at most — the retries come 10, 20, 40 and 80 minutes after the first four failures, and after the fifth OpenIAM stops: the next attempt is cleared and a `TICKET_DELIVERY_FAILED` audit record says `retries exhausted`. A manual **Retry** on the [Tickets screen](/administration-guide/ticketing/tickets.md#tickets-retry) still works after that. A successful delivery resets the count.

### Updates and closes that arrive before the ticket exists <a href="#operate-deferred" id="operate-deferred"></a>

An update or close for a subject whose create has not been confirmed yet — the create is still in flight, or it failed — has no ticket key to act on. OpenIAM holds it instead of sending it: the record keeps the note `Deferred: the ticket has not been created yet` and is looked at again every minute (`org.openiam.idm.ticket.requeue.delay.ms`). As soon as the create succeeds, the held operations are sent oldest first. If the create has not succeeded within 15 minutes (`org.openiam.idm.ticket.requeue.window.ms`), the record turns **Failed** with `Deferred UPDATE expired after 900000 ms` (or `CLOSE`) and the held operations are dropped. This is also how a close rule with **If no ticket exists yet → Create a new ticket** works: the create is sent, and the close waits for it.

### Duplicate protection <a href="#operate-duplicates" id="operate-duplicates"></a>

* **One record per subject.** The `TICKET` table allows one record per ticketing system, trigger group and subject. When two events for the same subject race, the loser is evaluated again against the winner's record, so it updates the ticket instead of opening a second one.
* **Labels.** Every ticket carries the label `openiam` and the label `openiam-<subject key>` (on ServiceNow, the correlation fields; see [How fields reach Jira and ServiceNow](/administration-guide/ticketing/jira-and-servicenow.md)).
* **Adoption before a create is retried.** Before resending a failed create, OpenIAM searches the ticketing system for `openiam-<subject key>`. If a ticket is there — the create got through but the reply was lost — OpenIAM adopts it, records a `TICKET_SYNC` audit with the adopted key, and sends nothing.
* **The connector never repeats a create on its own.** It retries an HTTP call that the ticketing system rate-limited (HTTP 429) or, except for a create, that failed with a 5xx or a network error: up to three retries, 1, 2 and 4 seconds apart or as long as `Retry-After` says, at most 30 seconds. Because a comment, a Jira transition or a ServiceNow update is retried on a 5xx, a comment can appear twice when the ticketing system accepted it but answered with an error.

## Properties <a href="#operate-properties" id="operate-properties"></a>

These keys are read by the services named in the table and have the defaults shown compiled in. They are not seeded as system properties, so they do not appear in **Administration → System Configuration**. To change one, set it on the service like any other service property, for example as an `OPENIAM_PROP_` environment variable with the dots replaced by underscores (`OPENIAM_PROP_org_openiam_idm_ticket_retry_max_count=8` on idm); see [Where a property value actually comes from](/administration-guide/reference/system-properties.md#where-a-property-value-actually-comes-from).

| Property                                          | Service         | Default           | What it controls                                                       |
| ------------------------------------------------- | --------------- | ----------------- | ---------------------------------------------------------------------- |
| `org.openiam.idm.ticket.pending.timeout.ms`       | idm             | `600000` (10 min) | How long a pending delivery waits for a reply before it is resent      |
| `org.openiam.idm.ticket.retry.backoff.base.ms`    | idm             | `300000` (5 min)  | The base of the backoff; the delay is base × 2^retry count             |
| `org.openiam.idm.ticket.retry.max.count`          | idm             | `5`               | Failures after which automatic retries stop                            |
| `org.openiam.idm.ticket.retry.batch.size`         | idm             | `100`             | Records the sweeper handles per run                                    |
| `org.openiam.idm.ticket.retry.sweeptime`          | idm             | `60000` (1 min)   | How often the sweeper runs, and its delay after start-up               |
| `org.openiam.idm.ticket.requeue.delay.ms`         | idm             | `60000` (1 min)   | How often a held update or close is looked at again                    |
| `org.openiam.idm.ticket.requeue.window.ms`        | idm             | `900000` (15 min) | How long a held update or close waits for its create before it fails   |
| `org.openiam.idm.ticket.audit.payload.max.length` | idm             | `4000`            | Longest payload or response recorded in an audit record, in characters |
| `org.openiam.idm.managed.sys.policy.ticket.type`  | idm             | `TICKET_OBJECT`   | The policy map type that carries ticket fields; do not change it       |
| `org.openiam.sync.ticket.max.results`             | synchronization | `1000`            | Tickets one synchronization run reads                                  |

Two values are fixed: a search from the rule editor or a retry adoption reads at most 50 tickets, and the seeded synchronization runs on the cron expression `0 0/15 * * * ?` (change it on the batch task). The Ticket Connector has its own timeouts and retry settings (`ticket.jira.*` and `ticket.servicenow.*`); they are listed in [Connect a ticketing system](/administration-guide/ticketing/connect-a-ticketing-system.md).

## Audit actions <a href="#operate-audit-actions" id="operate-audit-actions"></a>

Ticket audit records have the target type `TICKET` and hang under the audit record of the event that caused them — the user save, the approval, the provisioning reply — so the audit log shows the ticket next to its cause. Each names who started the event as its requestor: the administrator who saved the user, the approver, the requester, the provisioning initiator, or the system user (`system`) for scheduled and automatic runs.

| Action                                             | Written by                   | What it records                                                                                                                          |
| -------------------------------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `TICKET_EVENT_RECEIVED`                            | idm, for every event         | The trigger and the subject key                                                                                                          |
| `TICKET_RULE_MATCHED`                              | idm, for every matching rule | The rule, the decision (create, update, close, skip), the existing ticket and its key                                                    |
| `TICKET_CREATE`, `TICKET_UPDATE`, `TICKET_CLOSE`   | idm, on send                 | The rule, the operation, the policy decision (`existingTicketPolicy=…` or `noTicketPolicy=…`), the outcome and the payload sent          |
| The same actions, as a child of the send           | idm, on reply                | The connector's response: key, id and URL of a create, the new status of a transition, or the error                                      |
| `TICKET_DELIVERY_FAILED`                           | idm                          | A failure reply (as a child of the send), retries exhausted, a held update or close expired, or no stored request to resend              |
| `TICKET_RETRY`                                     | idm                          | Each resend, `manual` or `automatic`, with the retry count                                                                               |
| `TICKET_SYNC`                                      | idm, synchronization         | An adoption of an existing ticket with its key; a synchronization run with `received=`, `matched=`, `unknown=` and up to 50 unknown keys |
| `TICKET_RULE_SAVE`, `TICKET_RULE_DELETE`           | ESB                          | Who changed which rule; for a save, each changed field as `old → new`, each side cut to 500 characters                                   |
| `SIMULATE_PROVISIONING`, `DISPATCH_SIMULATION_REQ` | idm                          | A request captured in simulation, and its later apply                                                                                    |
| `TICKET_SYSTEM_INTEGRATION`                        | workflow                     | A run of the deprecated Groovy hook ([below](#operate-migrate-from-the-groovy-hook))                                                     |

Payloads and responses are cut to `org.openiam.idm.ticket.audit.payload.max.length` characters and marked `truncated=true` when cut. Connection settings are never recorded, and any attribute whose name contains `password`, `secret`, `token`, `credential`, `apikey` or `api_key` is left out. The per-ticket view of these records is the audit trail in the [ticket details](/administration-guide/ticketing/tickets.md#tickets-audit-trail); retention is covered in [Audit actions and retention](/administration-guide/reference/audit-actions-and-retention.md).

## Which log answers which question <a href="#operate-logs" id="operate-logs"></a>

| Question                                       | Look in                                                                                                                                                                                     |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Did the event reach ticket integration at all? | The audit log for `TICKET_EVENT_RECEIVED`; if absent, the emitting service's log: ESB for user events, workflow for request events, idm for provisioning events, openiam-nhi for NHI events |
| Which rule matched, and why did another not?   | `TICKET_RULE_MATCHED` audit records; the idm log, which explains skipped rules (rule disabled, managed system inactive or not a Ticket Connector system, conditions not met)                |
| What exactly was sent?                         | The payload of the `TICKET_CREATE`/`TICKET_UPDATE`/`TICKET_CLOSE` audit record, or the ticket's audit trail                                                                                 |
| Why did Jira or ServiceNow reject it?          | **Last error** on the ticket; the `ticket-connector-rabbitmq` log for the HTTP call and the ticketing system's answer                                                                       |
| Is the connector consuming requests?           | The `ticket-connector-rabbitmq` log and the depth of `TICKET_Connector_1_Request` in RabbitMQ                                                                                               |
| Did the synchronization read the tickets back? | `TICKET_SYNC` audit records with `received=` and `matched=`; the synchronization log and the batch task's history                                                                           |

## Troubleshooting <a href="#operate-troubleshooting" id="operate-troubleshooting"></a>

| Symptom                                                                                                    | Likely cause                                                                                                                             | Resolution                                                                                                                                                                                           |
| ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| No ticket and no record on the **Tickets** screen                                                          | No enabled rule matches the trigger, or its **Applies to** conditions exclude the event                                                  | Check the rule's **Currently fires for** line ([Write a ticket rule](/administration-guide/ticketing/ticket-rules.md#rule-if)) and the `TICKET_EVENT_RECEIVED` / `TICKET_RULE_MATCHED` audit records |
| No ticket, `TICKET_EVENT_RECEIVED` present, no match                                                       | The managed system is inactive or its connector is not the Ticket Connector; rules of such a system are skipped                          | Activate the managed system, or correct its connector                                                                                                                                                |
| A rule fires for every event although it has conditions                                                    | Its stored conditions cannot be read — an invalid condition set matches every event, with a warning in the idm log                       | Open the rule, set the conditions again and save                                                                                                                                                     |
| A ticket stays **Pending** with **Not created yet**                                                        | The Ticket Connector is not running (Helm `replicas: 0`), not connected to RabbitMQ, or the system is in simulation mode                 | Start the connector; check `TICKET_Connector_1_Request`; check the Simulation screen                                                                                                                 |
| **Failed**, `Jira rejected the credentials (HTTP 401)` or `ServiceNow rejected the credentials (HTTP 401)` | Wrong or revoked credential on the managed system                                                                                        | Correct it, run **Test connection**, then **Retry**                                                                                                                                                  |
| **Failed**, `… denied access (HTTP 403)`                                                                   | The account may not create or edit in that project or table                                                                              | Grant the permission in the ticketing system, then **Retry**                                                                                                                                         |
| **Failed**, `… resource not found (HTTP 404)`                                                              | The project, table, issue or endpoint does not exist, or the account cannot see it                                                       | Correct the rule or the managed system                                                                                                                                                               |
| **Failed**, `… rate limit exceeded (HTTP 429) after 4 attempts`                                            | The ticketing system throttled the account                                                                                               | Nothing to fix in OpenIAM; the backoff retries it later                                                                                                                                              |
| **Failed**, `Transition '…' is not available for issue …; available: …`                                    | The close rule's transition does not exist from the issue's current status                                                               | Use a transition the workflow offers there ([Write a ticket rule](/administration-guide/ticketing/ticket-rules.md#rule-target-transition))                                                           |
| **Failed**, `transition is required to close`                                                              | A close rule without a transition reached the dispatcher                                                                                 | Set the rule's **Transition**                                                                                                                                                                        |
| **Failed**, `no TICKET policy map on …`                                                                    | The managed system's TICKET policy map was removed or never created                                                                      | Recreate the managed system with the Ticket Connector, or restore the policy map ([details](/administration-guide/ticketing/policy-map-and-sync.md#map-ticket-policy-map))                           |
| **Failed**, `Deferred UPDATE expired after 900000 ms`                                                      | The update waited 15 minutes for a create that never succeeded                                                                           | Fix and retry the create; the update was dropped, so let the next event send it or update the ticket by hand                                                                                         |
| The same comment appears twice on a ticket                                                                 | The ticketing system accepted a comment but answered with a 5xx, and the connector retried it                                            | Delete the duplicate in the ticketing system; nothing to fix in OpenIAM                                                                                                                              |
| An update or close rule never finds the ticket                                                             | The rule's trigger is in a different trigger group from the rule that created the ticket — **User created** and **User terminated**, say | Use triggers of one group ([Triggers and conditions](/administration-guide/ticketing/ticket-rules/triggers-and-conditions.md))                                                                       |
| A ticket created by hand in Jira is never updated                                                          | OpenIAM matches only tickets it created                                                                                                  | Let a create rule open it                                                                                                                                                                            |
| Requester placeholders render empty                                                                        | The request has no requester OpenIAM can resolve, or the trigger is not a request trigger                                                | Check which triggers fill `requester.*` in [Template placeholders](/administration-guide/ticketing/ticket-rules/placeholders.md)                                                                     |
| Target user and manager placeholders render empty on a provisioning ticket                                 | The event is a group provisioning reply, which has no target user                                                                        | Use `managedSystem.*` and `event.*` placeholders in rules that can fire for groups                                                                                                                   |
| Status in OpenIAM lags behind the ticketing system                                                         | The synchronization runs every 15 minutes, or its batch task is disabled                                                                 | Check the batch task `Ticket sync <managed system>`                                                                                                                                                  |

## Move from the Groovy ticket hook <a href="#operate-migrate-from-the-groovy-hook" id="operate-migrate-from-the-groovy-hook"></a>

Before 2026.10.2, the only way to raise a ticket was a Groovy script on a request's target resource, run when the request completed — described in [Raise a ServiceNow incident from an approval](/administration-guide/requests/approval-flows/raise-a-servicenow-incident.md). In 2026.10.2 that hook is **deprecated but still runs**: a resource with a **Groovy Script** keeps calling it from the access request, revoke, new user and group save flows. Each run now writes a `TICKET_SYSTEM_INTEGRATION` audit record whose text ends with `Deprecated: use the Ticket Connector`, and the workflow service logs one warning per resource. The two shipped example scripts, `ServiceNowTicketCreation_1.0.groovy` and `ServiceNowTicketCreationRevoke_1.0.groovy`, carry a "Legacy: superseded by the Ticket Connector" header.

Ticket rules do everything the hook did and more: they update and close the ticket, retry a failed delivery, prevent duplicates and read the status back. Move a hook over like this:

{% stepper %}
{% step %}
**Connect the ticketing system.** Create a managed system with the Ticket Connector for the same Jira or ServiceNow instance ([Connect a ticketing system](/administration-guide/ticketing/connect-a-ticketing-system.md)). You can reuse the integration account the script used; the old `SERVICE_NOW_MANAGED_SYS` record is not used by ticket rules.
{% endstep %}

{% step %}
**Write the equivalent rules.** The hook ran when a request completed, so the usual equivalent is a **Request completed** → **Create** rule with **Applies to** limited to the request types whose resource carried the script. Add a **Request submitted** create and a completion close if the service desk wants the ticket for the whole lifecycle, as in the running example.
{% endstep %}

{% step %}
**Simulate.** Turn on **Create ticket** in simulation mode and raise one disposable request. Check the captured request against what the script produced ([Review tickets before they are sent](/administration-guide/ticketing/review-before-sending.md)).
{% endstep %}

{% step %}
**Switch over.** Clear the **Groovy Script** field on each resource that carried the hook, then take the ticketing system out of simulation. Do it in that order, or for a while both the script and the rule raise a ticket for the same request.
{% endstep %}

{% step %}
**Close what the script left open.** Incidents the script created are not known to OpenIAM and are never updated or closed by a rule. Close them in the ticketing system.
{% endstep %}
{% endstepper %}

After the switch, the audit log should show no new `TICKET_SYSTEM_INTEGRATION` records and a `TICKET_CREATE` for each completed request in scope.

## Related <a href="#operate-related" id="operate-related"></a>

* [How ticket integration works](/administration-guide/ticketing/overview.md) — subjects, trigger groups and delivery states.
* [Track tickets](/administration-guide/ticketing/tickets.md) — retry and discard, the ticket details and audit trail.
* [Connect a ticketing system](/administration-guide/ticketing/connect-a-ticketing-system.md) — the connector, its properties and Test connection.
* [The TICKET policy map and ticket synchronization](/administration-guide/ticketing/policy-map-and-sync.md) — the fields sent and the status read back.
* [Audit actions and retention](/administration-guide/reference/audit-actions-and-retention.md) — how long the audit records are kept.
* [Batch tasks](/administration-guide/automation/batch-tasks.md) — the task that runs the ticket synchronization.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/administration-guide/ticketing/operate-ticketing.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
