Week 19: REST Integrations: Table API & Scripted REST APIs

Everything you've built so far assumes something is inside ServiceNow talking to something else inside ServiceNow. This week is the first time something outside the platform gets a defined, controlled way in — and the first time you define an endpoint of your own instead of only consuming ones the platform ships.

Module 19 of 25 Week 19 of 26 ~3–4 Hours Hands-on Exercise Included

By the end of this week, you'll be able to

  • Call the built-in Table API to read and write records from outside the instance
  • Build a Scripted REST API resource exposing custom logic as an HTTP endpoint
  • Call a Scripted REST API from server-side script, including from within a widget

1. The Built-In Table API

Every table on the platform is automatically reachable over REST at /api/now/table/{tableName}, with standard HTTP verbs mapping to CRUD: GET to query, POST to insert, PUT/PATCH to update, DELETE to remove — respecting the exact same ACLs (Week 7) that govern access through the UI.

Table API — GET request (conceptual)
GET https://your-instance.service-now.com/api/now/table/incident
    ?sysparm_query=priority=1^active=true
    &sysparm_limit=10

Response: { "result": [ { "sys_id": "...", "number": "INC0010001", ... }, ... ] }

Notice sysparm_query takes the exact same encoded query syntax from Week 4's addEncodedQuery() — it's genuinely the same query engine, just reached over HTTP instead of GlideRecord.

2. Authentication

REST calls into an instance authenticate the same way a user would, just without a browser session: Basic Auth (username/password, simplest, not recommended for production integrations) or OAuth 2.0 (token-based, the recommended approach for anything beyond quick testing) — both configured via records in the instance (OAuth requires registering an Application Registry first).

3. Building a Scripted REST API

The Table API is generic — it doesn't know your business logic. A Scripted REST API (System Web Services > Scripted REST APIs) lets you define your own endpoint with custom logic, following a fixed function signature every resource script uses:

Scripted REST API resource — GET /api/x_yourscope_app/incidents/summary
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
  var groupSysId = request.queryParams.group;

  var utils = new IncidentUtils(); // the Script Include from Week 6, reused here
  var body = {
    open: utils.countOpenByGroup(groupSysId),
    overdue: utils.countOverdueByGroup(groupSysId)
  };

  return body; // automatically serialized to JSON in the response
})(request, response);

Notice this reuses IncidentUtils from Week 6 without modification — the same benefit of extracting logic into a Script Include instead of writing it inline pays off again here, exactly as it did when IncidentAjax wrapped it for GlideAjax back in Week 8.

4. Calling a Scripted REST API from Server Script

Server-side script (a widget's server script, a Business Rule, a Script Include) can call any REST endpoint — including your own Scripted REST API, or a completely external one — using RESTMessageV2:

Server Script — calling an external REST endpoint
var request = new sn_ws.RESTMessageV2();
request.setEndpoint('https://api.example.com/v1/status');
request.setHttpMethod('GET');
request.setRequestHeader('Authorization', 'Bearer ' + token);

var response = request.execute();
var body = JSON.parse(response.getBody());

5. Hands-on Exercise

Hands-on

Build and test your own Scripted REST API

Requirements:

  1. Create a Scripted REST API named "Incident Utils API" with a GET resource at /summary, implemented as shown above.
  2. Test it using the built-in REST API Explorer (System Web Services > REST API Explorer) rather than an external tool, to confirm the response shape.
  3. Separately, use the Table API directly: issue a GET request against /api/now/table/incident with an encoded query filtering to P1 incidents, using the REST API Explorer's Table API section.
  4. Compare the two response shapes and note, in your own words, why a Scripted REST API was worth building instead of just querying the Table API for the same data every time.

6. Knowledge Check

Four quick questions. Expand each to check your answer.

Q1

What does the built-in Table API give you access to that you don't have to build yourself?

Every table on the platform is automatically reachable over REST at /api/now/table/{tableName}, with GET/POST/PUT/DELETE mapping to standard CRUD operations and respecting the same ACLs the UI does — no custom endpoint code required for basic table access.

Q2

Why is a Scripted REST API sometimes worth building instead of just using the Table API?

The Table API is generic — it exposes raw table data but knows nothing about your specific business logic. A Scripted REST API lets you define an endpoint that runs custom logic (aggregating data from multiple tables, applying business rules, reusing a Script Include) and returns exactly the shape a consumer needs, rather than requiring the caller to replicate that logic on their end.

Q3

What is the fixed function signature every Scripted REST API resource script follows?

function process(request, response) { ... }, immediately invoked with request and response passed in — request gives access to query params, path params and the request body; whatever the function returns is automatically serialized to JSON in the response.

Q4

What does RESTMessageV2 let a server-side script do that GlideRecord can't?

GlideRecord only reads and writes ServiceNow's own tables. RESTMessageV2 lets server-side script make an outbound HTTP call to any REST endpoint — a completely external system, or even the instance's own Scripted REST API — setting the method, headers and body needed for that call.