Scripted REST APIs let you expose custom ServiceNow data and business logic through clean REST endpoints that external systems can call. You'll build the service definition, configure resources for different HTTP methods, and write the server-side script that handles requests and responses.
Why custom REST APIs matter
Before Scripted REST APIs, integrating with ServiceNow meant either using the generic Table API (which exposes your entire data model) or building custom web services with complex SOAP. External teams needed ServiceNow data but didn't want to learn your table structure. Internal teams needed to expose business logic — like "get my open requests" or "submit this specific type of incident" — but the Table API required multiple calls and knowledge of ServiceNow's field names. Platform teams spent time building integration middleware or writing documentation for APIs that exposed too much.
How Scripted REST APIs work
A Scripted REST API has two parts: the service definition (namespace, authentication, documentation) and resources (the actual endpoints with HTTP methods). Each resource maps to a URL path and contains server-side JavaScript that receives a request object and builds a response object. You control exactly what data goes out and what operations are allowed. Start with a simple GET that returns static data, then add POST for creating records, proper error handling, and field validation. The progression is: working endpoint, real data queries, input validation, proper HTTP status codes, then authentication and rate limiting.
Production-quality improvements
Once your basic API works, focus on reliability and security. Add proper error handling that returns consistent JSON error responses instead of letting exceptions bubble up. Implement field-level validation and return specific error messages for bad input. Use GlideRecord's setLimit() to prevent runaway queries. Add logging for debugging integration issues. Consider whether you need API versioning (add /v1/ to your paths now if you might). For high-volume APIs, implement caching and consider async processing for expensive operations.
Before you start
- •rest_api_explorer or admin role
- •Understanding of HTTP methods and REST conventions
Sourdough: ServiceNow Monitoring and Analytics
A Chrome extension for ServiceNow Admins and Developers with essential tools, analytics, graphs and monitoring features.
Free to install. Pro $5/month after a 14-day no-card trial.
Pro requires the ServiceNow admin role. Upgrade inside the extension.
Step by step
Create the REST service definition
Navigate to System Web Services > Scripted Web Services > Scripted REST APIs and click New. Set the Name (this becomes part of your URL), API ID (use lowercase with underscores), and select a Namespace or create one. The Base API path shows you the URL structure: /api/[namespace]/[api_name]. Set Authentication type — 'Inherit from parent' uses session cookies, 'Basic' requires username/password, 'OAuth' needs additional setup.
Add your first resource
In the Resources related list, click New. Set the Name and Resource path (this gets appended to the base path). HTTP method defaults to GET — leave it for now. The Relative path field shows the complete URL your API will respond to. Your script will go in the Script field, but leave it empty for now and save the resource record.
Write the resource script
Open your resource record and add this basic script: `response.setBody({message: 'Hello World', timestamp: new GlideDateTime().toString()});` This sets the response body to a JSON object. The response object has methods like setStatus(), setHeader(), and setBody(). The request object (available but not used here) has getBody(), getPathParams(), getQueryParams(), and getHeaders().
Test the endpoint
Save your resource and test it. Navigate to System Web Services > REST API Explorer, select your API from the dropdown, and click Send. You should see your JSON response. The URL in the explorer shows the full path external systems will use. If you get an authentication error, either log in first or change your service to use 'Basic' authentication.
Use REST API Explorer for testing — it handles ServiceNow's session authentication automatically.
Add real data handling
Replace your test script with something useful. For a GET that returns incident data: `var inc = new GlideRecord('incident'); inc.addQuery('active', true); inc.setLimit(10); inc.query(); var results = []; while(inc.next()) { results.push({number: inc.number.toString(), short_description: inc.short_description.toString()}); } response.setBody({incidents: results});` This queries active incidents and returns a clean JSON structure.
Handle POST requests with validation
Create a second resource with HTTP method POST for creating records. Use `var body = request.body.data;` to get the JSON payload. Add validation: `if (!body.short_description) { response.setStatus(400); response.setBody({error: 'short_description is required'}); return; }` Then create the record and return the sys_id. Always set appropriate HTTP status codes — 201 for created, 400 for bad input, 500 for server errors.
Add error handling and logging
Wrap your main logic in try/catch blocks. In the catch: `response.setStatus(500); response.setBody({error: 'Internal server error'}); gs.error('API Error: ' + e.message);` This prevents ugly stack traces from reaching external systems and logs errors for debugging. Use gs.info() to log successful operations with relevant details like record numbers or user info.
Best practices
Always use setLimit() on GlideRecord queries to prevent performance issues when datasets grow unexpectedly.
Return consistent JSON structure for errors — external systems need to parse failures reliably.
Use toString() when adding GlideRecord field values to response objects — without it you get internal ServiceNow objects that don't serialize properly.
Don't put sensitive business logic directly in REST resources — call Script Includes so you can reuse and unit test the logic.
Set explicit HTTP status codes rather than relying on defaults — 200 for success, 201 for created, 400 for bad input, 404 for not found.
Test Your Knowledge
Quick 3-question quiz — see how your ServiceNow skills stack up.
A list view on a table with millions of records is slow. Best fix?
Select an answer to continue