Ctrl K
ring2all.com

Custom Applications Module Documentation

Table of Contents

  1. Module Overview (Technical)
  2. Module Overview (Commercial/Business)
  3. Module Overview (End User/Administrator)
  4. Configuration Fields Reference
  5. Call Flow / Logic Explanation
  6. Common Scenarios & Examples
  7. Limitations & Important Notes
  8. Troubleshooting Tips
  9. Glossary
  10. Suggested UI Improvements

---

1. Module Overview (Technical)

What Are Custom Applications?

Custom Applications allow administrators to create programmable call logic using Lua scripts or XML dialplan entries. When a user dials the trigger number, FreeSWITCH executes the custom code before optionally routing to a final destination.

Two Application Types

TypeDescriptionUse Case
Lua ScriptProgrammatic logic with Lua codeComplex logic, API calls, database queries
XML DialplanDeclarative FreeSWITCH XMLSimple routing, variable setting

Architecture

Plaintext
┌─────────────────────────────────────────────────────────────────┐
│                Custom Applications Architecture                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  User dials: *99 (trigger number)                               │
│       │                                                         │
│       ▼                                                         │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              Custom Application Lookup                   │   │
│  │  SELECT * FROM custom_applications                       │   │
│  │  WHERE trigger_number = '*99' AND enabled = true         │   │
│  └──────────────────────────────────────────────────────────┘   │
│       │                                                         │
│       ▼                                                         │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              Execute Script                              │   │
│  │                                                          │   │
│  │  LUA SCRIPT:                                             │   │
│  │  ├─ Load script from file system                         │   │
│  │  ├─ Execute Lua code (session:answer(), play, etc.)      │   │
│  │  └─ Access variables: caller_id, CUSTOM_APP_UUID, etc.   │   │
│  │                                                          │   │
│  │  XML DIALPLAN:                                           │   │
│  │  ├─ Parse XML content                                    │   │
│  │  └─ Execute as inline dialplan                           │   │
│  │                                                          │   │
│  └──────────────────────────────────────────────────────────┘   │
│       │                                                         │
│       ▼                                                         │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │              Final Destination (if not skipped)          │   │
│  │                                                          │   │
│  │  ├─ extension   → Transfer to extension                  │   │
│  │  ├─ queue       → Send to call queue                     │   │
│  │  ├─ ivr         → Send to IVR menu                       │   │
│  │  ├─ conference  → Join conference                        │   │
│  │  ├─ voicemail   → Send to voicemail                      │   │
│  │  ├─ announcement→ Play announcement                      │   │
│  │  ├─ external    → Dial external number                   │   │
│  │  └─ hangup      → End call                               │   │
│  │                                                          │   │
│  └──────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Key Tables

TablePurpose
public.custom_applicationsApplication definitions (name, trigger, script)

Script Storage

Scripts are stored as files in FreeSWITCH:

Plaintext
/usr/share/freeswitch/scripts/custom_apps/[uuid].lua
/usr/share/freeswitch/scripts/custom_apps/[uuid].xml

Available Variables

VariableDescription
CUSTOM_APP_DOMAINThe domain/tenant the call is in
CUSTOM_APP_UUIDUnique ID of this application
caller_id_numberCaller's phone number
caller_id_nameCaller's name
destination_numberNumber that was dialed

Key Files

FileDescription
admin/apps/web/src/modules/customApplications/Frontend module
admin/apps/web/src/i18n/en/customApplications.jsonEnglish translations
telephony/freeswitch/lua/main/custom_app_handler.luaLua handler
---

2. Module Overview (Commercial/Business)

Business Value

Custom Applications provide extensibility without core modifications:

Without Custom AppsWith Custom Apps
Hardcoded logic onlyDynamic programmable logic
Developer requiredAdmin can create via UI
System restart neededHot-deployed scripts
No customizationUnlimited flexibility

Use Cases

  1. Custom IVR Logic
- Complex branching based on caller ID

- Database lookups for personalized greetings

- API integrations with external systems

  1. Pre-Call Announcements
- "This call may be recorded"

- Holiday hour announcements

- Emergency notifications

  1. Call Routing Logic
- Time-based routing with custom logic

- VIP caller detection

- Geographic routing

  1. Integration Points
- CRM lookups before connecting

- Ticket creation on call start

- SMS notifications

Feature Highlights

FeatureBenefit
Lua ScriptingFull programming language for complex logic
XML DialplanSimple declarative routing
Final DestinationRoute anywhere after script completes
Skip DestinationScript handles everything (hangup internally)
Hot DeployChanges apply immediately
---

3. Module Overview (End User/Administrator)

What Can You Do?

  • Create custom applications with Lua or XML code
  • Assign trigger numbers (extension or feature code)
  • Define final destinations for post-script routing
  • Enable/disable applications without deleting

User Workflow

