# Complete VoIP Client Setup - PacketDial/NetSapiens

**Client:** Valley Wide Plastering
**Domain:** vwp.91912.service
**Date:** 2026-07-09

---

## Overview

Setting up a complete VoIP client involves more than just users and phones. This document explores all elements needed for a production-ready VoIP deployment.

## Current VWP Status

Based on live API queries (2026-07-09):

```
Domain: vwp.91912.service
Users: 2 configured (needs 11 more from CSV)
DIDs: 0 (no phone numbers assigned)
Call Queues: 0 (no ring groups)
Auto-Attendants: 0 (no IVR menus)
Time Frames: 0 (no business hours routing)
Sites: 0 (single-site default)
```

---

## 1. Phone Number (DID) Management

### What DIDs Are

DIDs (Direct Inward Dialing) are phone numbers that route inbound calls to your PBX. Each DID needs routing rules to determine where calls go.

### DID Routing Applications

PacketDial supports multiple routing methods via `dial-rule-application`:

| Application | Routes To | Use Case |
|-------------|-----------|----------|
| `to-user` | Specific extension | Direct line to one person |
| `to-user-residential` | User with residential features | Home/mobile integration |
| `to-queue` | Call queue (ring group) | Sales, support, general line |
| `to-attendant` | Auto-attendant (IVR) | Main company line with menu |
| `to-voicemail` | Voicemail box | After-hours voicemail-only line |
| `to-hunt-group` | Hunt group | Sequential/round-robin routing |

### Example: ACG Domain DIDs

From `arizonacomputerguru` domain:

```json
{
  "phonenumber": "15202651226",
  "dial-rule-application": "to-user",
  "dial-rule-translation-destination-user": "15202651226",
  "dial-rule-description": "Main office line - routes to extension 1226"
}
```

### VWP DID Strategy

**Main Number:** 480-705-9500 (from wiki)

**Recommended Initial Setup:**
1. Create main DID → routes to auto-attendant (IVR menu)
2. Auto-attendant options:
   - Press 0 → receptionist (or general queue)
   - Press 1 → sales queue
   - Press 2 → accounting/payroll
   - Direct dial by extension (1-0-2 for extension 102)

**API Command to Create DID:**

```bash
# Option 1: Route to specific user (direct line)
ns.py create-did vwp.91912.service --body '{
  "phonenumber": "14807059500",
  "dial-rule-application": "to-user",
  "dial-rule-translation-destination-user": "102",
  "dial-rule-description": "Main line - Jesse Guerrero"
}' --confirm

# Option 2: Route to call queue (recommended for main line)
ns.py create-did vwp.91912.service --body '{
  "phonenumber": "14807059500",
  "dial-rule-application": "to-queue",
  "dial-rule-parameter": "8000",
  "dial-rule-description": "Main line - General queue"
}' --confirm

# Option 3: Route to auto-attendant (best for main line)
ns.py create-did vwp.91912.service --body '{
  "phonenumber": "14807059500",
  "dial-rule-application": "to-attendant",
  "dial-rule-parameter": "3000",
  "dial-rule-description": "Main line - IVR menu"
}' --confirm
```

---

## 2. Call Queues (Ring Groups)

### What They Are

Call queues ring multiple phones simultaneously or in sequence until someone answers. Essential for:
- Reception/front desk
- Sales teams
- Support teams
- After-hours coverage

### Call Queue Features

- **Dispatch Types:**
  - `Ring-all` (simultaneous) - all phones ring at once
  - `Round-robin` - distributes calls evenly
  - `Top-down` - tries agents in order
  - `Longest-idle` - routes to agent idle longest

- **Queue Music:** Plays music while callers wait
- **Position Announcements:** "You are caller number 3"
- **Overflow:** Route to voicemail after X rings or Y minutes
- **Agent Login/Logout:** Agents can log in/out of queue

### Creating a Call Queue

**Example: General Reception Queue**

```bash
# Step 1: Create the queue
ns.py create-callqueue vwp.91912.service --body '{
  "synchronous": "yes",
  "callqueue": "8000",
  "description": "General Reception",
  "callqueue-dispatch-type": "Ring-all",
  "callqueue-max-wait-time": 300,
  "callqueue-no-answer-destination": "voicemail:8000@vwp.91912.service"
}' --confirm

# Step 2: Add agents (users who will receive calls)
ns.py add-agent vwp.91912.service 8000 --body '{
  "callqueue-agent-id": "102@vwp.91912.service",
  "callqueue-agent-dispatch-order-ordinal": 1
}' --confirm

ns.py add-agent vwp.91912.service 8000 --body '{
  "callqueue-agent-id": "103@vwp.91912.service",
  "callqueue-agent-dispatch-order-ordinal": 2
}' --confirm
```

