packetdial: add onboard-domain wrapper (GUI Add-a-Domain -> 3-call API flow)

onboard-domain runs POST /domains -> addresses/validate (gen E911 pidflo) -> addresses/create
from one JSON body (domain fields + optional `emergency` block), gated --confirm. Reverse-
engineered from the OITVOIP wizard screenshots; live-created the real client domain
vwp.91912.service (Valley Wide Plastering) + E911 address, and proved the wrapper with a
throwaway create->delete (no leftovers, vwp intact). Documented GUI->API mapping + the two
manual gaps (voicemail user-defaults, email-send-from-address pending the packetdial.com mailbox)
+ the domain-type "no"-on-create quirk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 09:34:48 -07:00
parent 4157fc6f1d
commit d1d1302d55
3 changed files with 89 additions and 0 deletions

View File

@@ -202,6 +202,44 @@ The live OpenAPI spec is **NetSapiens API v2 v44.4.10** — **239 paths / 354 op
`--confirm`). The local spec copy used for this map: `.claude/tmp/ns-openapi.json` (refetch
from `pbx.packetdial.com/ns-api/webroot/openapi/openapi.json`).
## Onboard a new client domain (`onboard-domain`)
One gated command that mirrors the OITVOIP "Add a Domain" GUI wizard (Basic + Defaults +
Limitations + Emergency) and runs the **3-call flow**: `POST /domains``POST
.../addresses/validate` (generates the E911 `pidflo`) → `POST .../addresses`. Body = the
`POST /domains` fields **plus an optional `emergency` sub-object** (the E911 address). Verified
end-to-end on the production reseller (created vwp.91912.service for real; throwaway
create→delete to prove the wrapper).
```bash
ns.py onboard-domain --body-file new-client.json --confirm # --body '<json>' also works
```
`new-client.json` (the vwp example — note `domain` is the FULL name incl. the reseller suffix):
```json
{
"domain": "vwp.91912.service", "reseller": "91912.service",
"description": "Valley Wide Plastering", "domain-type": "Standard",
"dial-policy": "US and Canada", "time-zone": "America/Phoenix", "area-code": 480,
"caller-id-name": "Valley Wide Plastering", "caller-id-number": 4807059500,
"caller-id-number-emergency": 4807059500,
"single-sign-on-enabled": "no", "music-on-hold-randomized-enabled": "no",
"emergency": {
"address-name": "Valley Wide Plastering", "caller-name": "ValleyWidePlastering",
"address-line-1": "301 N 56TH ST", "address-country-abbreviation": "US",
"address-state-province-abbreviation": "AZ", "address-city": "CHANDLER",
"address-postal-code": "85226", "address-location-description": "Main"
}
}
```
GUI→API mapping: Name+suffix → `domain`; Dial Permission → `dial-policy`; Limitations →
`limits-max-*` (omit for "unlimited"); Emergency tab → the `emergency` block. Omitting `dial-plan`
auto-generates one named after the domain. **Two known gaps vs. the GUI** (still manual): the
Voicemail user-defaults (Enable/Transcription/Message) aren't in `POST /domains`, and
`email-send-from-address` (e.g. `voicemail@packetdial.com`) is left blank until that mailbox
exists — set it after with `raw PUT domains/<domain> --body '{"email-send-from-address":"..."}'`.
`domain-type` occasionally stores as `"no"` on create — re-`PUT` it if so. Undo a bad onboard:
`raw DELETE domains/<domain> --confirm`.
## Standard provisioning flow (new customer)
1. `create-domain` -> dial plan auto-generates