A practice API server for ServiceNow solution consultants to build and test custom REST integrations.
Base URL: https://integration-training.sliplane.app
Interactive Documentation: https://integration-training.sliplane.app/docs
This server is ready to use for ServiceNow integration training. No installation required!
This API provides realistic endpoints to practice:
- API Key Authentication - Learn to configure authentication headers in ServiceNow
- GET Requests - Retrieve and parse arrays of business records
- POST Requests - Send data to external systems
- Error Handling - Handle authentication failures and validation errors
pip install -r requirements.txtpython main.pyThe server will start at http://localhost:8000
Production Server:
- Interactive Docs: https://integration-training.sliplane.app/docs
- Alternative Docs: https://integration-training.sliplane.app/redoc
Local Development:
- Interactive Docs: http://localhost:8000/docs
- Alternative Docs: http://localhost:8000/redoc
Build the Docker image:
docker build -t servicenow-training-api .Run the container:
docker run -d -p 8000:8000 --name training-api servicenow-training-apiStop the container:
docker stop training-apiRemove the container:
docker rm training-apiCreate a docker-compose.yml file:
version: '3.8'
services:
api:
build: .
ports:
- "8000:8000"
restart: unless-stoppedThen run:
docker-compose up -dAll endpoints (except / and /health) require authentication. The API supports two authentication methods:
Header Name: X-API-Key
curl -H "X-API-Key: training-key-001" https://integration-training.sliplane.app/recordsHeader Format: Authorization: Bearer <token>
curl -H "Authorization: Bearer training-key-001" https://integration-training.sliplane.app/recordsValid API Keys for Training:
training-key-001training-key-002demo-api-key-123
Both authentication methods accept the same keys and can be used interchangeably.
Try this in your browser or API client (no authentication required):
GET https://integration-training.sliplane.app/health
Returns an array of business records.
Authentication (choose one):
X-API-Key: training-key-001
OR
Authorization: Bearer training-key-001
Response (200 OK):
[
{
"id": "REC001",
"name": "Enterprise Software License",
"category": "Software",
"status": "Active",
"value": 15000.0,
"created_date": "2024-01-15",
"owner": "IT Department",
"description": "Annual enterprise software license renewal"
}
]Retrieve a specific record by ID.
Authentication (choose one):
X-API-Key: training-key-001
OR
Authorization: Bearer training-key-001
Example: GET /records/REC001
Response (200 OK):
{
"id": "REC001",
"name": "Enterprise Software License",
"category": "Software",
"status": "Active",
"value": 15000.0,
"created_date": "2024-01-15",
"owner": "IT Department",
"description": "Annual enterprise software license renewal"
}Create a new business record.
Authentication (choose one):
X-API-Key: training-key-001
Content-Type: application/json
OR
Authorization: Bearer training-key-001
Content-Type: application/json
Request Body:
{
"name": "New Project Initiative",
"category": "Projects",
"value": 50000.00,
"owner": "Project Management Office",
"description": "Q4 strategic project initiative"
}Response (201 Created):
{
"success": true,
"message": "Record 'New Project Initiative' created successfully",
"record": {
"id": "REC006",
"name": "New Project Initiative",
"category": "Projects",
"status": "Pending",
"value": 50000.0,
"created_date": "2024-12-10",
"owner": "Project Management Office",
"description": "Q4 strategic project initiative"
}
}Retrieve summary statistics as a single JSON object (not an array).
Authentication (choose one):
X-API-Key: training-key-001
OR
Authorization: Bearer training-key-001
Response (200 OK):
{
"total_records": 5,
"total_value": 65500.0,
"average_value": 13100.0,
"status_breakdown": {
"Active": 2,
"Completed": 1,
"In Progress": 1,
"Pending": 1
},
"category_breakdown": {
"Software": 1,
"Services": 1,
"Compliance": 1,
"Training": 1,
"Hardware": 1
},
"most_valuable_record": {
"id": "REC005",
"name": "Office Equipment Upgrade",
"category": "Hardware",
"status": "Pending",
"value": 25000.0,
"created_date": "2024-05-12",
"owner": "Facilities",
"description": "Office workstation and equipment upgrade project"
},
"latest_record": {
"id": "REC005",
"name": "Office Equipment Upgrade",
"category": "Hardware",
"status": "Pending",
"value": 25000.0,
"created_date": "2024-05-12",
"owner": "Facilities",
"description": "Office workstation and equipment upgrade project"
}
}Use Case: Perfect for displaying dashboard metrics or summary statistics in ServiceNow. This endpoint demonstrates working with a single JSON object response rather than an array.
Health check endpoint (no authentication required).
Response:
{
"status": "healthy",
"timestamp": "2024-12-10T10:30:00",
"total_records": 5
}- Navigate to System Web Services > Outbound > REST Message
- Click New
- Fill in:
- Name: Training API Integration
- Endpoint:
https://integration-training.sliplane.app - Authentication: None (we'll use custom headers)
Note: For local development, use
http://localhost:8000as the endpoint instead.
In the REST Message form, add HTTP Headers.
Option A: Using X-API-Key
| Name | Value |
|---|---|
| X-API-Key | training-key-001 |
| Content-Type | application/json |
Option B: Using Bearer Token
| Name | Value |
|---|---|
| Authorization | Bearer training-key-001 |
| Content-Type | application/json |
Choose either Option A or Option B (both work identically).
- In the REST Message, create a new HTTP Method
- Configure:
- Name: Get All Records
- HTTP method: GET
- Endpoint:
${endpoint}/records
- Test the method
- Create another HTTP Method
- Configure:
- Name: Create Record
- HTTP method: POST
- Endpoint:
${endpoint}/records
- Add Content (request body):
{
"name": "Test Record from ServiceNow",
"category": "Integration Test",
"value": 1000.00,
"owner": "ServiceNow Admin",
"description": "Testing POST integration"
}- Test the method
- Create another HTTP Method
- Configure:
- Name: Get Summary
- HTTP method: GET
- Endpoint:
${endpoint}/summary
- Test the method
- Note: This endpoint returns a single JSON object, not an array
Example 1: Parsing Array Response (GET /records)
try {
var r = new sn_ws.RESTMessageV2('Training API Integration', 'Get All Records');
var response = r.execute();
var httpStatus = response.getStatusCode();
if (httpStatus == 200) {
var responseBody = response.getBody();
var records = JSON.parse(responseBody);
gs.info('Retrieved ' + records.length + ' records');
// Process each record
for (var i = 0; i < records.length; i++) {
var record = records[i];
gs.info('Record: ' + record.id + ' - ' + record.name);
}
} else {
gs.error('HTTP Error: ' + httpStatus);
}
} catch (ex) {
gs.error('Error calling API: ' + ex.message);
}Example 2: Parsing Single Object Response (GET /summary)
try {
var r = new sn_ws.RESTMessageV2('Training API Integration', 'Get Summary');
var response = r.execute();
var httpStatus = response.getStatusCode();
if (httpStatus == 200) {
var responseBody = response.getBody();
var summary = JSON.parse(responseBody); // Single object, not array
// Access direct properties
gs.info('Total Records: ' + summary.total_records);
gs.info('Total Value: $' + summary.total_value);
gs.info('Average Value: $' + summary.average_value);
// Access nested objects
gs.info('Status Breakdown:');
for (var status in summary.status_breakdown) {
gs.info(' ' + status + ': ' + summary.status_breakdown[status]);
}
// Access most valuable record
var mostValuable = summary.most_valuable_record;
gs.info('Most Valuable: ' + mostValuable.name + ' ($' + mostValuable.value + ')');
} else {
gs.error('HTTP Error: ' + httpStatus);
}
} catch (ex) {
gs.error('Error calling API: ' + ex.message);
}- Create a REST Message in ServiceNow
- Configure API Key authentication
- Retrieve all records and log them
- Retrieve all records
- Filter for records with status "Active"
- Create a GlideRecord in a custom table for each active record
- Create a ServiceNow Catalog Item
- On submission, POST data to the training API
- Display the response to the user
- Test with an invalid API key
- Handle authentication errors gracefully
- Implement retry logic for failed requests
- Create a Scheduled Job
- Periodically fetch records from the API
- Update a ServiceNow table with the latest data
- Call the GET /summary endpoint
- Parse the single JSON object (not an array)
- Display the statistics on a ServiceNow dashboard or homepage widget
- Practice accessing nested properties (status_breakdown, category_breakdown)
All examples below use the production server. For local development, replace https://integration-training.sliplane.app with http://localhost:8000.
GET Request with X-API-Key:
curl -H "X-API-Key: training-key-001" https://integration-training.sliplane.app/recordsGET Request with Bearer Token:
curl -H "Authorization: Bearer training-key-001" https://integration-training.sliplane.app/recordsPOST Request with X-API-Key:
curl -X POST https://integration-training.sliplane.app/records \
-H "X-API-Key: training-key-001" \
-H "Content-Type: application/json" \
-d '{
"name": "Test Record",
"category": "Testing",
"value": 500.00,
"owner": "Test User",
"description": "Testing POST endpoint"
}'POST Request with Bearer Token:
curl -X POST https://integration-training.sliplane.app/records \
-H "Authorization: Bearer training-key-001" \
-H "Content-Type: application/json" \
-d '{
"name": "Test Record",
"category": "Testing",
"value": 500.00,
"owner": "Test User",
"description": "Testing POST endpoint"
}'GET Summary Request (Single Object Response):
curl -H "X-API-Key: training-key-001" https://integration-training.sliplane.app/summaryExample 1: Using X-API-Key Header
import requests
BASE_URL = "https://integration-training.sliplane.app"
headers = {
"X-API-Key": "training-key-001"
}
# GET request
response = requests.get(f"{BASE_URL}/records", headers=headers)
print(response.json())
# POST request
new_record = {
"name": "Python Test",
"category": "API Testing",
"value": 750.00,
"owner": "API Tester",
"description": "Created via Python"
}
response = requests.post(
f"{BASE_URL}/records",
headers=headers,
json=new_record
)
print(response.json())Example 2: Using Bearer Token
import requests
BASE_URL = "https://integration-training.sliplane.app"
headers = {
"Authorization": "Bearer training-key-001"
}
# GET request
response = requests.get(f"{BASE_URL}/records", headers=headers)
print(response.json())
# POST request
new_record = {
"name": "Python Bearer Test",
"category": "API Testing",
"value": 850.00,
"owner": "API Tester",
"description": "Created via Python with Bearer token"
}
response = requests.post(
f"{BASE_URL}/records",
headers=headers,
json=new_record
)
print(response.json())Example 3: Getting Summary Statistics (Single Object)
import requests
BASE_URL = "https://integration-training.sliplane.app"
headers = {
"X-API-Key": "training-key-001"
}
# Get summary as single object
response = requests.get(f"{BASE_URL}/summary", headers=headers)
summary = response.json()
# Access the single object's properties
print(f"Total Records: {summary['total_records']}")
print(f"Total Value: ${summary['total_value']}")
print(f"Average Value: ${summary['average_value']}")
# Access nested objects
print("\nStatus Breakdown:")
for status, count in summary['status_breakdown'].items():
print(f" {status}: {count}")
print("\nMost Valuable Record:")
most_valuable = summary['most_valuable_record']
print(f" {most_valuable['name']}: ${most_valuable['value']}")Solution: Ensure the API server is running (python main.py)
Solution: Check that X-API-Key header is correctly configured with a valid key
Solution: Verify POST request body includes all required fields (name, category, value, owner)
- Auto-generated Documentation: FastAPI provides interactive docs at
/docs - Request Validation: Pydantic models validate all incoming data
- Mock Data Persistence: Data persists during server runtime (resets on restart)
- Realistic Response Codes: Practice handling 200, 201, 401, 404, 422 responses
- Explore the interactive API documentation at
/docs - Test all endpoints with different API keys
- Practice error scenarios (invalid keys, missing fields)
- Build your ServiceNow integration following the guide above
- Extend the API with additional endpoints for more practice
For FastAPI documentation: https://fastapi.tiangolo.com/ For ServiceNow REST integration: https://docs.servicenow.com/