Files
claudetools/.claude/skills/yealink-ymcs/SKILL.md
Mike Swanson c3aeef60fb sync: auto-sync from GURU-5070 at 2026-07-01 15:06:42
Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-07-01 15:06:42
2026-07-01 15:07:39 -07:00

5.0 KiB

name, description
name description
yealink-ymcs Manage ACG's Yealink phone fleets via the YMCS v2 API: sites/devices/accounts/firmware/alarms/RPS; gated writes (add MAC, reboot, push SIP account). Pairs with packetdial. Triggers: yealink, ymcs, provision phone, register MAC, RPS, reboot phone.

yealink-ymcs — Yealink Management Cloud Service (YMCS) v2 API

Manages the physical Yealink phones for ACG-managed clients. Pairs with packetdial: the PBX (NetSapiens/PacketDial) owns the SIP accounts; YMCS owns the phones (provisioning, config, firmware, RPS zero-touch). See reference_packetdial_oit_netsapiens for the vendor stack.

Auth (v2 — token, not the legacy RPS HMAC)

POST /v2/token with HTTP Basic base64(AccessKeyID:Secret) (+ timestamp ms + nonce headers + body {"grant_type":"client_credentials"}) → bearer token (~24h). Subsequent calls send Authorization: Bearer <token>. Creds from vault services/yealink-ymcs.sops.yaml (credentials.access_key_id / access_key_secret); env overrides YMCS_ACCESS_KEY_ID / YMCS_ACCESS_KEY_SECRET; region YMCS_REGION (us|eu|au, default us → us-api.ymcs.yealink.com). Yealink servers require LEGACY TLS renegotiation — handled in-client via an SSL context with OP_LEGACY_SERVER_CONNECT.

Account scope (verified 2026-06-22)

The ACG AccessKey is the parent account — one key sees all client sites as children: Arizona Computer Guru LLC (parent) → VWP (Valley Wide Plastering), GuruHQ, Ace Pick Up Parks. No per-client keys needed. (Per-client YMCS portal logins still exist, e.g. Valleywide in clients/valleywide/, but the API key covers everything.)

Commands

PY="$CLAUDETOOLS_ROOT/.claude/scripts/py.sh"; Y=".claude/skills/yealink-ymcs/scripts/ymcs.py"
# reads (live-verified [V] unless noted)
bash "$PY" "$Y" sites                 # [V] site tree (id/name/parentId/level)
bash "$PY" "$Y" devices [--site <id>] # [V] devices (keys: mac, modelName, deviceStatus, siteId, sn, programVersion, wanIp...) — --site filter is best-effort [P]
bash "$PY" "$Y" accounts              # [V] device accounts
bash "$PY" "$Y" device-groups | device-configs | firmwares | models | alarms | oplogs
bash "$PY" "$Y" official-firmwares    # [P] returns a non-standard shape; may need a model param
bash "$PY" "$Y" rps-servers           # [V] RPS provisioning servers (ACG: "WL - ACG" ftp://p.packetdials.net)
bash "$PY" "$Y" rps-devices           # [V] devices registered in RPS
# writes (ALL gated --confirm)
bash "$PY" "$Y" add-devices-by-mac --body '{...}' --confirm   # bulk-add phones by MAC to a site
bash "$PY" "$Y" add-sipaccount --body '{...}' --confirm        # push a SIP account onto a device (PBX glue)
bash "$PY" "$Y" reboot --body '{"ids":[...]}' --confirm        # reboot device(s)
bash "$PY" "$Y" reset  --body '{"ids":[...]}' --confirm        # FACTORY RESET — careful
bash "$PY" "$Y" rps-add --body '{...}' --confirm               # add device(s) to RPS (zero-touch)
bash "$PY" "$Y" rps-del --body '{...}' --confirm
bash "$PY" "$Y" raw POST /v2/dm/listDevices --body '{"skip":0,"limit":50,"autoCount":true}' [--confirm]

List endpoints page automatically ({skip,limit,autoCount}{total, data:[]}); the wrappers return {total, count, data} with all pages.

How it pairs with packetdial (the onboarding pipeline)

  1. packetdial onboard-domain → create the PBX domain + users + DIDs (NetSapiens SIP accounts).
  2. yealink-ymcs → the phones: add-devices-by-mac into the client's site, add-sipaccount to push each NetSapiens SIP cred onto its phone, and/or rps-add so the phone zero-touch- provisions on first boot (RPS server WL - ACG = ftp://p.packetdials.net).
  3. Result: new client → domain live → phones registered to pbx.packetdial.com. VWP is the live pilot (just onboarded to the PBX; 21 devices in YMCS, fleet partly pending).

Gotchas

  • Legacy TLS (handled). If a future Python drops OP_LEGACY_SERVER_CONNECT, connections fail.
  • MSYS path conversion: in raw, a leading /v2/... arg gets rewritten by Git-Bash to C:/Program Files/Git/v2/.... The raw command auto-recovers (cuts back to /v2/); don't use MSYS_NO_PATHCONV=1 (it breaks the vault subprocess). Named wrappers are unaffected.
  • /v2/dm/sipAccounts is the create endpoint (not a list) — wrapped as the gated add-sipaccount. There's no list-sip-accounts in the v2 API.
  • Verification: token + sites/devices/accounts/rps-servers are [V]; writes + official-firmwares + the --site filter are [P] (plumbed per the n8n reference + spec, not lifecycle-exercised — no throwaway device to safely test writes on).

Reference

  • Vendor stack: reference_packetdial_oit_netsapiens. Portal login (web UI): infrastructure/voip-phones.sops.yaml. Per-client portal e.g. clients/valleywide/.
  • Endpoint map harvested from the dszp/n8n-nodes-yealinkymcs community node + Yealink "Open API for YMCS V4X" doc. Full /v2/dm/* + /v2/rps/* surface reachable via raw.