skills/genai/voice-assist/SKILL.md
Configure AI Voice Agents for ServiceNow including speech-to-text, intent recognition, voice-driven workflows, IVR integration, and conversational AI for voice channels
npx skillsauth add happy-technologies-llc/happy-servicenow-skills voice-assistInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill covers configuring AI-powered Voice Agents in ServiceNow for telephony and voice-driven interactions. It covers:
When to use:
admin, sn_va.topic_admin, sn_cs.admin, or sn_va.voice_admincom.glide.cs.chatbot (Virtual Agent), com.sn_va.voice (Voice), com.glide.interaction (Agent Workspace Interaction)| Table | Purpose | Key Fields |
|-------|---------|------------|
| sys_cs_topic | Virtual Agent conversation topics | name, description, channel, state, nlu_intent, category, order |
| interaction | Voice/chat interaction records | number, channel, state, opened_for, assignment_group, duration, disposition, recording_url |
| sys_cs_topic_detail | Topic flow step definitions | topic, step_type, prompt_text, order, variable_name, next_step |
| sys_cs_message | Conversation messages | interaction, message_type, body, direction, timestamp |
| sys_cs_intent | NLU intent definitions | name, description, model, training_phrases, confidence_threshold |
| sys_cs_context | Conversation context variables | name, data_type, scope, default_value |
| sys_properties | System configuration properties | name, value, description, type |
Check that voice capabilities are enabled and configured.
Using MCP (Claude Code/Desktop):
Tool: SN-Query-Table
Parameters:
table_name: sys_properties
query: nameLIKEva.voice^ORnameLIKEcs.voice^ORnameLIKEtelephony
fields: name,value,description
limit: 30
Using REST API:
GET /api/now/table/sys_properties?sysparm_query=nameLIKEva.voice^ORnameLIKEcs.voice^ORnameLIKEtelephony&sysparm_fields=name,value,description&sysparm_limit=30
Set up STT engine properties for voice input processing.
Using MCP:
Tool: SN-Update-Record
Parameters:
table_name: sys_properties
sys_id: [stt_property_sys_id]
data:
value: "google_cloud_speech"
Key STT properties to configure:
| Property | Purpose | Recommended Value |
|----------|---------|-------------------|
| sn.va.voice.stt.provider | STT engine provider | google_cloud_speech, aws_transcribe, azure_speech |
| sn.va.voice.stt.language | Primary recognition language | en-US |
| sn.va.voice.stt.model | Recognition model type | phone_call (optimized for telephony) |
| sn.va.voice.stt.profanity_filter | Filter profanity | true |
| sn.va.voice.stt.interim_results | Enable partial results | true |
| sn.va.voice.tts.provider | TTS engine provider | google_cloud_tts, aws_polly, azure_speech |
| sn.va.voice.tts.voice | TTS voice selection | en-US-Neural2-C (natural voice) |
| sn.va.voice.tts.speed | Speech rate | 1.0 (normal speed) |
Build Virtual Agent topics optimized for voice interactions.
Using MCP:
Tool: SN-Create-Record
Parameters:
table_name: sys_cs_topic
fields:
name: "Password Reset - Voice"
description: "Voice-optimized password reset flow with caller verification and DTMF fallback"
channel: voice
state: draft
category: it_support
nlu_intent: password_reset
greeting_message: "I can help you reset your password. First, I need to verify your identity. Can you please tell me your employee ID?"
Using REST API:
POST /api/now/table/sys_cs_topic
Content-Type: application/json
{
"name": "Password Reset - Voice",
"description": "Voice-optimized password reset flow with caller verification",
"channel": "voice",
"state": "draft",
"category": "it_support",
"nlu_intent": "password_reset"
}
Add topic detail steps for the voice conversation.
Using MCP:
Tool: SN-Create-Record
Parameters:
table_name: sys_cs_topic_detail
fields:
topic: [topic_sys_id]
step_type: user_input
prompt_text: "Please say or enter your employee ID number."
order: 100
variable_name: employee_id
input_type: alphanumeric
dtmf_enabled: true
timeout_seconds: 10
retry_count: 3
retry_prompt: "I did not catch that. Please say your employee ID again, or press the numbers on your phone keypad."
no_input_prompt: "Are you still there? Please say your employee ID to continue."
Add verification step:
Tool: SN-Create-Record
Parameters:
table_name: sys_cs_topic_detail
fields:
topic: [topic_sys_id]
step_type: script_action
order: 200
script: |
var user = new GlideRecord('sys_user');
user.addQuery('employee_number', vaInputs.employee_id);
user.query();
if (user.next()) {
vaVars.user_sys_id = user.sys_id.toString();
vaVars.user_name = user.name.toString();
vaVars.verified = true;
} else {
vaVars.verified = false;
}
next_step_success: 300
next_step_failure: 250
Add confirmation prompt:
Tool: SN-Create-Record
Parameters:
table_name: sys_cs_topic_detail
fields:
topic: [topic_sys_id]
step_type: user_input
prompt_text: "I found your account. Just to confirm, is your name {user_name}? Please say yes or no."
order: 300
variable_name: name_confirmed
input_type: boolean
dtmf_mapping: "1=yes,2=no"
Train the NLU model to recognize voice-specific utterances.
Using MCP:
Tool: SN-Create-Record
Parameters:
table_name: sys_cs_intent
fields:
name: password_reset
description: "Intent for password reset requests via voice channel"
model: default_nlu_model
confidence_threshold: 0.7
training_phrases: |
I need to reset my password
my password is not working
I forgot my password
can you help me change my password
I am locked out of my account
password expired
I cannot log in
reset password please
my password does not work anymore
I need a new password
help me with my password
account is locked
Using REST API:
POST /api/now/table/sys_cs_intent
Content-Type: application/json
{
"name": "password_reset",
"description": "Intent for password reset requests via voice",
"confidence_threshold": "0.7",
"training_phrases": "I need to reset my password\nmy password is not working\nI forgot my password\ncan you help me change my password\nI am locked out"
}
Configure the telephony provider connection.
Using MCP:
Tool: SN-Execute-Background-Script
Parameters:
script: |
// Configure Twilio integration properties
var props = {
'sn.va.voice.telephony.provider': 'twilio',
'sn.va.voice.telephony.account_sid': '[twilio_account_sid]',
'sn.va.voice.telephony.phone_number': '+18005551234',
'sn.va.voice.telephony.webhook_url': gs.getProperty('glide.servlet.uri') + 'api/sn_va/voice/webhook',
'sn.va.voice.telephony.recording_enabled': 'true',
'sn.va.voice.telephony.max_call_duration': '1800',
'sn.va.voice.telephony.transfer_number': '+18005555678'
};
for (var key in props) {
var prop = new GlideRecord('sys_properties');
prop.addQuery('name', key);
prop.query();
if (prop.next()) {
prop.value = props[key];
prop.update();
} else {
prop.initialize();
prop.name = key;
prop.value = props[key];
prop.description = 'Voice agent telephony configuration';
prop.insert();
}
}
gs.info('Telephony properties configured: ' + Object.keys(props).length + ' properties set.');
description: "Voice: Configure telephony provider integration properties"
Query interaction records for voice channel analytics.
Using MCP:
Tool: SN-Query-Table
Parameters:
table_name: interaction
query: channel=voice^ORDERBYDESCsys_created_on
fields: sys_id,number,channel,state,opened_for,assignment_group,duration,disposition,topic,sys_created_on,close_notes
limit: 50
Generate voice analytics:
Tool: SN-Execute-Background-Script
Parameters:
script: |
var analytics = {
period: 'Last 30 days',
total_calls: 0,
avg_duration_seconds: 0,
self_service_rate: 0,
transfer_rate: 0,
by_disposition: {},
by_topic: {},
avg_confidence: 0
};
var ga = new GlideAggregate('interaction');
ga.addQuery('channel', 'voice');
ga.addQuery('sys_created_on', '>=', gs.daysAgo(30));
ga.addAggregate('COUNT');
ga.addAggregate('AVG', 'duration');
ga.query();
if (ga.next()) {
analytics.total_calls = parseInt(ga.getAggregate('COUNT'));
analytics.avg_duration_seconds = Math.round(parseFloat(ga.getAggregate('AVG', 'duration')) || 0);
}
var resolved = new GlideAggregate('interaction');
resolved.addQuery('channel', 'voice');
resolved.addQuery('sys_created_on', '>=', gs.daysAgo(30));
resolved.addQuery('disposition', 'resolved');
resolved.addAggregate('COUNT');
resolved.query();
if (resolved.next() && analytics.total_calls > 0) {
analytics.self_service_rate = Math.round((parseInt(resolved.getAggregate('COUNT')) / analytics.total_calls) * 100);
}
gs.info('VOICE ANALYTICS:\n' + JSON.stringify(analytics, null, 2));
description: "Voice: Generate voice interaction analytics for the last 30 days"
| Operation | MCP Tool | REST Endpoint | |-----------|----------|---------------| | Query Topics | SN-Query-Table | GET /api/now/table/sys_cs_topic | | Create Topics | SN-Create-Record | POST /api/now/table/sys_cs_topic | | Create Flow Steps | SN-Create-Record | POST /api/now/table/sys_cs_topic_detail | | Configure Intents | SN-Create-Record | POST /api/now/table/sys_cs_intent | | Query Interactions | SN-Query-Table | GET /api/now/table/interaction | | Set Properties | SN-Execute-Background-Script | POST /api/now/table/sys_properties | | Schema Discovery | SN-Discover-Table-Schema | GET /api/now/table/sys_dictionary |
Symptom: STT frequently misrecognizes caller speech
Cause: Default STT model may not be optimized for telephony audio quality (8kHz narrowband)
Solution: Switch STT model to phone_call or telephony variant. Add custom vocabulary for company-specific terms. Check audio codec compatibility (G.711 recommended).
Symptom: Callers report being asked the same question repeatedly
Cause: Topic flow step retry logic lacks an exit condition or max-retry transfer
Solution: Set retry_count to 3 maximum on all input steps. Add an explicit "transfer to agent" step after max retries.
Symptom: Calls connect but the voice topic does not start
Cause: Topic channel filter excludes voice, or the NLU confidence threshold is too high
Solution: Verify channel=voice on the topic record. Lower NLU confidence threshold to 0.6 for voice (speech recognition introduces noise).
Symptom: Telephony provider configured but calls do not reach ServiceNow
Cause: Webhook URL is incorrect, firewall blocks inbound traffic, or SSL certificate issue
Solution: Verify the webhook URL matches {instance}/api/sn_va/voice/webhook. Check network ACLs and certificate validity. Test with the provider's webhook validator tool.
Scenario: Deploy a voice agent for common IT support requests
Topics to create:
Sample interaction:
Scenario: Configure voice agent for benefits enrollment questions
Tool: SN-Create-Record
Parameters:
table_name: sys_cs_topic
fields:
name: "Benefits Inquiry - Voice"
description: "Voice self-service for benefits plan information, enrollment status, and coverage details"
channel: voice
state: draft
category: hr_benefits
nlu_intent: benefits_inquiry
genai/playbook-generation - Process automation for voice workflowsgenai/flow-generation - Flow Designer for voice-triggered automationcsm/chat-recommendation - Chat-based recommendations (extend to voice)hrsd/chat-reply-recommendation - HR chat replies adaptable to voiceadmin/workflow-creation - Build workflows triggered by voice interactionstesting
Manage supplier onboarding, qualification, performance monitoring, and offboarding with auditable lifecycle controls
tools
Identify emerging risks, prioritize intake signals, and route candidates into formal GRC risk assessment workflows
documentation
Screen inbound documents for completeness, policy risk, and routing readiness before extraction or case workflows
testing
Generate concise task summaries with status, timeline, blockers, SLA risk, and recommended next actions