0

Create change request

by
Published today

Create a normal, emergency or standard change request through the Change Management API (/api/sn_chg_rest). A standard change takes a standard change template sys_id. Returns sys_id, number and state.

Script servicenow Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 6 hours ago
1
//native
2

3
function authHeader(auth: RT.Servicenow) {
4
  return auth.token
5
    ? `Bearer ${auth.token}`
6
    : `Basic ${btoa(`${auth.username}:${auth.password}`)}`
7
}
8

9
// Change Management API fields come back as { value, display_value }.
10
function value(field: any) {
11
  return field != null && typeof field === "object" ? field.value : field
12
}
13

14
function label(field: any) {
15
  return field != null && typeof field === "object"
16
    ? field.display_value
17
    : field
18
}
19

20
/**
21
 * Create Change Request
22
 * Create a normal, emergency or standard change request through the Change Management API (/api/sn_chg_rest, documented in the Yokohama and Brazil API references; needs the itil, change_manager or admin role). A standard change takes the sys_id of a standard change template (std_change_record_producer), whose description and plans cannot be overridden. Reference fields (assignment_group, cmdb_ci) take sys_ids; dates use 'YYYY-MM-DD HH:MM:SS' in UTC. Returns sys_id, number, state and the full record; fields ServiceNow did not apply are listed in ignored_fields.
23
 */
24
export async function main(
25
  auth: RT.Servicenow,
26
  type: "normal" | "emergency" | "standard",
27
  short_description: string,
28
  standard_change_template_id: string | undefined,
29
  description: string | undefined,
30
  assignment_group: string | undefined,
31
  cmdb_ci: string | undefined,
32
  start_date: string | undefined,
33
  end_date: string | undefined,
34
  fields: { [key: string]: any } | undefined
35
) {
36
  let path: string
37
  if (type === "standard") {
38
    if (!standard_change_template_id) {
39
      throw new Error(
40
        "standard_change_template_id is required for a standard change"
41
      )
42
    }
43
    path = `change/standard/${encodeURIComponent(standard_change_template_id)}`
44
  } else if (type === "normal" || type === "emergency") {
45
    path = `change/${type}`
46
  } else {
47
    throw new Error(`Unknown change type: ${type}`)
48
  }
49

50
  // The create endpoints take the record fields as query parameters, not a JSON body.
51
  const url = new URL(`${auth.instance_url}/api/sn_chg_rest/${path}`)
52
  const values: { [key: string]: any } = {
53
    ...(fields ?? {}),
54
    short_description,
55
    description,
56
    assignment_group,
57
    cmdb_ci,
58
    start_date,
59
    end_date,
60
  }
61
  for (const [key, v] of Object.entries(values)) {
62
    if (v != null && v !== "") {
63
      url.searchParams.append(
64
        key,
65
        typeof v === "object" ? JSON.stringify(v) : String(v)
66
      )
67
    }
68
  }
69

70
  const response = await fetch(url, {
71
    method: "POST",
72
    headers: {
73
      Authorization: authHeader(auth),
74
      Accept: "application/json",
75
    },
76
  })
77

78
  if (!response.ok) {
79
    throw new Error(`${response.status} ${await response.text()}`)
80
  }
81

82
  const { result } = (await response.json()) as { result: any }
83
  return {
84
    sys_id: value(result.sys_id),
85
    number: value(result.number),
86
    state: value(result.state),
87
    state_label: label(result.state),
88
    ignored_fields: result.__meta?.ignoredFields ?? [],
89
    record: result,
90
  }
91
}
92