Plaintext
┌─────────────────────────────────────────────────────────────────┐
│                 Creating a Custom Application                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Step 1: Basic Information (General Settings Tab)               │
│  ├─ Name: "Recording Disclaimer"                               │
│  ├─ Trigger Number: *99                                        │
│  ├─ Description: "Plays recording notice before transfer"      │
│  └─ Application Type: Lua Script                               │
│                                                                 │
│  Step 2: Script Content (Script Content Tab)                    │
│  ├─ Write Lua code:                                            │
│  │   session:answer()                                          │
│  │   session:sleep(500)                                        │
│  │   session:streamFile("ivr/recording_disclaimer.wav")        │
│  │   -- Final destination handles the rest                     │
│  │                                                              │
│  Step 3: Final Destination                                      │
│  ├─ Skip Final Destination: ✗ (transfer after script)         │
│  ├─ Destination Type: Queue                                    │
│  └─ Destination Value: support_queue                           │
│                                                                 │
│  Step 4: Enable and Save                                        │
│  └─ Enabled: ✓                                                 │
│                                                                 │
│  Result: Dial *99 → Plays disclaimer → Transfers to queue      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Quick Tips

TIP
Start Simple: Begin with basic Lua scripts before attempting complex integrations.
TIP
Test Thoroughly: Always test custom applications in a development environment first.
CAUTION
Syntax Errors: Invalid Lua/XML will cause the application to fail. Check FreeSWITCH logs for errors.

---

4. Configuration Fields Reference

General Settings Tab

FieldDescriptionExampleRequired
NameUnique application nameRecording DisclaimerYes
Trigger NumberExtension/feature code99, 8001Yes
DescriptionPurpose documentationPlays recording noticeNo
Application TypeLua Script or XML DialplanLua ScriptYes
EnabledActive/inactiveOn/OffYes

Script Content Tab

FieldDescriptionNotes
Script ContentLua code or XML dialplanMonaco editor with syntax highlighting

Final Destination Section

FieldDescriptionOptions
Skip Final DestinationDon't route after scriptOn = script handles hangup
Destination TypeWhere to routeExtension, Queue, IVR, Conference, Voicemail, Announcement, External, Hangup, Time Condition, Call Flow, Ring Group
Destination ValueTarget identifierDepends on type

Destination Types

TypeValue FormatExample
ExtensionExtension number1001
QueueQueue namesupport_queue
Ring GroupRing group IDsales_group
IVRIVR namemain_menu
VoicemailExtension number1001
AnnouncementAnnouncement IDholiday_hours
ConferenceConference extension8000
Hangup(none)Ends call
ExternalPhone number+15551234567
Time ConditionTime condition IDbusiness_hours
Call FlowCall flow IDmain_flow
---

5. Call Flow / Logic Explanation

Custom Application Execution Flow

Plaintext
┌─────────────────────────────────────────────────────────────────┐
│              Custom Application Execution Flow                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. User dials *99 (trigger number)                             │
│     │                                                           │
│     ▼                                                           │
│  2. Dialplan matches custom_application route                   │
│     │                                                           │
│     ▼                                                           │
│  3. Load application from database                              │
│     ├─ Verify enabled = true                                   │
│     ├─ Get app_type (lua/xml)                                  │
│     └─ Get script_filename                                     │
│     │                                                           │
│     ▼                                                           │
│  4. Set channel variables                                       │
│     ├─ CUSTOM_APP_DOMAIN = [domain]                             │
│     ├─ CUSTOM_APP_UUID = [uuid]                                 │
│     └─ (other call variables available)                         │
│     │                                                           │
│     ▼                                                           │
│  5. Execute script                                              │
│     │                                                           │
│     ├─ LUA:                                                     │
│     │   session:execute("lua", "custom_apps/[uuid].lua")       │
│     │                                                           │
│     └─ XML:                                                     │
│         process inline dialplan from file                       │
│     │                                                           │
│     ▼                                                           │
│  6. Script completes                                            │
│     │                                                           │
│     ├─ skip_final_destination = true → DONE (call ends)        │
│     │                                                           │
│     └─ skip_final_destination = false → Step 7                  │
│     │                                                           │
│     ▼                                                           │
│  7. Route to final destination                                  │
│     ├─ extension → transfer("1001 XML default")                │
│     ├─ queue → callcenter("support@...")                       │
│     ├─ ivr → ivr("main_menu")                                  │
│     └─ etc.                                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

---

6. Common Scenarios & Examples

Scenario 1: Recording Disclaimer

Purpose: Play "This call may be recorded" before connecting to support. Configuration:
SettingValue
NameRecording Disclaimer
Trigger99
TypeLua Script
Skip DestinationNo
Final DestinationQueue: support_queue
Script:

Lua
-- Recording Disclaimer
session:answer()
session:sleep(500)
session:streamFile("ivr/this_call_may_be_recorded.wav")
-- Final destination handles transfer to queue

Scenario 2: VIP Caller Detection

Purpose: Check if caller is VIP and route accordingly. Configuration:
SettingValue
NameVIP Router
Trigger77
TypeLua Script
Skip DestinationYes (script handles routing)
Script:

