ServiceNow Integration
Keep ServiceNow as your system of record. AscendCore becomes the approval-gated system of action on top: incidents flow in, a human approves in Slack or Teams, the runbook executes, and the decision is written back to the ticket. No migration.
In one sentence
A ServiceNow Business Rule POSTs new incidents to AscendCore, where the ticket is AI-classified into a runbook, held for explicit human approval, executed against your identity stack, and the outcome lands back on the originating ticket as a work note with an audit-chain reference.
How a ticket flows
- Ingest. Your Business Rule POSTs the incident to
POST /api/v1/tickets/ingestwith a scoped API key. One ticket is ingested at most once: retries and rule re-fires return the original run instead of posting a second card. - Classify. AscendCore classifies the ticket text into a runbook intent with a confidence score. Low-confidence or unrecognized tickets are received, audit-logged, and left alone (
no_action). Nothing executes on a guess. - Approve.The matching runbook's approval card is posted to your IT admin channel (Slack, or Teams for Teams-channel orgs), with a threaded note showing the originating ticket number, a link back to it, and the AI's classification and confidence. A human approves or denies. Every runbook is approval-gated. There is no autonomous path.
- Execute.On approval, the runbook runs against your stack (Okta, Entra ID, M365) and the action is recorded on the org's tamper-evident SHA-256 audit chain.
- Write back. The decision (approved or denied, by whom, at what time) is appended to the originating ticket as a work note. Your ITSM keeps the complete story.
Step 1: Create a scoped API key
In your admin portal under API, create a key with the ticket:ingest scope. Least privilege applies: a key with only this scope can submit tickets but cannot execute runbooks directly, read audit rows, or browse the catalog.
Store the key in a ServiceNow system property (or a credential record), not in the Business Rule body.
Step 2: Add the Business Rule
Create an async Business Rule on the incident table, when: after insert, with two system properties (ascendcore.ingest_url, ascendcore.api_key) configured first:
(function executeRule(current /*GlideRecord: incident*/) {
try {
// System properties (set once under sys_properties.list):
// ascendcore.ingest_url = https://ascendcore.ai/api/v1/tickets/ingest
// ascendcore.api_key = ak_live_... (scope: ticket:ingest)
var endpoint = gs.getProperty('ascendcore.ingest_url');
var apiKey = gs.getProperty('ascendcore.api_key');
if (!endpoint || !apiKey) {
gs.warn('[AscendCore] ingest skipped: properties not configured');
return;
}
var instance = gs.getProperty('glide.servlet.uri');
var body = {
source: 'servicenow',
ticket: {
sysId: current.getUniqueValue(),
number: current.getValue('number'),
shortDescription: current.getValue('short_description'),
description: current.getValue('description') || undefined,
url: instance + 'nav_to.do?uri=incident.do?sys_id=' + current.getUniqueValue(),
callerEmail: current.caller_id.email
? current.caller_id.email.toString()
: undefined
}
};
var r = new sn_ws.RESTMessageV2();
r.setEndpoint(endpoint);
r.setHttpMethod('POST');
r.setRequestHeader('Authorization', 'Bearer ' + apiKey);
r.setRequestHeader('Content-Type', 'application/json');
r.setRequestBody(JSON.stringify(body));
var resp = r.execute();
gs.info('[AscendCore] ingest ' + current.getValue('number') +
' -> HTTP ' + resp.getStatusCode());
} catch (e) {
gs.error('[AscendCore] ingest failed: ' + e);
}
})(current);Flow Designer works equally well: use an outbound REST step with the same payload and headers. Scope the rule with a filter (for example, category = account access) if you only want a subset of incidents routed to AscendCore.
Payload reference
| Field | Required | Purpose |
|---|---|---|
source | Yes | Must be "servicenow" in this release. |
ticket.sysId | Yes | Incident sys_id. Idempotency key and write-back target. |
ticket.number | Yes | Human-readable number (INC0010234). Shown to the approver. |
ticket.shortDescription | Yes | Primary classification input. |
ticket.description | No | Appended to the classification input when present. |
ticket.url | No | Deep link back to the ticket, shown in the approval thread. |
ticket.callerEmail | No | Target-user fallback when the ticket text names nobody else. |
Supported intents in this release
| Intent | Runbook | System |
|---|---|---|
| MFA reset | RB-002 | Okta |
| Password reset | RB-001 | Okta |
| Offboarding (suspend account) | RB-011 | Okta |
| Account unlock | RB-007 | Microsoft Entra ID |
| M365 license assignment | RB-006 | M365 |
| Group add / remove (group named in the ticket) | RB-013 | Microsoft Entra ID |
| New hire provisioning (name and email in the ticket) | RB-003 | Okta + M365 |
Tickets that classify to anything else are acknowledged with no_action and audit-logged. Additional intents arrive as additive extensions; your Business Rule does not change.
What the write-back looks like
When the approval reaches a decision (from Slack, Teams, or the dashboard), AscendCore appends a work note to the originating incident:
[AscendCore] Runbook decision: APPROVED
Runbook: MFA Reset
Target user: Sarah Chen (sarah.chen@acme.com)
Decision by: slack:U0123APPROVER at 2026-06-09T17:42:11.310Z
Action executed by AscendCore after explicit human approval.
This decision is recorded on the org's tamper-evident audit chain in AscendCore.Denied requests get a work note too, stating that no changes were made. The write-back is deliberately non-blocking: if your instance is unreachable, the approval flow itself is unaffected and the decision remains on the AscendCore audit chain.
Security model
- Scoped bearer auth.The integration reuses AscendCore's standard API-key model. Keys are salted-hashed at rest, scope-gated, rate-limited, and revocable from the dashboard.
- Approval-gated, always. Ingested tickets follow the same human-in-the-loop policy as every other trigger. AI classifies; it never executes.
- Audit-chained.Every ingestion (including no-action dispositions) and every decision is recorded on the org's tamper-evident SHA-256 audit chain, usable as evidence for SOC 2 and ISO 27001 reviews.
- Idempotent. Duplicate submissions of the same incident return the original run. Retry storms cannot flood your approval channel.
- Sandbox-aware. If your org is in Sandbox Mode, ingested tickets exercise the full approval flow with mocked execution and no real write-back.
Full API reference
The complete request/response contract for POST /api/v1/tickets/ingest (dispositions, error codes, schemas) lives in the OpenAPI reference. Using Jira instead? See the Jira guide.
