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>
5.9 KiB
5.9 KiB
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 returnserrors/not_found.
Authentication (bearerAuth)
All calls send Authorization: Bearer <token>. Two ways to get the token:
- Static API key — created in
pbx.packetdial.comAdmin > API Keys. Prefix encodes scope:nsr_= reseller,nss_= system,nsd_= domain. Use the key string directly as the bearer token (no exchange step). - OAuth2 password grant —
POST /ns-api/v2/tokensform-encoded:grant_type=password&client_id=..&client_secret=..&username=..&password=..Response includesaccess_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(anddomain,userscoping via the nested path). Always bound CDR queries — they can be large.
Provisioning flow (new customer domain)
POST /domains— creates the domain; dial plan auto-generates.POST /domains/{domain}/users— one per extension.POST /domains/{domain}/users/{user}/devicesorPOST /domains/{domain}/phones— SIP devices (MAC provisioning).POST /domains/{domain}/phonenumbers— attach DIDs, route to users.- Configure
answerrulesas 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 inmsp-tools/oitvoip.sops.yamlwas the open TODO. - 2026-06-02:
packetdialskill created wrapping the v2 API (read-by-default, gated writes). Confirmedvoip.is portal-only andpbx.is the API host. - 2026-06-22: Reseller API key provisioned + vaulted (
msp-tools/oitvoip.sops.yaml, key-idnsr_hSGUB5Wo, scope Reseller91912.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 thearizonacomputergurutest 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--bodyverbatim. Note: entry-bearing timeframe types (days-of-week etc.) reject create without their array — createalwaysthen 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 onarizonacomputerguru: 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 — E911address-formatted-pidfloviaaddresses/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 onraw.