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
| Connector | What it needs | Notes |
|---|---|---|
| Source | Read access to every configured table or view, including the sys_id and timestamp fields and every projected field | Granted 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 |
| Sink | Create, write and delete access on every target table, as the operations you use require | A sink that only patches needs write, not delete |
Either, when snow.table.<alias>.query.domain=false | query_no_domain_table_api | The 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.
OAuth 2.0 client credentials (recommended)
The client credentials grant is disabled by default on ServiceNow instances. To enable it:
- In All > System Properties > All Properties (or
sys_properties.list), create or setglide.oauth.inbound.client.credential.grant_type.enabledtotrue. - 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.
4. Recommended instance property
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_relationandsys_history_lineare excluded. They are very large, are not designed to be scanned bysys_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_idandinc_sys_updated_onin a view overincidentwith variable prefixinc). Setsnow.table.<alias>.sys.id.fieldandsnow.table.<alias>.timestamp.fieldto the prefixed names; the connector orders and cursors on those columns and still keys records by the value it reads from thesys.id.fieldcolumn. - Append-only tables such as log or event tables can be polled on
sys_created_onby settingsnow.table.<alias>.timestamp.field=sys_created_on, which avoids re-reading rows whosesys_updated_onis touched by housekeeping jobs. - Tables with encrypted or locale-dependent display values should be read with the
default
display.value=false;trueandallcost 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.