← ITSM ticket routing overview

GUIDES · SERVICENOW · IT SERVICE MANAGEMENT

Suggest Category and Assignment group in ServiceNow from your own tickets

Train on resolved incidents and suggest Category and Assignment group in ServiceNow. A tested business-rule example with confidence thresholds and human review.

By StayCharted · · Updated

How the connection works

When a new incident arrives, a business rule sends its short description and description to your StayCharted model. The model answers with the category and assignment group your team would most likely choose, and how sure it is. If it's sure enough, the rule fills in whatever nobody has chosen yet. Either way, it writes a work note:

Show Code example
INC0010007 · "Outlook keeps asking for my password"

Work note   StayCharted: Category Software, Assignment group Service Desk, 80% sure.
            Filled in: Category, Assignment group.

Allow about an hour for setup, plus time to prepare your history and review the model’s report. The example above used a fill threshold of 0.75. With the script’s default of 0.9, that same 80% answer would add a note without filling fields.

Tested. We ran every step below on a ServiceNow Personal Developer Instance in October 2026, with made-up tickets. The four cases worked as described: a confident answer filled the fields, an unsure one only added a note, a person's choice was kept, and a missing API key left the incident untouched with a note. Results on your tickets depend on your history; Part 2 shows you how often the model is right before you connect it.

Before you start

  • ServiceNow: the admin role, or a developer who can create system properties and business rules.
  • StayCharted: an Essentials or Business workspace, which the API needs. Training itself works on every plan, Free included, so you can read the report first.
  • Outbound HTTPS from your instance to amt.staycharted.com. Most instances allow it; your administrator can confirm.

Part 1: Export resolved incidents

  1. Open Incident → All. Filter to State is Resolved or Closed, and Resolved in the last 12 months. For a first model, narrow it to one service or assignment group family.
  2. Show these columns (right-click a column header → Configure → List Layout): Short description, Description, Location, Category, Assignment group. Add other fields known when the ticket was opened, such as the caller's department.
  3. Right-click a column header → Export → CSV.

Three rules matter more than the model you pick:

  • Use the final values. Category and Assignment group on a resolved incident are what your team settled on. The group a ticket went to first is often the mistake you're trying to avoid.
  • Leave out anything filled in later: resolution notes, close code, "resolved by". They make the test score look great and the model useless on new incidents.
  • Personal information: StayCharted's Data quality step finds email addresses and phone numbers before training, so you can mask them.

Part 2: Train the model

  1. In StayCharted, choose New model and upload the CSV.
  2. Columns the model reads: Short description, Description, Location (and any other opening fields you exported).
  3. Answer: choose both Category and Assignment group. The model learns them together and answers both, with one confidence for the pair.
  4. Choose the AI Classifier Model, which reads meaning as well as words, and train.
  5. Read the report by category before anything else. An overall 95% can hide a group the model gets right only half the time. Look at the mistakes: they often show incidents filed in the wrong group, which you can fix and retrain.
  6. Look at the review table: for each confidence, how many answers fall below it and how many of the model's mistakes those include. You'll use it to set the fill confidence in Part 3.
  7. Publish the version you're happy with. On the model's page, the Use tab shows the model id under Prediction API.
  8. Create an API key: Settings → API keys. Keep it somewhere safe; you'll paste it once, in Part 3.

Part 3: Connect ServiceNow

1. Store the model id and the key as system properties. In the navigator (the search box at the top left), type sys_properties.list and press Enter. Click New for each:

Name Type Value
staycharted.model_id string the model id from Part 2
staycharted.api_key password2 the API key. Paste it here only, never into a script
staycharted.fill_confidence string optional: the confidence at or above which fields are filled, 0 to 1. Leave it out for 0.9

2. Add the business rule. Go to System Definition → Business Rules → New:

  • Name: StayCharted suggestion
  • Table: Incident [incident]
  • Tick Advanced.
  • When to run: When async, tick Insert. Async means the incident saves at once and the suggestion arrives a few seconds later.
  • Advanced tab: paste the script below, then Submit.
