Integration Hub Spoke Generation
Overview
This skill covers generating ServiceNow Integration Hub spokes for connecting to external services:
- Creating spoke containers to organize related integration actions
- Building spoke actions with REST, SOAP, and scripted steps
- Configuring connection aliases for secure credential management
- Defining action inputs and outputs with proper data typing
- Implementing data transformations between ServiceNow and external formats
- Adding error handling and retry logic for resilient integrations
- Packaging spokes for deployment across instances
When to use: When building reusable integrations with external APIs, creating custom connectors for third-party services, or packaging integration logic into deployable spokes.
Prerequisites
- Roles:
integration_admin,flow_designer, oradmin - Plugins:
com.glide.hub.flow_designer(Flow Designer),com.glide.hub.integration(Integration Hub) - Access: sys_spoke, sys_hub_action_type_definition, sys_connection_alias tables
- Knowledge: REST/SOAP API fundamentals, JSON/XML data formats, OAuth and basic authentication
- Related Skills:
genai/flow-generationfor consuming spokes in flows
Procedure
Step 1: Analyze the Integration Requirements
Parse the integration request to identify:
- External service: What system or API to connect to (Slack, Jira, Salesforce, custom REST)
- Operations: What actions the spoke should support (create, read, update, delete, query)
- Authentication: How to authenticate (OAuth 2.0, Basic Auth, API Key, mutual TLS)
- Data format: Request/response format (JSON, XML, form-encoded)
- Error handling: Expected error codes and retry behavior
Step 2: Query Existing Spokes for Patterns
MCP Approach:
Use SN-Query-Table on sys_spoke:
- query: active=true
- fields: sys_id,name,description,scope,logo,active
- limit: 20
Query existing spoke actions:
Use SN-Query-Table on sys_hub_action_type_definition:
- query: spoke=<spoke_sys_id>^active=true
- fields: sys_id,name,description,action_type,inputs,outputs
- limit: 20
REST Approach:
GET /api/now/table/sys_spoke
?sysparm_query=active=true
&sysparm_fields=sys_id,name,description,scope,active
&sysparm_limit=20
Step 3: Create the Spoke Record
MCP Approach:
Use SN-Create-Record on sys_spoke:
- name: "Acme CRM Spoke"
- description: "Integration spoke for Acme CRM REST API - supports contacts, deals, and activities"
- scope: "x_acme_crm"
- logo: ""
- active: true
- version: "1.0.0"
REST Approach:
POST /api/now/table/sys_spoke
Body: {
"name": "Acme CRM Spoke",
"description": "Integration spoke for Acme CRM REST API - supports contacts, deals, and activities",
"scope": "x_acme_crm",
"active": true,
"version": "1.0.0"
}
Step 4: Create Connection Alias
Connection aliases provide secure, reusable credential storage.
Connection Alias Types:
| Type | Value | Use Case |
|---|---|---|
| HTTP Connection | http_connection | REST/SOAP API credentials |
| JDBC Connection | jdbc_connection | Database connections |
| LDAP Connection | ldap_connection | Directory services |
| Custom | custom | Non-standard authentication |
MCP Approach:
Use SN-Create-Record on sys_connection_alias:
- name: "Acme CRM API"
- connection_type: "http_connection"
- description: "Connection alias for Acme CRM REST API"
- active: true
- scope: "x_acme_crm"
- spoke: "<spoke_sys_id>"
REST Approach:
POST /api/now/table/sys_connection_alias
Body: {
"name": "Acme CRM API",
"connection_type": "http_connection",
"description": "Connection alias for Acme CRM REST API",
"active": true,
"scope": "x_acme_crm",
"spoke": "<spoke_sys_id>"
}
Configure Credential (Basic Auth):
Use SN-Create-Record on sys_alias_credential:
- connection_alias: "<connection_alias_sys_id>"
- type: "basic_auth"
- user_name: "${connection.username}"
- password: "${connection.password}"
- active: true
Configure Credential (OAuth 2.0):
Use SN-Create-Record on sys_alias_credential:
- connection_alias: "<connection_alias_sys_id>"
- type: "oauth2"
- oauth_profile: "<oauth_profile_sys_id>"
- active: true
Step 5: Create Spoke Actions
Each action represents an operation the spoke can perform.
MCP Approach:
Use SN-Create-Record on sys_hub_action_type_definition:
- name: "Create Contact"
- description: "Creates a new contact in Acme CRM"
- spoke: "<spoke_sys_id>"
- action_type: "custom"
- category: "x_acme_crm"
- access: "public"
- active: true
- annotation: "Creates a contact record in external CRM system"
Use SN-Create-Record on sys_hub_action_type_definition:
- name: "Get Contact"
- description: "Retrieves a contact by ID from Acme CRM"
- spoke: "<spoke_sys_id>"
- action_type: "custom"
- category: "x_acme_crm"
- access: "public"
- active: true
Use SN-Create-Record on sys_hub_action_type_definition:
- name: "Search Contacts"
- description: "Searches contacts in Acme CRM by criteria"
- spoke: "<spoke_sys_id>"
- action_type: "custom"
- category: "x_acme_crm"
- access: "public"
- active: true
REST Approach:
POST /api/now/table/sys_hub_action_type_definition
Body: {
"name": "Create Contact",
"description": "Creates a new contact in Acme CRM",
"spoke": "<spoke_sys_id>",
"action_type": "custom",
"category": "x_acme_crm",
"access": "public",
"active": true
}
Step 6: Define Action Inputs
MCP Approach:
Use SN-Create-Record on sys_hub_action_input:
- action_type: "<create_contact_action_sys_id>"
- name: "first_name"
- label: "First Name"
- type: "string"
- mandatory: true
- order: 100
Use SN-Create-Record on sys_hub_action_input:
- action_type: "<create_contact_action_sys_id>"
- name: "last_name"
- label: "Last Name"
- type: "string"
- mandatory: true
- order: 200
Use SN-Create-Record on sys_hub_action_input:
- action_type: "<create_contact_action_sys_id>"
- name: "email"
- label: "Email Address"
- type: "string"
- mandatory: true
- order: 300
Use SN-Create-Record on sys_hub_action_input:
- action_type: "<create_contact_action_sys_id>"
- name: "company_id"
- label: "Company ID"
- type: "string"
- mandatory: false
- order: 400
REST Approach:
POST /api/now/table/sys_hub_action_input
Body: {
"action_type": "<create_contact_action_sys_id>",
"name": "email",
"label": "Email Address",
"type": "string",
"mandatory": true,
"order": 300
}
Step 7: Add REST Steps to Actions
REST steps define the actual HTTP calls to external services.
MCP Approach:
Use SN-Create-Record on sys_hub_rest_step:
- action_type: "<create_contact_action_sys_id>"
- name: "Call Create Contact API"
- order: 100
- connection_alias: "<connection_alias_sys_id>"
- http_method: "POST"
- resource_path: "/api/v2/contacts"
- content_type: "application/json"
- request_body: '{
"first_name": "${inputs.first_name}",
"last_name": "${inputs.last_name}",
"email": "${inputs.email}",
"company_id": "${inputs.company_id}"
}'
- headers: '[{"name":"Accept","value":"application/json"}]'
REST Approach:
POST /api/now/table/sys_hub_rest_step
Body: {
"action_type": "<create_contact_action_sys_id>",
"name": "Call Create Contact API",
"order": 100,
"connection_alias": "<connection_alias_sys_id>",
"http_method": "POST",
"resource_path": "/api/v2/contacts",
"content_type": "application/json",
"request_body": "{\"first_name\":\"${inputs.first_name}\",\"last_name\":\"${inputs.last_name}\",\"email\":\"${inputs.email}\"}"
}
GET Request Example:
Use SN-Create-Record on sys_hub_rest_step:
- action_type: "<get_contact_action_sys_id>"
- name: "Call Get Contact API"
- order: 100
- connection_alias: "<connection_alias_sys_id>"
- http_method: "GET"
- resource_path: "/api/v2/contacts/${inputs.contact_id}"
- content_type: "application/json"
- headers: '[{"name":"Accept","value":"application/json"}]'
Step 8: Define Action Outputs
MCP Approach:
Use SN-Create-Record on sys_hub_action_output:
- action_type: "<create_contact_action_sys_id>"
- name: "contact_id"
- label: "Contact ID"
- type: "string"
- order: 100
Use SN-Create-Record on sys_hub_action_output:
- action_type: "<create_contact_action_sys_id>"
- name: "status_code"
- label: "HTTP Status Code"
- type: "integer"
- order: 200
Use SN-Create-Record on sys_hub_action_output:
- action_type: "<create_contact_action_sys_id>"
- name: "response_body"
- label: "Response Body"
- type: "string"
- order: 300
Step 9: Add Error Handling with Script Steps
MCP Approach:
Use SN-Create-Record on sys_hub_script_step:
- action_type: "<create_contact_action_sys_id>"
- name: "Handle Response"
- order: 200
- script: |
(function execute(inputs, outputs) {
var statusCode = inputs.rest_step_status_code;
var responseBody = inputs.rest_step_response_body;
if (statusCode == 201) {
var response = JSON.parse(responseBody);
outputs.contact_id = response.id;
outputs.status_code = statusCode;
} else if (statusCode == 409) {
throw new Error('Contact already exists: ' + responseBody);
} else if (statusCode == 429) {
throw new Error('Rate limit exceeded. Retry after cooldown.');
} else {
throw new Error('API error ' + statusCode + ': ' + responseBody);
}
})(inputs, outputs);
Step 10: Test and Publish the Spoke
MCP Approach:
Use SN-Update-Record on sys_spoke:
- sys_id: "<spoke_sys_id>"
- active: true
Verify all actions are properly configured:
Use SN-Query-Table on sys_hub_action_type_definition:
- query: spoke=<spoke_sys_id>
- fields: sys_id,name,active,action_type
- limit: 50
Verify connection alias is available:
Use SN-Query-Table on sys_connection_alias:
- query: spoke=<spoke_sys_id>
- fields: sys_id,name,connection_type,active
Tool Usage
| Tool | Purpose | When to Use |
|---|---|---|
| SN-Query-Table | Find existing spokes and actions | Pattern discovery and validation |
| SN-Create-Record | Create spokes, actions, inputs, outputs, steps | Building spoke components |
| SN-Update-Record | Modify spoke settings, activate spokes | Editing and publishing |
| SN-Get-Table-Schema | Discover spoke table fields | Understanding available configurations |
Best Practices
- One spoke per external service -- avoid mixing multiple APIs in a single spoke
- Use connection aliases for all credentials -- never hardcode secrets in scripts or REST steps
- Define comprehensive inputs/outputs with clear labels and proper data types
- Always add error handling -- parse HTTP status codes and provide meaningful error messages
- Implement retry logic for transient failures (429, 503) using script steps
- Use pagination for search/list actions to handle large result sets
- Version your API paths in resource_path to support API evolution
- Log integration calls for debugging with appropriate verbosity levels
- Test with mock data before connecting to production external services
- Document rate limits and throttling behavior in the spoke description
Troubleshooting
| Issue | Cause | Resolution |
|---|---|---|
| Connection test fails | Invalid credentials or URL in connection alias | Verify connection alias configuration and test connectivity |
| 401 Unauthorized | OAuth token expired or invalid credentials | Refresh OAuth token or update credential record |
| 403 Forbidden | API key lacks required permissions | Check external service permissions for the integration user |
| REST step timeout | External service slow or unreachable | Increase timeout on REST step or check network connectivity |
| Response parsing error | Unexpected response format from API | Add defensive JSON parsing in script step with try/catch |
| Action not visible in Flow Designer | Action access set to private or spoke inactive | Set access to "public" and verify spoke is active |
| Input data truncated | String field length limits | Use multi-line text type for large payloads |
Examples
Example 1: Slack Notification Spoke
Generate a spoke for sending Slack messages:
- Action 1: Send Message -- POST to /api/chat.postMessage with channel, text, attachments
- Action 2: Create Channel -- POST to /api/conversations.create with name, is_private
- Action 3: Upload File -- POST to /api/files.upload with channels, file content
- Connection: OAuth 2.0 with Slack Bot Token
- Error Handling: Handle rate limits (429), channel not found (channel_not_found)
Example 2: Jira Integration Spoke
Generate a spoke for Jira Cloud operations:
- Action 1: Create Issue -- POST to /rest/api/3/issue with project, summary, description, issuetype
- Action 2: Get Issue -- GET /rest/api/3/issue/{issueKey} returning status, assignee, priority
- Action 3: Add Comment -- POST to /rest/api/3/issue/{issueKey}/comment with body
- Action 4: Transition Issue -- POST to /rest/api/3/issue/{issueKey}/transitions
- Connection: Basic Auth with API token, base URL configurable per instance
Example 3: Custom REST API Spoke
Generate a spoke for a custom internal microservice:
- Action 1: Submit Order -- POST /api/v1/orders with line items, customer, shipping address
- Action 2: Check Order Status -- GET /api/v1/orders/{orderId} returning status, tracking number
- Action 3: Cancel Order -- DELETE /api/v1/orders/{orderId} with reason
- Connection: API Key authentication via custom header
- Data Transform: Map ServiceNow catalog variables to API request format
Related Skills
genai/flow-generation- Flow Designer flows that consume spoke actionsgenai/playbook-generation- Playbooks that call spoke actions as activitiescatalog/approval-workflows- Approval flows that may trigger external notificationsadmin/instance-management- Connection alias and credential configuration