Skip to main content

ServiceNow setup

Everything the connectors need on the ServiceNow side is standard instance administration: a user, some roles, an optional OAuth client and two instance properties. No application, update set or scripted REST API is installed.

1. Create an integration user​

In All > System Security > Users > New, create a dedicated user for the connectors. Tick Web service access only so the account cannot log in to the UI, and give it a strong password stored in a Connect config provider (see Authentication).

Roles​

ConnectorWhat it needsNotes
SourceRead access to every configured table or view, including the sys_id and timestamp fields and every projected fieldGranted through the instance's ACLs, usually by a role such as itil for incident and change_request, or a table-specific role for custom tables
SinkCreate, write and delete access on every target table, as the operations you use requireA sink that only patches needs write, not delete
Either, when snow.table.<alias>.query.domain=falsequery_no_domain_table_apiThe connector sends sysparm_query_no_domain=true only when the flag is false; without the role the instance ignores the parameter and returns only the user's domains

The rest_api_explorer role is not needed; it only gates the interactive REST API Explorer in the UI, not the API itself.

The Table API returns whatever the user's ACLs allow and hides the rest silently: a field the user cannot read is omitted from the response rather than reported as an error, and a table the user cannot read returns an empty result or a 403. The source connector's startup probe reads one row per table and fails if sys_id or the timestamp field is missing, but it cannot tell you about other fields you expected. Check the user's access with the REST API Explorer while logged in as an administrator, or run a query as the user with curl, before trusting a topic.

2. Set the user's time zone to UTC​

Open the user record and set Time zone to UTC. This is a prerequisite, not a preference.

ServiceNow stores date and time values in UTC, but it interprets the literal timestamps in an encoded query, such as sys_updated_on>2026-01-01 00:00:00, in the session user's time zone. The source connector builds its cursor predicates from UTC timestamps and stores UTC timestamps in its offsets. If the integration user sits in Europe/London, every query is shifted by up to an hour, the safety lag no longer protects the current second, and rows can be missed at the boundary.

The startup probe warns when it detects that the integration user's time zone is not UTC. Treat the warning as a configuration error.

3. Choose an authentication flow​

Basic authentication​

The simplest option and enough for many deployments. The connector sends the user's credentials on every request over HTTPS:

snow.url=https://acme.service-now.com
snow.auth.type=basic
snow.auth.username=${file:/secrets/snow.properties:username}
snow.auth.password=${file:/secrets/snow.properties:password}

OAuth 2.0: register an OAuth client​

In All > System OAuth > Application Registry > New, choose Create an OAuth API endpoint for external clients and fill in:

  • Name: something identifying the connector cluster.
  • Client ID: generated by the instance; copy it.
  • Client Secret: generated or set by you; copy it now, it is masked afterwards.
  • Access Token Lifespan and Refresh Token Lifespan: the defaults are fine. The connector refreshes the access token shortly before it expires and uses the refresh token when the instance issues one, so a short access token lifespan costs nothing.

The token endpoint is {snow.url}/oauth_token.do; the connector derives it from snow.url unless you set snow.oauth.token.url.

The client credentials grant is disabled by default on ServiceNow instances. To enable it:

  1. In All > System Properties > All Properties (or sys_properties.list), create or set glide.oauth.inbound.client.credential.grant_type.enabled to true.
  2. On the application registry record, add the OAuth Application User field to the form if it is not shown, and set it to the integration user from step 1. Tokens issued by this grant run as that user, so its roles and time zone apply.

Then configure the connector:

snow.url=https://acme.service-now.com
snow.auth.type=oauth2
snow.oauth.grant.type=client_credentials
snow.oauth.client.id=${file:/secrets/snow.properties:client.id}
snow.oauth.client.secret=${file:/secrets/snow.properties:client.secret}

OAuth 2.0 password grant​

If the property cannot be enabled on your instance, the resource-owner password grant works on every release. It combines the OAuth client with the integration user's credentials:

snow.url=https://acme.service-now.com
snow.auth.type=oauth2
snow.oauth.grant.type=password
snow.oauth.client.id=${file:/secrets/snow.properties:client.id}
snow.oauth.client.secret=${file:/secrets/snow.properties:client.secret}
snow.auth.username=${file:/secrets/snow.properties:username}
snow.auth.password=${file:/secrets/snow.properties:password}

Both grants are described in full, with the token refresh behaviour, in Authentication.

Set glide.invalid_query.returns_no_rows to true (default false) in All > System Properties > All Properties.

By default, ServiceNow ignores the part of an encoded query it cannot parse, for example a misspelt field name, and returns the rows that match the rest of the query. For a connector that means a typo in snow.table.<alias>.query can quietly turn active=true into "every row in the table", or, worse, a malformed cursor predicate can return rows it should not. With the property set, an invalid query returns no rows, which the connector notices immediately. The startup probe checks whether the instance ignores invalid query terms and warns when it does.

This is an instance-wide property that also affects list views and scripts. Discuss it with the instance owner; if it cannot be set, be doubly careful with per-table queries and test them in the REST API Explorer first.

5. Rate limit rules​

Administrators define inbound REST rate limits in All > System Web Services > REST > Rate Limit Rules (the label varies slightly by release). A rule caps requests per hour for a resource, a user, a role, or everyone. When a request exceeds a rule the instance answers 429 Too Many Requests with a Retry-After header.

The connectors treat 429 as retryable: they wait for the Retry-After interval when it is present, otherwise back off exponentially with jitter, and they never exceed snow.http.max.concurrent.requests in-flight requests to one instance. If you create a rule for the integration user, size it from the numbers in Rate limits so that steady-state polling stays inside it and only a backfill ever hits it.

6. Tables that are not suitable​

  • sys_audit, sys_audit_relation and sys_history_line are excluded. They are very large, are not designed to be scanned by sys_updated_on, and are not supported by Confluent's connectors either. If you need field-level history, poll the business table and let downstream consumers diff versions, or use the optional event bridge.
  • Database views work, but their columns carry the prefix of the underlying table (for example inc_sys_id and inc_sys_updated_on in a view over incident with variable prefix inc). Set snow.table.<alias>.sys.id.field and snow.table.<alias>.timestamp.field to the prefixed names; the connector orders and cursors on those columns and still keys records by the value it reads from the sys.id.field column.
  • Append-only tables such as log or event tables can be polled on sys_created_on by setting snow.table.<alias>.timestamp.field=sys_created_on, which avoids re-reading rows whose sys_updated_on is touched by housekeeping jobs.
  • Tables with encrypted or locale-dependent display values should be read with the default display.value=false; true and all cost more on the instance and depend on the user's locale and time zone.

Next steps​

Run the quickstart against the fake ServiceNow first, then register the production connector configuration with the user and OAuth client you created here.