Show ServiceNow business-rule script
// StayCharted: suggest Category and Assignment group for a new incident.
//
// Business rule settings:
//   Name:     StayCharted suggestion
//   Table:    Incident [incident]
//   Advanced: checked
//   When:     async      Insert: checked
//
// Needs two system properties (sys_properties):
//   staycharted.model_id  (string)    the model's id from StayCharted
//   staycharted.api_key   (password2) the API key; never paste the key into this script
// Optional:
//   staycharted.base_url        (string)  defaults to https://amt.staycharted.com
//   staycharted.fill_confidence (string)  fill fields only at or above this
//                                         confidence, 0 to 1; default 0.9.
//                                         Below it, the answer is a work note only.
(function executeRule(current, previous) {
    var modelId = gs.getProperty('staycharted.model_id');
    var apiKey = gs.getProperty('staycharted.api_key');
    var base = gs.getProperty('staycharted.base_url', 'https://amt.staycharted.com');
    var url = base + '/api/v1/models/' + modelId + '/classify';
    var fillAt = parseFloat(gs.getProperty('staycharted.fill_confidence', '0.9'));

    // Same field names as the columns the model was trained on.
    var body = { input: {
        'Short description': current.getValue('short_description') || '',
        'Description':       current.getValue('description') || '',
        'Location':          current.getDisplayValue('location') || ''
    } };

    var note;
    try {
        var rm = new sn_ws.RESTMessageV2();
        rm.setEndpoint(url);
        rm.setHttpMethod('post');
        rm.setRequestHeader('Authorization', 'Bearer ' + apiKey);
        rm.setRequestHeader('Content-Type', 'application/json');
        rm.setRequestBody(JSON.stringify(body));
        rm.setHttpTimeout(20000);
        var res = rm.execute();
        var status = res.getStatusCode();
        if (status != 200) throw 'HTTP ' + status + ' ' + res.getBody();
        var a = JSON.parse(res.getBody());
        var f = a.fields || {};
        var pct = Math.round((a.confidence || 0) * 100);
        note = 'StayCharted: Category ' + (f['Category'] || '?') +
               ', Assignment group ' + (f['Assignment group'] || '?') + ', ' + pct + '% sure.';

        if (a.needsReview || (a.confidence || 0) < fillAt) {
            note += ' Not sure enough to fill anything in: triage as usual.';
        } else {
            // Fill only what nobody chose. A stock instance pre-fills Category
            // with its default ("Inquiry / Help"), so the default counts as
            // not chosen. Never overwrite anything else a person picked.
            var filled = [];
            if (f['Category'] && notChosen('category')) {
                current.setDisplayValue('category', f['Category']);
                filled.push('Category');
            }
            if (!current.getValue('assignment_group') && f['Assignment group']) {
                current.setDisplayValue('assignment_group', f['Assignment group']);
                filled.push('Assignment group');
            }
            note += filled.length ? ' Filled in: ' + filled.join(', ') + '.'
                                  : ' Left the fields as they were chosen.';
        }
    } catch (e) {
        note = 'StayCharted suggestion unavailable (' + e + '). Triage as usual.';
    }
    current.work_notes = note;
    current.update();

    function notChosen(field) {
        var value = current.getValue(field);
        if (!value) return true;
        var d = new GlideRecord('sys_dictionary');
        d.addQuery('name', current.getTableName());
        d.addQuery('element', field);
        d.query();
        return d.next() && value == d.getValue('default_value');
    }
})(current, previous);

If you trained on other columns, change the input names to match them exactly; fields the model doesn't read are ignored.

3. Test it. Create an incident with a short description your team sees often, leave Category at its default and Assignment group empty, and save. Reopen it after a few seconds: the work notes show the model's answer, and the fields are filled if it was sure enough.

What the rule does, and doesn't:

  • It fills only what nobody chose. A stock instance pre-fills Category with "Inquiry / Help", so the rule treats that default as not chosen. A person-selected Category equal to the configured default is indistinguishable from an untouched default, so it can be replaced. Test your default and assignment rules before enabling field fills.
  • Below the fill confidence, it fills nothing and notes "Not sure enough to fill anything in: triage as usual." Start at 0.9 and lower it only if the report shows answers at that level are almost always right.
  • If StayCharted can't answer (no key, a network problem, a model switched off), it notes "StayCharted suggestion unavailable … Triage as usual" and changes nothing.
  • It never changes anything else. Priority, state and the caller stay as they were.

Before using this in production: keep this rule insert-only. The tested sample uses current.update(); ServiceNow advises against this pattern and warns that asynchronous updates can conflict with other updates. Have your ServiceNow developer review concurrent edits and existing business rules before enabling automatic fills. ServiceNow business-rule guidance.

Part 4: Review and retrain

  • Your team corrects in ServiceNow, as today. When someone changes a filled-in category or group, the resolved incident records the right answer.
  • Retrain monthly by exporting the last 12 months again (Part 1). The corrections are in the export as final values, so the model follows your current groups, not last year's.
  • Review Queue (Essentials and Business): answers below the model's review cutoff also wait there. Pick one place to review; checking the same incident in both is wasted work.
  • Publish a new version only if its report is better, category by category.

Variations

  • Requested Items: the same rule on Requested Item [sc_req_item], sending the catalog item's variables (for example current.variables.business_justification) instead of the description. This variation needs separate implementation and testing; see the access-request workflow overview.
  • Priority: ServiceNow calculates Priority from Impact and Urgency, so train on Urgency (or Impact) rather than Priority, and fill that field.
  • Flow Designer: if you have IntegrationHub, a REST step in a flow can make the same call. The business rule needs no extra subscription.
  • Other tools: the call is the same from Jira Service Management, Freshservice and others. See AI ticket routing for any ITSM tool.

Which StayCharted model to use

ServiceNow is a trademark of ServiceNow, Inc. StayCharted is not affiliated with ServiceNow.

Common questions

Does StayCharted connect to our ServiceNow instance?

No. Your instance calls StayCharted; StayCharted never calls in. It receives only the fields the rule sends, for that one incident.

Where is the API key stored?

In a password2 system property, encrypted in your instance, and read by the rule when it runs. It never appears in the script.

Does it slow down saving an incident?

No. The rule runs asynchronously after the incident is saved.

How does it count against our plan?

Each new incident is one prediction against your workspace's monthly allowance, shown in StayCharted under Plan & usage.

Can it close or reassign tickets?

No. It fills Category and Assignment group only when they're unset and the model is sure, and it writes a note. Everything else stays with your team.

Put it into practice

Explore support ticket routing →

Model training best practices · API reference

STAYCHARTED AI MODEL TRAINER

Train AI to categorize the way your team does.

Start with examples you already have, see how often it’s right on items it never saw, and use confidence to prioritize the ones a person should review.

Start free