packetdial: build out + document the skill against the live NetSapiens v2 API

Key is now provisioned + live-verified, so grounded the skill in the real spec (RTFM):
- Mapped the OpenAPI surface (v44.4.10, 239 paths / 354 ops) — capability map added to
  SKILL.md (what the platform exposes vs what's wrapped vs raw-only).
- Added 6 live-verified read wrappers (ns.py + ns_client.py): callqueues, timeframes,
  sites, contacts, autoattendants, billing (domain limits/usage).
- Replaced the stale "not yet provisioned" credentials section with the live status
  (vaulted nsr_ reseller key, key-id nsr_hSGUB5Wo, scope Reseller 91912.service, RW) +
  the pbx.packetdial.com vs api.ucaasnetwork.com hostname note + override.
- api.md history updated. Writes remain gated behind --confirm; everything unwrapped
  reachable via `raw`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 07:36:12 -07:00
parent 567986fa49
commit d75c367bf7
4 changed files with 98 additions and 27 deletions

View File

@@ -351,6 +351,31 @@ class NetSapiensClient:
def subscriptions(self) -> Any:
return self.request("GET", "subscriptions")
# --- per-domain feature resources (live-verified shapes, 2026-06-22) ---
def callqueues(self, domain: str) -> Any:
"""ACD call queues in a domain (agents, dispatch type, live queued count)."""
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/callqueues")
def timeframes(self, domain: str) -> Any:
"""Time-based routing schedules (business hours / holidays) for a domain."""
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/timeframes")
def sites(self, domain: str) -> Any:
"""Multi-site definitions within a domain."""
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/sites")
def contacts(self, domain: str) -> Any:
"""Shared/domain contacts (address book)."""
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/contacts")
def autoattendants(self, domain: str) -> Any:
"""Auto-attendants (IVR menus) in a domain."""
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/autoattendants")
def billing(self, domain: str) -> Any:
"""Domain billing/limits snapshot: max + current counts (users, queues, AAs, calls)."""
return self.request("GET", f"domains/{urllib.parse.quote(domain)}/billing")
# ======================================================================
# WRITE METHODS (gated — the CLI requires --confirm before calling these)
# ======================================================================