Files
claudetools/.claude/skills/packetdial/references/api.md
Mike Swanson 1062a5ed44 packetdial: finish resource wrapping (reads + gated writes across the platform)
Added read wrappers: addresses (E911), smsnumbers, blocked-numbers, moh, dialrules,
recording, transcriptions. Added gated write wrappers: DID update/delete, per-user device
CRUD, E911 address CRUD, contact CRUD, site create/update, auto-attendant create, SMS
number CRUD, block/unblock numbers, MoH TTS create/delete.

Verification: contact create→delete lifecycle verified on arizonacomputerguru (id field is
`unique-id`); reads for addresses/blocked-numbers/moh verified. Remaining writes are plumbed
per the OpenAPI spec [P] but not lifecycle-verified (test domain lacks the feature or needs a
special body) — SKILL.md marks each [V]/[P] and documents the gotchas (E911 pidflo via
addresses/validate; SMS not provisioned on test domain; number-filters add 202'd but didn't
persist; MoH file upload is multipart -> raw). Capability map + api.md history updated.
All writes --confirm-gated; anything unwrapped still reachable via `raw`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 08:05:06 -07:00

105 lines
5.9 KiB
Markdown

# NetSapiens SNAPsolution API v2 — Reference (PacketDial / OITVOIP)
Source of truth: the live OpenAPI spec at
`https://pbx.packetdial.com/ns-api/webroot/openapi/openapi.json`
(title "NetSapiens API v2", version 44.4.10 as of 2026-06-02).
## Hosts
- **API host:** `pbx.packetdial.com``https://pbx.packetdial.com/ns-api/v2`
- **Customer portal (no API):** `voip.packetdial.com` — login-gated UI; the
Cascades fax/UC dashboard lives here (account 28598). Hitting `/ns-api/*` on
this host returns `errors/not_found`.
## Authentication (`bearerAuth`)
All calls send `Authorization: Bearer <token>`. Two ways to get the token:
1. **Static API key** — created in `pbx.packetdial.com` Admin > API Keys.
Prefix encodes scope: `nsr_` = reseller, `nss_` = system, `nsd_` = domain.
Use the key string directly as the bearer token (no exchange step).
2. **OAuth2 password grant**`POST /ns-api/v2/tokens` form-encoded:
`grant_type=password&client_id=..&client_secret=..&username=..&password=..`
Response includes `access_token` (JWT) + `expires_in`. The client caches it
and refreshes ~60s before expiry.
## Endpoint inventory (239 paths, grouped)
Top-level resource groups and the methods present:
| Resource | Methods | Notes |
|---|---|---|
| `/version` | GET | platform version |
| `/apikeys`, `/apikeys/{id}`, `/apikeys/~` | GET POST PUT DELETE | `~` = current key |
| `/tokens`, `/jwt` | POST (+ GET/DELETE on jwt) | auth / token mgmt |
| `/resellers`, `/resellers/{reseller}` | GET POST PUT DELETE | |
| `/domains`, `/domains/{domain}` | GET POST PUT PATCH DELETE | `/domains/count` for totals |
| `/domains/{domain}/users`, `/users/{user}` | GET POST PUT DELETE | extensions |
| `/domains/{domain}/users/{user}/devices` | GET POST PUT DELETE | per-user SIP devices |
| `/domains/{domain}/users/{user}/answerrules` | GET POST | call routing |
| `/domains/{domain}/users/{user}/cdrs` | GET | per-user CDRs |
| `/domains/{domain}/phones` | GET POST PUT DELETE | domain device list |
| `/domains/{domain}/phonenumbers`, `/{phonenumber}` | GET POST PUT DELETE | DIDs |
| `/domains/{domain}/addresses`, `/addresses/endpoints` | GET POST PUT DELETE | emergency/E911 addrs |
| `/domains/{domain}/cdrs`, `/cdrs` | GET | call detail records (`/count` variants) |
| `/phonenumbers` | GET | global DID search |
| `/smsnumbers` | GET | |
| `/subscriptions` | GET POST PUT DELETE | event/webhook subs |
| `/connections`, `/routes`, `/routecon` | GET POST PUT DELETE | SIP trunks / routing |
| `/configurations`, `/config-definitions`, `/templates` | GET POST PUT DELETE | |
| `/certificates`, `/images` | GET POST PUT DELETE | |
| `/meetings`, `/video`, `/firebase` | GET POST | UC / video |
| `/sipflow` | GET | SIP trace |
| `/holidays`, `/cdrs` | GET | |
| `/backup`, `/restore` | POST / GET PUT | platform backup |
Many resources also expose `/count` (totals) and `#1/#2/#3` openapi-dedup
variants (same path, different query-param shapes). Use the Swagger UI for the
exact request/response schema of any specific path.
## Common query params
- List endpoints accept `limit`, `offset`, and resource-specific filters.
- CDR endpoints accept `start-date` / `end-date` (and `domain`, `user` scoping
via the nested path). Always bound CDR queries — they can be large.
## Provisioning flow (new customer domain)
1. `POST /domains` — creates the domain; dial plan auto-generates.
2. `POST /domains/{domain}/users` — one per extension.
3. `POST /domains/{domain}/users/{user}/devices` or
`POST /domains/{domain}/phones` — SIP devices (MAC provisioning).
4. `POST /domains/{domain}/phonenumbers` — attach DIDs, route to users.
5. Configure `answerrules` as needed.
## History
- 2026-04-20: API researched (session log `session-logs/2026-04-20-session.md`,
"OITVOIP / NetSapiens API Research"). Platform identified, auth shapes
documented. **No API key created yet** — provisioning the key + storing it in
`msp-tools/oitvoip.sops.yaml` was the open TODO.
- 2026-06-02: `packetdial` skill created wrapping the v2 API (read-by-default,
gated writes). Confirmed `voip.` is portal-only and `pbx.` is the API host.
- 2026-06-22: **Reseller API key provisioned + vaulted** (`msp-tools/oitvoip.sops.yaml`,
key-id `nsr_hSGUB5Wo`, scope Reseller `91912.service`, read-write). Live-verified end to
end. RTFM pass over the v2 spec (v44.4.10, 239 paths / 354 ops) — capability map added to
SKILL.md. Added live-verified read wrappers: `callqueues`, `timeframes`, `sites`,
`contacts`, `autoattendants`, `billing`. Reseller territory = 3 domains today
(arizonacomputerguru + two `*.91912.service`).
Added gated WRITE wrappers for call queues (`create/update/delete-callqueue`,
`add/update/remove-agent`) and time frames (`create/update/delete-timeframe`), each
live-verified create→update→delete on the `arizonacomputerguru` test domain (sanctioned
test bed, not in production use). Timeframe writes are body-discriminated (same path; the
server selects the op from the body) — wrappers pass `--body` verbatim. Note: entry-bearing
timeframe types (days-of-week etc.) reject create without their array — create `always` then
convert, or include the array.
Finished the resource wrapping: added reads (`addresses`, `smsnumbers`, `blocked-numbers`,
`moh`, `dialrules`, `recording`, `transcriptions`) and gated writes (DID update/delete,
per-user device CRUD, E911 address CRUD, contact CRUD, site create/update, auto-attendant
create, SMS number CRUD, block/unblock numbers, MoH TTS create/delete). Verified [V]
lifecycles on `arizonacomputerguru`: contact create→delete (id = `unique-id`), plus the
callqueue/timeframe lifecycles. The rest are plumbed per spec [P] but not lifecycle-verified
(test domain lacks the feature, or needs a special body — E911 `address-formatted-pidflo` via
`addresses/validate`; SMS not provisioned; number-filters add 202'd but didn't persist on the
empty domain). Multipart MoH upload + dialrule writes + queue-agent PATCH stay on `raw`.