rest-integration
$
npx mdskill add serac-labs/serac/rest-integrationEnable outbound REST API calls from ServiceNow with authentication and error handling
- Simplify integration with external REST APIs from ServiceNow instances
- Uses ServiceNow's RESTMessageV2 API and sys_rest_message records
- Handles authentication, status code errors, and response parsing
- Supports retries with exponential backoff for improved reliability
SKILL.md
.github/skills/rest-integrationView on GitHub ↗
---
name: rest-integration
description: Make outbound REST calls from ServiceNow with sn_ws.RESTMessageV2 — basic/bearer/OAuth/API-key auth, error handling by status code, response parsing, sys_rest_message records, and retry with exponential backoff.
version: 1.0.0
tools:
- snow_create_rest_message
- snow_test_rest_connection
- snow_test_web_service
- snow_execute_script_with_output
---
# REST Integration Patterns for ServiceNow
ServiceNow provides RESTMessageV2 for outbound REST API calls and the REST API for inbound requests.
## Outbound REST (Calling External APIs)
### Basic GET Request
```javascript
var request = new sn_ws.RESTMessageV2()
request.setEndpoint("https://api.example.com/users")
request.setHttpMethod("GET")
request.setRequestHeader("Accept", "application/json")
var response = request.execute()
var httpStatus = response.getStatusCode()
var body = response.getBody()
if (httpStatus == 200) {
var data = JSON.parse(body)
gs.info("Found " + data.length + " users")
}
```
### POST Request with JSON Body
```javascript
var request = new sn_ws.RESTMessageV2()
request.setEndpoint("https://api.example.com/incidents")
request.setHttpMethod("POST")
request.setRequestHeader("Content-Type", "application/json")
request.setRequestHeader("Accept", "application/json")
var payload = {
title: "New Incident",
description: "Created from ServiceNow",
priority: "high",
}
request.setRequestBody(JSON.stringify(payload))
var response = request.execute()
```
### Using REST Message Records
Create a REST Message record for reusable integrations:
```javascript
// Using predefined REST Message from sys_rest_message
var request = new sn_ws.RESTMessageV2("External API", "Create User")
// Set variable substitutions defined in the REST Message
request.setStringParameter("user_name", userName)
request.setStringParameter("email", email)
var response = request.execute()
```
## Authentication Methods
### Basic Authentication
```javascript
var request = new sn_ws.RESTMessageV2()
request.setEndpoint("https://api.example.com/data")
request.setHttpMethod("GET")
request.setBasicAuth("username", "password")
```
### Bearer Token
```javascript
var request = new sn_ws.RESTMessageV2()
request.setEndpoint("https://api.example.com/data")
request.setHttpMethod("GET")
request.setRequestHeader("Authorization", "Bearer " + token)
```
### OAuth 2.0 (Using OAuth Profile)
```javascript
var request = new sn_ws.RESTMessageV2()
request.setEndpoint("https://api.example.com/data")
request.setHttpMethod("GET")
request.setAuthenticationProfile("oauth2", "My OAuth Profile")
```
### API Key
```javascript
var request = new sn_ws.RESTMessageV2()
request.setEndpoint("https://api.example.com/data")
request.setHttpMethod("GET")
request.setRequestHeader("X-API-Key", apiKey)
// Or as query parameter
request.setQueryParameter("api_key", apiKey)
```
## Error Handling
```javascript
try {
var request = new sn_ws.RESTMessageV2()
request.setEndpoint("https://api.example.com/data")
request.setHttpMethod("GET")
request.setHttpTimeout(10000) // 10 second timeout
var response = request.execute()
var httpStatus = response.getStatusCode()
if (httpStatus == 200) {
var body = response.getBody()
var data = JSON.parse(body)
// Process successful response
} else if (httpStatus == 401) {
gs.error("Authentication failed")
} else if (httpStatus == 404) {
gs.error("Resource not found")
} else if (httpStatus >= 500) {
gs.error("Server error: " + httpStatus)
} else {
gs.error("Unexpected status: " + httpStatus)
}
} catch (ex) {
gs.error("REST Exception: " + ex.message)
}
```
## Response Handling
### Parse JSON Response
```javascript
var body = response.getBody()
var data = JSON.parse(body)
// Access nested data
var userName = data.user.name
var items = data.items || []
```
### Handle Arrays
```javascript
var body = response.getBody()
var users = JSON.parse(body)
for (var i = 0; i < users.length; i++) {
var user = users[i]
gs.info("User: " + user.name + " (" + user.email + ")")
}
```
### Response Headers
```javascript
var contentType = response.getHeader("Content-Type")
var rateLimitRemaining = response.getHeader("X-RateLimit-Remaining")
```
## MCP Tools for REST
```javascript
// Create REST Message record
snow_create_rest_message({
name: "External API",
endpoint: "https://api.example.com",
authentication: "basic", // or "oauth2", "api_key"
methods: [
{
name: "Get Users",
http_method: "GET",
endpoint: "/users",
},
{
name: "Create User",
http_method: "POST",
endpoint: "/users",
content_type: "application/json",
},
],
})
// Test REST connection
snow_test_rest_connection({
endpoint: "https://api.example.com/health",
})
```
## Best Practices
1. **Use REST Message records** - Centralized configuration, easier maintenance
2. **Set timeouts** - Prevent hanging scripts with `setHttpTimeout()`
3. **Handle all status codes** - Not just 200
4. **Log failures** - Use `gs.error()` for debugging
5. **Use Async for slow APIs** - Don't block business rules
6. **Store credentials securely** - Use Connection & Credential Aliases
7. **Implement retry logic** - For transient failures
8. **Rate limit awareness** - Check response headers, implement backoff
## Retry Pattern
```javascript
function callApiWithRetry(endpoint, maxRetries) {
var retries = 0
var delay = 1000 // Start with 1 second
while (retries < maxRetries) {
try {
var request = new sn_ws.RESTMessageV2()
request.setEndpoint(endpoint)
request.setHttpMethod("GET")
var response = request.execute()
if (response.getStatusCode() == 200) {
return JSON.parse(response.getBody())
}
if (response.getStatusCode() >= 500) {
// Server error - retry
retries++
gs.sleep(delay)
delay = delay * 2 // Exponential backoff
continue
}
// Client error - don't retry
throw new Error("Client error: " + response.getStatusCode())
} catch (ex) {
retries++
if (retries >= maxRetries) {
throw ex
}
gs.sleep(delay)
delay = delay * 2
}
}
}
```
More from serac-labs/serac
- acl-securityCreate and debug ServiceNow ACLs (record, field, REST, script-include). Covers role/condition/script patterns, evaluation order, field-level visibility, and impersonation testing for row- and field-level security.
- agent-workspaceBuild ServiceNow Agent Workspace configurations — workspaces, lists, forms, contextual side panels, Agent Assist similar-record finders, and workspace-specific UI actions on sys_aw_* tables.
- approval-workflowsConfigure ServiceNow approval rules and sysapproval_approver records — manager/group/script approvers, multi-level routing, delegation via sys_user_delegate, and parent-record state rollup.
- asset-managementManage ServiceNow hardware assets, software licenses, and lifecycle states on alm_hardware/alm_license — license allocation, CMDB-to-asset linking, warranty tracking, inventory aggregation (HAM/SAM).
- atf-testingBuild ServiceNow Automated Test Framework tests and suites — impersonation, form steps, assertions, server-side script steps, test parameters, and execution via snow_create_atf_test / snow_execute_atf_test.
- blast-radiusTrace ServiceNow configuration dependencies — what artifacts touch a given field, what calls a script include, table/app-level config inventory. Use before deletes, renames, or refactors.
- bun-file-ioUse this when you are working on file operations like reading, writing, scanning, or deleting files. It summarizes the preferred file APIs and patterns used in this repo. It also notes when to use filesystem helpers for directories.
- business-rule-patternsWrite ServiceNow business rules (before/after/async/display) — current vs previous, changesTo/changesFrom, recursion avoidance, setAbortAction, and async dispatch for heavy work.
- catalog-itemsBuild ServiceNow Service Catalog items, variables, variable sets, catalog client scripts, record producers, and order guides with reference qualifiers and dynamic pricing.
- client-scriptsWrite ServiceNow client scripts (onLoad/onChange/onSubmit/onCellEdit) using g_form, g_user, GlideAjax, field visibility/mandatory toggles, and validation with debounced server calls.