Integrations

ServiceNow

Create and update ServiceNow incident records via inbound REST, keyed by correlation_id = Yorker incident ID.

ServiceNow

Yorker integrates with ServiceNow via inbound REST against the standard incident table. The first opened event creates a new incident record; subsequent lifecycle events update that record via correlation_id lookup — no sys_id round-trip required.

For the underlying model (lifecycle states, event types, scoped hypothesis), see Incidents.

Set up

Yorker needs an inbound REST credential with permission to create and update incident records.

  1. In ServiceNow, create a service account (or re-use an existing integration user) with the Incident table permissions needed to POST and PATCH.
  2. Note your instance URL (e.g. https://acme.service-now.com) and optionally the assignment group new incidents should route to.
  3. Create the channel in Yorker:
curl -X POST https://yorkermonitoring.com/api/notification-channels \
  -H "Authorization: Bearer $YORKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "snow-prod",
    "channel": {
      "type": "servicenow",
      "instanceUrl": "https://acme.service-now.com",
      "username": "yorker_integration",
      "password": "…",
      "assignmentGroup": "Network Operations"
    }
  }'
FieldRequiredDescription
instanceUrlyesBase URL of the ServiceNow instance
usernameyesIntegration user
passwordyesPassword or OAuth token (stored at rest; treated as secret)
assignmentGroupnoGroup name — maps to assignment_group on new incidents

Authentication is HTTP Basic over TLS.

Event mapping

Yorker eventActionNotes
openedPOST /incidentCreates record with correlation_id = incident_id
severity_changedPATCH recordUpdates impact, urgency, adds work_notes
acknowledgedPATCH recordSets state = 2 (Work in Progress), adds ack note
note_addedPATCH recordAppends to work_notes
auto_resolvedPATCH recordSets state = 6 (Resolved), fills close_code + close_notes
closedPATCH recordSets state = 6 (Resolved), uses Yorker closeReason
reopened(skipped)Yorker reopens create a new external ticket, not mutate the old
alert_attached(skipped)Internal-only

Updates target PATCH /api/now/table/incident?sysparm_query=correlation_id=<incident_id> — no sys_id is stored.

Field mapping (on opened)

ServiceNow fieldSource
short_descriptionpayload.hypothesis.summary (stripped of CR/LF, capped at 160)
descriptionHypothesis summary + observations summary + triage URL
work_notesscope: external_symptoms_only + ruled-out list
impact, urgencycritical → 1, warning → 2, info → 3
correlation_idYorker incident_id
correlation_display"Yorker Incident"
assignment_groupChannel config (if set)

Severity mapping

Yorker severityServiceNow impactServiceNow urgency
critical1 (High)1 (High)
warning2 (Medium)2 (Medium)
info3 (Low)3 (Low)

Why reopened isn't routed

ServiceNow's "Reopen" action reverts a closed incident to an active state on the same record. Yorker's recurrence model treats a new burst of correlated alerts after auto-resolution as a new incident with a pointer back to the prior one (recurrenceOf). Those two semantics don't map cleanly, so Yorker creates a new ServiceNow record on recurrence (via the next opened event) rather than mutating the closed one. Use the View in Yorker link on each record to pivot between related incidents.

Template overrides

Three fields are user-editable: short_description, description, and work_notes. The envelope (state, impact, urgency, correlation_id, assignment_group) stays under Yorker's control so the lookup pattern and severity mapping remain consistent.

curl -X PUT https://yorkermonitoring.com/api/notification-channels/nch_abc \
  -H "Authorization: Bearer $YORKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "incidentTemplate": {
      "channelType": "servicenow",
      "overrides": {
        "opened": {
          "shortDescription": "[{{upperCase incident.severity}}] {{incident.title}}",
          "description": "Yorker incident {{incident.incidentId}}\n\nHypothesis: {{payload.hypothesis.summary}}\n\nTriage: {{incident.triageUrl}}",
          "workNotes": "Scope: {{payload.hypothesis.scope}}\nRuled out:\n{{#each payload.hypothesis.ruledOut}}  - {{this}}\n{{/each}}"
        }
      }
    }
  }'

Template render failures fall back to the default string and log a warning. Dispatch never fails on a bad template.

Helpers and render context are the same as the Slack integration.

short_description is always stripped of CR/LF (header injection guard) and capped at 160 characters after render.

Disabling

The ServiceNow channel type is incident-pipeline-only — it has no legacy per-alert dispatch path. incidentSubscribed is locked to true for ServiceNow channels; the API rejects create/update requests that set it to false. To stop routing incidents to a ServiceNow channel, delete it or remove it from the alert rule's channel list.