### VWP Queue Recommendations

Based on the 18 extensions provided:

1. **Queue 8000 - General/Reception**
   - Agents: Jesse (102), Rose (103), Shelly (104)
   - Dispatch: Ring-all
   - Purpose: Main company line

2. **Queue 8001 - Management**
   - Agents: Jesse (102), J.R. (105), Chris (113)
   - Dispatch: Top-down
   - Purpose: Escalated calls

3. **Queue 8002 - Accounting/Payroll**
   - Agents: Payroll (107), Toni (115)
   - Dispatch: Ring-all
   - Purpose: Billing inquiries

---

## 3. Auto-Attendants (IVR Menus)

### What They Are

Interactive Voice Response (IVR) menus that greet callers and route based on keypress:
- "Press 1 for Sales, Press 2 for Support, Press 0 for Operator"

### Auto-Attendant Structure

Components:
1. **Greeting Prompt:** Audio message callers hear
2. **Menu Options:** Keypresses (0-9, *, #)
3. **Destinations:** Where each option routes (user, queue, voicemail, sub-menu)
4. **Timeout Action:** What happens if caller doesn't press anything
5. **Invalid Action:** What happens on invalid keypress

### Creating an Auto-Attendant

```bash
# Create basic auto-attendant
ns.py create-autoattendant vwp.91912.service --body '{
  "synchronous": "yes",
  "user": "3000",
  "attendant-name": "Main Menu",
  "attendant-greeting-prompt": "Welcome to Valley Wide Plastering. Press 1 for Sales, Press 2 for Accounting, or stay on the line for our receptionist.",
  "attendant-timeout-seconds": 10,
  "attendant-timeout-destination": "queue:8000@vwp.91912.service"
}' --confirm
```

**Note:** The greeting prompt can be:
- Text (uses TTS - text-to-speech)
- Uploaded audio file (.wav)
- Professionally recorded message

### Menu Option Configuration

After creating the auto-attendant, add menu options:

```bash
# Option 1: Route to queue
ns.py raw POST domains/vwp.91912.service/autoattendants/3000/options --body '{
  "key": "1",
  "destination": "queue:8001@vwp.91912.service",
  "description": "Sales"
}' --confirm

# Option 2: Route to specific extension
ns.py raw POST domains/vwp.91912.service/autoattendants/3000/options --body '{
  "key": "2",
  "destination": "user:107@vwp.91912.service",
  "description": "Payroll"
}' --confirm

# Option 0: Operator
ns.py raw POST domains/vwp.91912.service/autoattendants/3000/options --body '{
  "key": "0",
  "destination": "queue:8000@vwp.91912.service",
  "description": "Receptionist"
}' --confirm
```

---

## 4. Time Frames (Business Hours Routing)

### What They Are

Time-based routing rules that change call handling based on:
- Day of week (Monday-Friday vs weekend)
- Time of day (business hours vs after-hours)
- Specific dates (holidays, company events)

### Time Frame Types

| Type | Use Case |
|------|----------|
| `always` | Always active (default) |
| `days-of-week` | M-F 8am-5pm, etc. |
| `specific-dates` | Dec 25, Jan 1, company holidays |
| `holiday` | Follows holiday calendar |
| `custom` | Complex logic |

### Creating Business Hours

```bash
# Step 1: Create business hours timeframe
ns.py create-timeframe vwp.91912.service --body '{
  "synchronous": "yes",
  "timeframe-name": "Business Hours",
  "timeframe-type": "days-of-week",
  "timeframe-days-of-week-array": [
    {
      "day-of-week": "monday",
      "start-time": "08:00:00",
      "end-time": "17:00:00"
    },
    {
      "day-of-week": "tuesday",
      "start-time": "08:00:00",
      "end-time": "17:00:00"
    },
    {
      "day-of-week": "wednesday",
      "start-time": "08:00:00",
      "end-time": "17:00:00"
    },
    {
      "day-of-week": "thursday",
      "start-time": "08:00:00",
      "end-time": "17:00:00"
    },
    {
      "day-of-week": "friday",
      "start-time": "08:00:00",
      "end-time": "17:00:00"
    }
  ]
}' --confirm

# Step 2: Create after-hours timeframe
ns.py create-timeframe vwp.91912.service --body '{
  "synchronous": "yes",
  "timeframe-name": "After Hours",
  "timeframe-type": "always"
}' --confirm
```

### Using Time Frames with DIDs

Modify DID routing based on time:

```bash
# Update DID to use time-based routing
ns.py update-did vwp.91912.service 14807059500 --body '{
  "dial-rule-matching-timeframe": "{timeframe-id-business-hours}",
  "dial-rule-application": "to-attendant",
  "dial-rule-parameter": "3000"
}' --confirm
```

**After-Hours DID Rule:**
```bash
# Create second rule for same DID (after-hours)
ns.py create-did vwp.91912.service --body '{
  "phonenumber": "14807059500",
  "dial-rule-matching-timeframe": "{timeframe-id-after-hours}",
  "dial-rule-application": "to-voicemail",
  "dial-rule-parameter": "8000",
  "dial-rule-description": "After hours - main voicemail"
}' --confirm
```

---

## 5. Other Client Setup Elements

### Sites (Multi-Location)

For clients with multiple physical locations:

```bash
ns.py create-site vwp.91912.service --body '{
  "site": "Chandler-Main",
  "site-description": "Main Office - 301 N 56th St",
  "site-address-line-1": "301 N 56TH ST",
  "site-address-city": "CHANDLER",
  "site-address-state-province-abbreviation": "AZ",
  "site-address-postal-code": "85226"
}' --confirm
```

**Use Case:** Different caller ID, different local area code, site-to-site dialing

### Hunt Groups

Similar to queues but with sequential routing:

```bash
# Ring extension 102, if no answer try 103, then 104
ns.py create-huntgroup vwp.91912.service --body '{
  "huntgroup": "9000",
  "description": "Management Hunt",
  "huntgroup-type": "sequential",
  "huntgroup-members": ["102", "103", "104"],
  "huntgroup-timeout": 20
}' --confirm
```

### Voicemail-Only Numbers

For departments without dedicated phones:

```bash
ns.py create-user vwp.91912.service --body '{
  "user": "9999",
  "name-first-name": "Warehouse",
  "name-last-name": "Voicemail",
  "email": "warehouse@valleywideplastering.com",
  "emergency-address-id": "a-6a395c03d4cfe"
}' --confirm

# Route DID directly to voicemail (no ringing)
ns.py create-did vwp.91912.service --body '{
  "phonenumber": "14807059501",
  "dial-rule-application": "to-voicemail",
  "dial-rule-parameter": "9999",
  "dial-rule-description": "Warehouse messages"
}' --confirm
```

### Fax to Email

Enable fax reception (routes faxes to email as PDF):

```bash
ns.py create-faxaccount vwp.91912.service --body '{
  "user": "8888",
  "email": "faxes@valleywideplastering.com",
  "description": "Main fax line"
}' --confirm

# Assign DID to fax
ns.py create-did vwp.91912.service --body '{
  "phonenumber": "14807059502",
  "dial-rule-application": "to-fax",
  "dial-rule-parameter": "8888",
  "dial-rule-description": "Fax line"
}' --confirm
```

---

## 6. Recommended VWP Setup Plan

### Phase 1: Basic Connectivity (DONE/IN PROGRESS)
- [x] Domain created
- [x] E911 address configured
- [x] 11 matched users ready for CSV import
- [ ] Users created in PacketDial
- [ ] Devices assigned as phones distributed

### Phase 2: Main Line Setup (NEXT)

1. **Create General Reception Queue (8000)**
   - Agents: Jesse (102), Rose (103), Shelly (104)
   - Dispatch: Ring-all
   - Max wait: 60 seconds → voicemail

2. **Create Main Auto-Attendant (3000)**
   - Greeting: "Thank you for calling Valley Wide Plastering..."
   - Option 0: Reception queue (8000)
   - Option 1: Sales/Estimating - Bart (116)
   - Option 2: Accounting/Payroll - Payroll dept (107)
   - Timeout: Ring reception queue (8000)

3. **Assign Main DID**
   - Number: 480-705-9500
   - Route to: Auto-attendant (3000)

### Phase 3: Business Hours Routing

1. **Create Business Hours Time Frame**
   - Monday-Friday, 7:00 AM - 5:00 PM (Arizona time)

2. **Create After-Hours Time Frame**
   - All other times

3. **Update Main DID Routing**
   - Business hours: Auto-attendant (3000)
   - After hours: General voicemail (8000)

### Phase 4: Additional Features

1. **Department Queues**
   - Management queue (8001)
   - Accounting queue (8002)

2. **Shared Extensions**
   - Kitchen (111) - physical phone
   - Conference Room (112) - physical phone
   - Warehouse (118) - voicemail only or physical phone

3. **Direct Lines (if needed)**
   - Additional DIDs for key personnel
   - Port existing numbers

---

## 7. Complete Setup Script Outline

### Inputs Needed
```json
{
  "domain": "vwp.91912.service",
  "main_did": "14807059500",
  "business_hours": {
    "start": "07:00:00",
    "end": "17:00:00",
    "days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
    "timezone": "America/Phoenix"
  },
  "queues": [
    {
      "id": "8000",
      "name": "General Reception",
      "agents": ["102", "103", "104"],
      "dispatch": "Ring-all"
    }
  ],
  "auto_attendant": {
    "id": "3000",
    "greeting": "Thank you for calling Valley Wide Plastering. For reception, press 0. For estimating, press 1. For accounting, press 2.",
    "options": [
      {"key": "0", "destination": "queue:8000"},
      {"key": "1", "destination": "user:116"},
      {"key": "2", "destination": "user:107"}
    ],
    "timeout_destination": "queue:8000"
  }
}
```

### Execution Order

1. Verify users exist (from CSV import)
2. Create call queue(s)
3. Add agents to queue(s)
4. Create auto-attendant
5. Configure auto-attendant menu options
6. Create business hours timeframe
7. Create after-hours timeframe
8. Create main DID with business hours routing
9. Create after-hours DID rule
10. Test inbound calling
11. Verify voicemail delivery

---

## 8. Testing Checklist

### Inbound Call Testing

- [ ] Call main number during business hours → hears auto-attendant
- [ ] Press 0 → rings reception queue (multiple phones)
- [ ] Press 1 → rings estimating (ext 116)
- [ ] Press 2 → rings accounting (ext 107)
- [ ] Press invalid key → reprompts or routes to default
- [ ] Wait without pressing anything → routes to reception
- [ ] Call after hours → goes directly to voicemail
- [ ] Check voicemail email delivery

### Internal Calling

- [ ] Dial extension-to-extension (e.g., 102 calls 103)
- [ ] Dial queue extension (e.g., 102 dials 8000)
- [ ] Transfer calls between extensions
- [ ] Conference calling works
- [ ] Voicemail-to-email delivery
- [ ] Call park/pickup (if configured)

### Outbound Calling

- [ ] Extension dials external number (verify caller ID shows main number)
- [ ] Emergency calls (911) route correctly
- [ ] Long distance allowed per dial-policy
- [ ] International blocked (unless needed)

---

## 9. Next Steps for VWP

**Immediate (After CSV Import):**
1. Verify 11 users created successfully
2. Get client clarification on 7 unmatched extensions
3. Create general reception queue (8000)
4. Create main auto-attendant (3000)
5. Assign main DID (480-705-9500)

**Short-term:**
1. Set up business hours routing
2. Assign physical phones to users
3. Create additional queues as needed
4. Configure voicemail greetings
5. Test all call flows

**Optional/Future:**
1. Port additional phone numbers
2. Set up department-specific DIDs
3. Configure call recording (if needed)
4. Set up fax-to-email
5. Add reporting/analytics

---

## API Commands Reference

### DIDs
```bash
ns.py dids {domain}                       # List all DIDs
ns.py create-did {domain} --body '{...}'  # Create DID
ns.py update-did {domain} {number} --body '{...}'  # Update routing
ns.py delete-did {domain} {number} --confirm  # Remove DID
```

### Call Queues
```bash
ns.py callqueues {domain}                 # List queues
ns.py create-callqueue {domain} --body '{...}' --confirm
ns.py add-agent {domain} {queue} --body '{...}' --confirm
ns.py remove-agent {domain} {queue} {agent} --confirm
ns.py delete-callqueue {domain} {queue} --confirm
```

### Auto-Attendants
```bash
ns.py autoattendants {domain}             # List auto-attendants
ns.py create-autoattendant {domain} --body '{...}' --confirm
ns.py raw POST domains/{domain}/autoattendants/{id}/options --body '{...}'
```

### Time Frames
```bash
ns.py timeframes {domain}                 # List time frames
ns.py create-timeframe {domain} --body '{...}' --confirm
ns.py update-timeframe {domain} {id} --body '{...}' --confirm
ns.py delete-timeframe {domain} {id} --confirm
```

---

**Last Updated:** 2026-07-09
**Document Status:** Exploration / Planning
**Next Action:** Discuss with client which features are needed for go-live
