Files
claudetools/.claude/skills/packetdial/SKILL.md
Howard Enos dd414c424a sync: auto-sync from HOWARD-HOME at 2026-06-02 15:03:53
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-02 15:03:53
2026-06-02 15:04:49 -07:00

5.3 KiB

name, description
name description
packetdial Manage the Arizona Computer Guru (ACG) PacketDial / OITVOIP hosted-VoIP platform via the NetSapiens SNAPsolution API v2 (pbx.packetdial.com, v44.4). List and inspect domains, users, devices/phones, DIDs (phone numbers), resellers, and pull CDRs (call detail records). Provision new customer domains, users, SIP devices, and phone numbers (all writes gated behind --confirm). Read-only by default. Invoke for: "packetdial", "oitvoip", "oit voip", "netsapiens", "voip portal", "pbx portal", "voip domain", "voip user", "voip extension", "provision phone", "add did", "phone number on voip", "call detail records", "cdr", "voip.packetdial", "pbx.packetdial". NOTE: voip.packetdial.com is the customer-facing portal (the fax/UC dashboard, e.g. Cascades account 28598) and has no API — the programmable surface is pbx.packetdial.com. This skill talks to the LIVE production reseller PBX; treat writes conservatively.

PacketDial / NetSapiens (OITVOIP) Skill

Standalone CLI client for the NetSapiens SNAPsolution API v2 that backs ACG's hosted-VoIP offering through OITVOIP / PacketDial. Read-only by default; every write (create / update / delete) is gated behind --confirm.

The two hostnames (important)

Host What it is API?
voip.packetdial.com Customer-facing white-label portal / UC & fax dashboard (e.g. Cascades fax account 28598). Login-gated UI. No
pbx.packetdial.com Reseller PBX platform — NetSapiens v44.4. Yes — this skill targets it

Credentials — ONE-TIME SETUP (not yet provisioned)

As of this skill's creation no API key exists yet — the vault entry msp-tools/oitvoip.sops.yaml is empty/absent, so every command will fail with a clear "No credentials found" error until you do this once:

  1. Log into pbx.packetdial.com -> Admin > API Keys and create a reseller-scoped key (prefix nsr_). If self-service key creation is not available, reply to Darwin Escaro (OITVOIP) for reseller OAuth client credentials.
  2. Store it in the SOPS vault. Preferred (static bearer key):
    # msp-tools/oitvoip.sops.yaml
    credentials:
      api_key: nsr_xxxxxxxxxxxxxxxx
    
    Or, for OAuth2 password-grant credentials:
    credentials:
      client_id:     <client id>
      client_secret: <client secret>
      username:      <portal user@domain>
      password:      <portal password>
    
  3. That's it — the client auto-detects which shape is present.

The client never hardcodes secrets. Resolution order: PACKETDIAL_API_KEY env -> PACKETDIAL_CLIENT_ID+friends env -> vault credentials.api_key -> vault OAuth fields. Env overrides exist for quick testing without touching the vault.

Running the CLI

This machine's Python launcher is py (per identity.json); python / python3 also work. Run from the scripts dir so the two modules resolve.

cd C:/claudetools/.claude/skills/packetdial/scripts

py ns.py status                 # API version + authenticated key identity
py ns.py domains                # list all domains
py ns.py domain <domain>        # one domain's config
py ns.py users <domain>         # users / extensions in a domain
py ns.py user <domain> <user>
py ns.py phones <domain>        # SIP devices registered in a domain
py ns.py dids <domain>          # phone numbers (DIDs) on a domain
py ns.py devices <domain> <user>
py ns.py cdrs --domain <domain> --start 2026-06-01 --end 2026-06-02
py ns.py resellers

Writes (gated)

Every mutating command prints a [DRY RUN] line and exits non-zero unless you pass --confirm. Bodies are raw JSON matching the NetSapiens v2 schema.

py ns.py create-domain --body '{"domain":"acme","description":"Acme Inc"}' --confirm
py ns.py create-user acme --body '{"user":"101","name-first-name":"Jane"}' --confirm
py ns.py create-phone acme --body '{...}' --confirm
py ns.py create-did acme --body '{"phonenumber":"15205551234"}' --confirm
py ns.py update-user acme 101 --body '{"name-last-name":"Doe"}' --confirm
py ns.py delete-user acme 101 --confirm

Raw escape hatch (any of the 239 v2 paths)

The named commands cover the common surface; for anything else, hit the path directly. Non-GET methods still require --confirm.

py ns.py raw GET  domains/acme/users/101/answerrules
py ns.py raw POST domains/acme/users --body '{...}' --confirm

Standard provisioning flow (new customer)

  1. create-domain -> dial plan auto-generates
  2. create-user per extension
  3. create-phone per SIP device (MAC-provisioned)
  4. create-did to attach DIDs and route them to users
  5. Log the work back to the Syncro ticket

Notes

  • This is the LIVE production reseller PBX. A bad create-domain or delete-user affects real customers — confirm the target domain first with a read command before any write.
  • CDR queries can be large; always pass --start/--end and a --limit.
  • Reference detail (auth shapes, full endpoint inventory) lives in references/api.md.