Lua
-- VIP Caller Detection
local caller = session:getVariable("caller_id_number")
local vip_numbers = {"5551234567", "5559876543", "5551111111"}

local is_vip = false
for _, num in ipairs(vip_numbers) do
    if caller:find(num) then
        is_vip = true
        break
    end
end

session:answer()
if is_vip then
    session:streamFile("ivr/vip_welcome.wav")
    session:transfer("1001", "XML", "default")  -- VIP extension
else
    session:transfer("5000", "XML", "default")  -- Regular queue
end

Scenario 3: Emergency Announcement

Purpose: Play emergency message and hang up. Configuration:
SettingValue
NameEmergency Notice
Trigger911
TypeLua Script
Skip DestinationYes
Script:

Lua
-- Emergency Announcement
session:answer()
session:streamFile("emergency/building_evacuation.wav")
session:hangup()

Scenario 4: Simple XML Routing

Purpose: Set a variable and transfer. Configuration:
SettingValue
NameDepartment Router
Trigger50
TypeXML Dialplan
Skip DestinationYes
Script:

Xml
<extension name="custom_router">
  <condition field="destination_number" expression=".*">
    <action application="set" data="department=sales"/>
    <action application="transfer" data="1001 XML default"/>
  </condition>
</extension>

---

7. Limitations & Important Notes

Technical Limitations

WARNING
Syntax Errors: Invalid Lua or XML will cause the application to fail silently. Always check logs.
WARNING
No Debugging UI: Script debugging must be done via FreeSWITCH console/logs.
IMPORTANT
Script Permissions: Scripts run with FreeSWITCH privileges. Be careful with file operations.

Best Practices

  1. Keep Scripts Simple: Complex logic is harder to debug
  2. Use Logging: Add freeswitch.consoleLog("INFO", message) for debugging
  3. Handle Errors: Wrap critical code in pcall() for error handling
  4. Test Offline: Test Lua scripts in a Lua interpreter first
  5. Document Code: Add comments explaining what the script does

Security Considerations

CAUTION
Code Injection: Custom applications run arbitrary code. Restrict who can create them.
CAUTION
External API Calls: Be careful with API calls in scripts—they can slow down call setup.

---

8. Troubleshooting Tips

Common Issues

SymptomPossible CauseSolution
Application not triggeredTrigger number conflictCheck for duplicate extensions
Script errorLua syntax errorCheck FreeSWITCH console logs
No audiosession:answer() missingEnsure call is answered first
Final destination ignoredskip_final_destination = trueSet to false if routing needed
Variables undefinedWrong variable nameCheck available variables

Debugging in FreeSWITCH

Enable Lua debugging:

Bash
fs_cli -x "console loglevel debug"

Watch for custom app execution:

Bash
fs_cli -x "log 7" | grep -i custom_app

Diagnostic SQL

List custom applications:

Sql
SELECT name, trigger_number, app_type, enabled,
       final_destination_module, final_destination_value
FROM public.custom_applications
WHERE domain_id = [domain_id]
ORDER BY trigger_number;

Check script file:

Bash
ls -la /usr/share/freeswitch/scripts/custom_apps/[uuid].lua

---

9. Glossary

TermDefinition
Custom ApplicationUser-defined script that executes when a trigger number is dialed
LuaLightweight programming language used for FreeSWITCH scripting
XML DialplanFreeSWITCH's declarative routing configuration format
Trigger NumberThe extension or feature code that activates the application
Final DestinationWhere the call is routed after the script completes
Skip DestinationOption to not route after script (script handles hangup)
Hot DeployChanges take effect immediately without restart
sessionLua object representing the active call/channel
Channel VariableNamed values attached to a call for data passing
---

10. Suggested UI Improvements

Enhanced Tooltips (Already Good)

The existing tooltips are comprehensive. Minor enhancements:

FieldSuggested Addition
scriptContentAdd link to Lua API documentation
triggerNumberAdd conflict check warning

UX Enhancements

  1. Syntax Validation: Real-time Lua/XML syntax checking in editor

  1. Script Templates: Dropdown of common script templates:
- Announcement + Transfer

- VIP Detection

- Time-Based Routing

- API Integration

  1. Test Button: "Test this application" that initiates a test call

  1. Version History: Track changes to scripts over time

  1. Duplicate Detection: Warn if trigger number conflicts with existing entries

  1. Log Viewer: Show recent execution logs for this application

Editor Improvements

CurrentSuggested
Monaco editorAdd Lua autocomplete for FreeSWITCH API
Plain textSyntax highlighting for FreeSWITCH functions
No validationReal-time syntax error highlighting
---

Lua Script Status ✅

Integration Module

ComponentStatusNotes
Custom Applications✅ ActiveExecutes custom Lua scripts defined in the application's configuration
---

Documentation last updated: January 2026*

AI Assistant

👋 Hello! I'm your Ring2All documentation assistant. I can help you find information about configuring and using the Ring2All PBX platform.

How can I help you today?