> For the complete documentation index, see [llms.txt](https://docs.cybus.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.cybus.io/2-4-2/guides/system-connectivity/analytics-monitoring-alerting/servicenow-integration.md).

# ServiceNow Integration

This guide describes how to integrate ServiceNow with Connectware. You configure a service commissioning file that creates ServiceNow incidents from shop floor alarms and polls assigned incidents in return, using the ServiceNow Table API. A complete example file is available at the end of this guide.

## Objectives

* Establishing a connection between Connectware and the ServiceNow Table API.
* Creating ServiceNow incidents from shop floor alarm topics.
* Polling the active incidents of an assignment group and publishing them to an MQTT topic.

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware.
* Access to a ServiceNow instance and its hostname. For example, `example.service-now.com`. A free [Personal Developer Instance](https://developer.servicenow.com/) works for testing.
* A dedicated ServiceNow integration user with the roles required to read and write the incident table.
* Access to the [Admin UI](/2-4-2/access/admin-ui.md) with sufficient [user permissions](/2-4-2/access/user-management.md).
* Basic knowledge of MQTT and the Connectware [services](/2-4-2/data-flows/services.md) concept (for example, [service commissioning files](/2-4-2/data-flows/service-commissioning-files.md), [connections](/2-4-2/data-flows/service-commissioning-files/resources/cybus-connection.md), and [endpoints](/2-4-2/data-flows/service-commissioning-files/resources/cybus-endpoint.md)).

## Connectware and ServiceNow Integration

ServiceNow exposes every table of its platform through the [Table API](https://developer.servicenow.com/dev.do#!/reference/api/latest/rest/c_TableAPI), a REST API on your instance at `https://<instance>.service-now.com/api/now/table/<table_name>`. Connectware communicates with this API through the [HTTP/REST connector](/2-4-2/connectors/enterprise-connectors/http-rest.md).

This guide uses the Table API in both directions:

* **Creating incidents**: A `POST` request to `/api/now/table/incident` creates one incident per request. The request body contains the incident fields as JSON.
* **Polling incidents**: A `GET` request to `/api/now/table/incident` returns matching incident records. Query parameters such as `sysparm_query`, `sysparm_fields`, and `sysparm_limit` control the filter, the returned fields, and the number of records. Connectware polls this endpoint and publishes the result to an MQTT topic.

The Table API wraps every response in a `result` property: an object for a created record, an array for a queried record list.

The MQTT topics in this guide follow an ISA-95-style equipment hierarchy (`<enterprise>/<site>/<area>/<line>/<cell>`). The mappings subscribe with wildcards across all levels, so any machine in the hierarchy is picked up without changing the integration.

### ServiceNow Connection Properties

The connection to ServiceNow requires the hostname of your instance and the credentials of the integration user. We add them as parameters to the service commissioning file, so you can set them when you install the service.

Do not worry about copying the service commissioning file snippets together into one, the complete example file is available at the end of this guide.

* `serviceNowHost`: The hostname of your ServiceNow instance, without the scheme. For example, `example.service-now.com`.
* `serviceNowUsername` and `serviceNowPassword`: The credentials of the integration user.
* `callerId`: The `sys_id` of the ServiceNow user that is set as the caller of new incidents. You find it in the `sys_user` table of your instance.
* `assignmentGroup`: The name of the assignment group whose incidents are polled.
* `pollInterval`: The polling interval for assigned incidents in milliseconds. Defaults to 30 seconds.
* `topicRoot`: The root of the MQTT topic hierarchy. Defaults to `enterprise`.

{% code lineNumbers="true" %}

```yaml
parameters:
  serviceNowHost:
    description: Hostname of your ServiceNow instance
    type: string
    default: example.service-now.com

  serviceNowUsername:
    description: Username of the ServiceNow integration user
    type: string

  serviceNowPassword:
    description: Password of the ServiceNow integration user
    type: string

  callerId:
    description: sys_id of the ServiceNow user set as the caller of new incidents
    type: string
    default: '00000000000000000000000000000000'

  assignmentGroup:
    description: Name of the assignment group whose incidents are polled
    type: string
    default: Service Desk

  pollInterval:
    description: Polling interval for assigned incidents in milliseconds
    type: integer
    default: 30000

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise
```

{% endcode %}

### ServiceNow Connection

To connect to the Table API, we set up a `Cybus::Connection` resource that uses the HTTP/REST connector with basic authentication. The `auth` property holds the credentials of the integration user.

Use a dedicated integration user instead of a personal account. In ServiceNow, mark this user as **Web service access only**, so the account cannot log in to the ServiceNow UI. The user needs the roles that the access control lists (ACLs) of the target table require, for example the `itil` role for the incident table. If your instance restricts platform REST APIs with REST API ACLs, the user additionally needs the `snc_platform_rest_api_access` role. ServiceNow also supports OAuth 2.0 for inbound REST requests, which the HTTP/REST connector covers with the [OAuth 2.0 Client Credentials Grant](https://docs.cybus.io/2-4-2/guides/system-connectivity/analytics-monitoring-alerting/pages/Hij6TsDxB4GxfyynBwLn#oauth-2.0-client-credentials-grant), but this guide uses basic authentication.

{% code lineNumbers="true" %}

```yaml
resources:
  serviceNowConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: !ref serviceNowHost
        port: 443
        auth:
          username: !ref serviceNowUsername
          password: !ref serviceNowPassword
```

{% endcode %}

### Creating Incidents from Shop Floor Alarms

To create incidents, we define a write endpoint for the `/api/now/table/incident` path and a mapping that feeds it from the MQTT topic hierarchy. The HTTP/REST connector expects the request body in the `body` property of the message (see [Publishing Data to REST Servers](/2-4-2/connectors/enterprise-connectors/http-rest.md#publishing-data-to-rest-servers)).

The mapping uses [named wildcards](/2-4-2/data-flows/service-commissioning-files/resources/cybus-mapping.md#wildcards), so the topic levels are available in the `$context.vars` object of the `transform` rule. The rule builds the incident fields from the alarm payload and puts the location of the alarm into the `description`, so the service desk sees which machine raised it without leaving the incident form.

{% code lineNumbers="true" %}

```yaml
incidentCreateEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref serviceNowConnection
    write:
      path: /api/now/table/incident

incidentCreateMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/+site/+area/+line/+cell/alarm'
        publish:
          endpoint: !ref incidentCreateEndpoint
        rules:
          - transform:
              expression: !sub >-
                {
                  "body": {
                    "short_description": "Shop floor alarm: " & text,
                    "description": "Alarm " & code & " reported by cell "
                      & $context.vars.cell & " on line " & $context.vars.line
                      & " in area " & $context.vars.area & " at site "
                      & $context.vars.site & ".",
                    "urgency": $string(urgency),
                    "impact": $string(impact),
                    "caller_id": "${callerId}"
                  }
                }
```

{% endcode %}

Any message published to a matching topic, for example `enterprise/hamburg/assembly/line-1/press-01/alarm`, now creates one incident. The alarm payload only needs the alarm fields, the topic provides the location:

{% code lineNumbers="true" %}

```json
{
  "text": "Hydraulic pressure below threshold",
  "code": "PRESS-ALM-017",
  "urgency": 2,
  "impact": 3
}
```

{% endcode %}

The transform rule turns this message into the following request body:

{% code lineNumbers="true" %}

```json
{
  "short_description": "Shop floor alarm: Hydraulic pressure below threshold",
  "description": "Alarm PRESS-ALM-017 reported by cell press-01 on line line-1 in area assembly at site hamburg.",
  "urgency": "2",
  "impact": "3",
  "caller_id": "00000000000000000000000000000000"
}
```

{% endcode %}

Some notes on the incident fields:

* `short_description` is the field that ServiceNow shows in incident lists. Nothing more is technically required to create an incident, but a `description`, a caller, and a meaningful urgency make the incident actionable.
* `urgency` and `impact` take the values `1` (high), `2` (medium), and `3` (low). ServiceNow calculates the `priority` of the incident from these two fields.
* `caller_id` is a reference field and takes the `sys_id` of a user record. Depending on the policies of your instance, the caller can be mandatory.
* Custom fields of your instance carry a `u_` prefix, for example `u_machine_id`. You can set them in the same request body.

### Polling Assigned Incidents

For the opposite direction, a subscribe endpoint polls the incident table on a fixed interval and publishes the result to the MQTT broker. The query parameters narrow the result down to what the shop floor needs:

* `sysparm_query`: An encoded query that filters the records, in this case the active incidents of one assignment group. Conditions are joined with `^`. To build more complex queries, filter an incident list in the ServiceNow UI, right-click the filter breadcrumb, and select **Copy query**.
* `sysparm_fields`: The fields to return. Keeping this list short keeps the MQTT messages small.
* `sysparm_display_value`: Set to `true` to return display values, for example `In Progress` instead of the numeric state code.
* `sysparm_limit`: The maximum number of records per poll.

{% code lineNumbers="true" %}

```yaml
assignedIncidentsEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref serviceNowConnection
    subscribe:
      path: /api/now/table/incident
      interval: !ref pollInterval
      query:
        sysparm_query: !sub 'assignment_group.name=${assignmentGroup}^active=true'
        sysparm_fields: number,short_description,state,priority,urgency,sys_updated_on,sys_id
        sysparm_display_value: 'true'
        sysparm_limit: '25'

assignedIncidentsMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref assignedIncidentsEndpoint
        publish:
          topic: !sub '${topicRoot}/servicenow/incidents'
        rules:
          - transform:
              expression: 'value.result'
```

{% endcode %}

Every poll result arrives in the standardized wrapper of the HTTP/REST connector (see [Response Message Format](/2-4-2/connectors/enterprise-connectors/http-rest.md#response-message-format)), where the `value` property contains the Table API response. The `transform` rule unwraps the message to the `result` array, so the topic carries plain incident records:

{% code lineNumbers="true" %}

```json
[
  {
    "number": "INC0010042",
    "short_description": "Shop floor alarm: Hydraulic pressure below threshold",
    "state": "In Progress",
    "priority": "4 - Low",
    "urgency": "2 - Medium",
    "sys_updated_on": "2026-07-16 09:12:45",
    "sys_id": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
  }
]
```

{% endcode %}

From the `enterprise/servicenow/incidents` topic, any other Connectware service can pick up the incidents, for example to light an andon signal on the affected line until the incident is resolved.

## Verifying the Integration

1. Install the service and set the parameters with the values of your ServiceNow instance.
2. Check that the connection is in the **Connected** state on the service details page in the Admin UI.
3. Publish a test alarm to `enterprise/hamburg/assembly/line-1/press-01/alarm`, for example with an MQTT client or the Admin UI. Use the alarm payload shown in this guide.
4. Open the incident list in ServiceNow and check that a new incident with the short description `Shop floor alarm: Hydraulic pressure below threshold` exists.
5. Assign the incident to the assignment group that you set in the `assignmentGroup` parameter. Use the [Data Explorer](/2-4-2/monitoring/data-explorer.md) to check that the incident appears on the `enterprise/servicenow/incidents` topic within the polling interval.
6. The result of every HTTP request is published to the `/res` topic of the endpoint. If ServiceNow rejects a request, the message on the `/res` topic contains an `error` property with the HTTP status. A `401` status indicates wrong credentials, a `403` status indicates missing roles or ACLs of the integration user.

## Service Commissioning File Example

{% file src="/files/NscHvzDGqQJ12P8yXXjD" %}

{% code title="servicenow-example.yml" lineNumbers="true" expandable="true" %}

```yaml
---
# ----------------------------------------------------------------------------
# Service Commissioning File
# ----------------------------------------------------------------------------
# Copyright: Cybus GmbH
# Contact: support@cybus.io
# ----------------------------------------------------------------------------
# ServiceNow Integration (Example)
# ----------------------------------------------------------------------------

description: >
  Service commissioning file for creating ServiceNow incidents from shop
  floor alarms and polling assigned incidents through the Table API (Example)

metadata:
  name: ServiceNow Integration
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  serviceNowHost:
    description: Hostname of your ServiceNow instance
    type: string
    default: example.service-now.com

  serviceNowUsername:
    description: Username of the ServiceNow integration user
    type: string

  serviceNowPassword:
    description: Password of the ServiceNow integration user
    type: string

  callerId:
    description: sys_id of the ServiceNow user set as the caller of new incidents
    type: string
    default: '00000000000000000000000000000000'

  assignmentGroup:
    description: Name of the assignment group whose incidents are polled
    type: string
    default: Service Desk

  pollInterval:
    description: Polling interval for assigned incidents in milliseconds
    type: integer
    default: 30000

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise

resources:
  # Connection to the ServiceNow instance using basic authentication
  serviceNowConnection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: !ref serviceNowHost
        port: 443
        auth:
          username: !ref serviceNowUsername
          password: !ref serviceNowPassword

  # Creates one ServiceNow incident per alarm message
  incidentCreateEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref serviceNowConnection
      write:
        path: /api/now/table/incident

  # Builds the incident from the alarm payload and the topic levels
  incidentCreateMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/+site/+area/+line/+cell/alarm'
          publish:
            endpoint: !ref incidentCreateEndpoint
          rules:
            - transform:
                expression: !sub >-
                  {
                    "body": {
                      "short_description": "Shop floor alarm: " & text,
                      "description": "Alarm " & code & " reported by cell "
                        & $context.vars.cell & " on line " & $context.vars.line
                        & " in area " & $context.vars.area & " at site "
                        & $context.vars.site & ".",
                      "urgency": $string(urgency),
                      "impact": $string(impact),
                      "caller_id": "${callerId}"
                    }
                  }

  # Polls the active incidents of the assignment group
  assignedIncidentsEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref serviceNowConnection
      subscribe:
        path: /api/now/table/incident
        interval: !ref pollInterval
        query:
          sysparm_query: !sub 'assignment_group.name=${assignmentGroup}^active=true'
          sysparm_fields: number,short_description,state,priority,urgency,sys_updated_on,sys_id
          sysparm_display_value: 'true'
          sysparm_limit: '25'

  # Publishes the polled incidents to the MQTT broker
  assignedIncidentsMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref assignedIncidentsEndpoint
          publish:
            topic: !sub '${topicRoot}/servicenow/incidents'
          rules:
            - transform:
                expression: 'value.result'
```

{% endcode %}


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.cybus.io/2-4-2/guides/system-connectivity/analytics-monitoring-alerting/servicenow-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
