Integrate with ServiceNow
This document provides a step-by-step guide to integrate Versus Incident with ServiceNow for on-call management. The integration escalates unacknowledged alerts into ServiceNow by creating records through the ServiceNow Table API.
We'll cover setting up ServiceNow, configuring the integration with Versus, deploying Versus, and testing the integration with practical examples.
Prerequisites
Before you begin, ensure you have:
- A ServiceNow instance (a free Developer instance works for testing)
- Versus Incident deployed (instructions provided later)
- Prometheus Alert Manager set up to monitor your systems
Setting Up ServiceNow for On-Call
Let's configure a practical example in ServiceNow with a dedicated integration user and the target table.
1. Create an Integration User
First, create a user that Versus will authenticate as when creating records:
- Log in to your ServiceNow instance as an administrator
- Navigate to User Administration > Users > New
- Fill in the user details:
- User ID (e.g.,
versus.integration) - First/Last name (e.g., "Versus Integration")
- Set a strong password
- Check Web service access only so the account cannot log in to the UI
- User ID (e.g.,
- Submit to create the user
2. Grant Table Permissions
The integration user needs permission to create records on the target table (the incident table by default):
- Navigate to User Administration > Roles
- Assign a role that allows record creation on your target table:
- For the
incidenttable, theitilrole is the common choice - For a custom table, create or assign a role with
createaccess
- For the
- Open the integration user and add the role under the Roles tab
- Save the user
Note: Follow least-privilege. Grant only the access needed to create records on the one table Versus writes to — nothing more.
3. Identify Your Instance URL and Table
You need two values for the Versus configuration:
- Instance URL — the base URL of your instance, e.g.
https://dev12345.service-now.com - Table — the table records are created in. Versus defaults to
incident. To use a different table (e.g. a customu_versus_alert), note its name.
4. Confirm the Table API Endpoint
Versus posts records to the standard Table API path:
{instance_url}/api/now/table/{table}
For example, with the default table:
https://dev12345.service-now.com/api/now/table/incident
You can verify access from your terminal before wiring up Versus:
curl -u "versus.integration:YOUR_PASSWORD" \
-H "Content-Type: application/json" \
-X POST "https://dev12345.service-now.com/api/now/table/incident" \
-d '{"short_description":"Versus connectivity test","correlation_id":"test-001"}'
A 201 Created response confirms the user and permissions are correct.
How the Mapping Works
When an alert escalates, Versus sends an HTTP POST to the Table API with HTTP Basic auth and maps the incident onto two fields:
| ServiceNow field | Value |
|---|---|
short_description | A human-readable summary (Incident <id>) |
correlation_id | The incident ID, used by ServiceNow to de-duplicate inbound events |
The request uses the shared HTTPS client with TLS verification enabled. A non-2xx response is treated as a failure and logged. Credentials are never written to logs.
Deploy Versus Incident
Now let's deploy Versus with ServiceNow integration. You can use Docker or Kubernetes.
Docker Deployment
Create a directory for your configuration files:
mkdir -p ./config
Create config/config.yaml with the following content:
name: versus
host: 0.0.0.0
port: 3000
public_host: https://your-ack-host.example
alert:
debug_body: true
slack:
enable: true
token: ${SLACK_TOKEN}
channel_id: ${SLACK_CHANNEL_ID}
template_path: "config/slack_message.tmpl"
oncall:
enable: true
wait_minutes: 3
provider: servicenow
servicenow:
instance_url: ${SERVICENOW_INSTANCE_URL} # e.g. https://dev12345.service-now.com (REQUIRED)
username: ${SERVICENOW_USERNAME} # REQUIRED
password: ${SERVICENOW_PASSWORD} # REQUIRED
table: incident # ServiceNow table; defaults to "incident"
other_instance_urls: # Optional: per-request instance override
infra: ${SERVICENOW_OTHER_INSTANCE_URL_INFRA}
app: ${SERVICENOW_OTHER_INSTANCE_URL_APP}
db: ${SERVICENOW_OTHER_INSTANCE_URL_DB}
redis: # Required for on-call functionality
insecure_skip_verify: true # dev only
host: ${REDIS_HOST}
port: ${REDIS_PORT}
password: ${REDIS_PASSWORD}
db: 0
By default, Versus adds an interactive acknowledgment button to Slack notifications when on-call is enabled, using the unified template shipped in config/slack_message.tmpl. If the alert is acknowledged before wait_minutes elapses, ServiceNow is never called.
Create the docker-compose.yml file:
version: '3.8'
services:
versus:
image: ghcr.io/versuscontrol/versus-incident
ports:
- "3000:3000"
environment:
- SLACK_TOKEN=your_slack_token
- SLACK_CHANNEL_ID=your_channel_id
- SERVICENOW_INSTANCE_URL=https://dev12345.service-now.com
- SERVICENOW_USERNAME=versus.integration
- SERVICENOW_PASSWORD=your_servicenow_password
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=your_redis_password
volumes:
- ./config:/app/config:ro
depends_on:
- redis
redis:
image: redis:6.2-alpine
command: redis-server --requirepass your_redis_password
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
redis_data:
Run Docker Compose:
docker-compose up -d
Warning: Always provide
usernameandpasswordthrough environment variables. Never commit credentials toconfig.yaml.
Alert Manager Routing Configuration
Now, let's configure Alert Manager to route alerts to Versus with different behaviors:
Send Alert Only (No On-Call)
receivers:
- name: 'versus-no-oncall'
webhook_configs:
- url: 'http://versus-service:3000/api/incidents?oncall_enable=false'
send_resolved: false
route:
receiver: 'versus-no-oncall'
group_by: ['alertname', 'service']
routes:
- match:
severity: warning
receiver: 'versus-no-oncall'
Send Alert with Acknowledgment Wait
receivers:
- name: 'versus-with-ack'
webhook_configs:
- url: 'http://versus-service:3000/api/incidents?oncall_wait_minutes=5'
send_resolved: false
route:
routes:
- match:
severity: critical
receiver: 'versus-with-ack'
This waits 5 minutes for acknowledgment before creating a ServiceNow record if the user doesn't click the ACK link in Slack.
Send Alert with Immediate On-Call Trigger
receivers:
- name: 'versus-immediate'
webhook_configs:
- url: 'http://versus-service:3000/api/incidents?oncall_wait_minutes=0'
send_resolved: false
route:
routes:
- match:
severity: urgent
receiver: 'versus-immediate'
This creates a ServiceNow record immediately without waiting.
Override the ServiceNow Instance per Alert
You can route specific alerts to a different ServiceNow instance using the servicenow_other_instance query parameter instead of exposing instance URLs directly. The value must match a key under other_instance_urls:
receivers:
- name: 'versus-servicenow-infra'
webhook_configs:
- url: 'http://versus-service:3000/api/incidents?servicenow_other_instance=infra'
send_resolved: false
route:
routes:
- match:
team: infrastructure
receiver: 'versus-servicenow-infra'
This routes infrastructure team alerts to the instance named infra, which is mapped in your configuration file:
oncall:
provider: servicenow
servicenow:
instance_url: ${SERVICENOW_INSTANCE_URL}
username: ${SERVICENOW_USERNAME}
password: ${SERVICENOW_PASSWORD}
other_instance_urls:
infra: ${SERVICENOW_OTHER_INSTANCE_URL_INFRA}
app: ${SERVICENOW_OTHER_INSTANCE_URL_APP}
db: ${SERVICENOW_OTHER_INSTANCE_URL_DB}
The override applies to that single request only; the global config is never mutated.
Warning: Every URL listed under
other_instance_urlsis reached with the same defaultusernameandpassword. Only point overrides at instances that share the same credential trust domain.
Testing the Integration
Let's test the complete workflow:
-
Trigger an Alert:
- Simulate a critical alert in Prometheus to match the Alert Manager rule.
-
Verify Versus:
- Check that Versus receives the alert and sends it to Slack.
- You should see a message with an acknowledgment link.
-
Check Escalation:
- Option 1: Click the ACK link to acknowledge the incident — ServiceNow should not receive a record.
- Option 2: Wait for the acknowledgment timeout (e.g., 5 minutes) without clicking the link.
- In ServiceNow, open the target table (e.g. Incident > All) and confirm a new record was created with the matching
short_descriptionandcorrelation_id.
-
Immediate Trigger Test:
- Send an urgent alert and confirm a record is created in ServiceNow instantly.
How It Works Under the Hood
When Versus integrates with ServiceNow, the following occurs:
- Versus receives an alert from Alert Manager.
- If on-call is enabled and the acknowledgment period passes without an ACK, Versus:
- Builds a Table API payload with
short_descriptionandcorrelation_id. - Sends an authenticated
POSTto{instance_url}/api/now/table/{table}using HTTP Basic auth.
- Builds a Table API payload with
- ServiceNow creates the record on the target table, where it flows into your existing assignment rules, workflows, and notifications.
Conclusion
You've now integrated Versus Incident with ServiceNow for on-call management. Alerts from Prometheus Alert Manager can create ServiceNow records via Versus when they go unacknowledged.
This integration provides:
- A delay period for engineers to acknowledge incidents before a record is created
- Slack notifications with one-click acknowledgment
- De-duplication through the
correlation_idfield - Per-alert routing to different ServiceNow instances
For the full configuration reference, see ServiceNow. Adjust the configuration as needed for your environment and incident response processes.