@kody/zoom
README.md
283 lines · 11.8 KB · Markdown@kody/zoom
Official Zoom wordmark (Simple Icons path from Zoom brand) in white on Zoom Blue #0B5CFF. Paths are unmodified. Zoom® is a trademark of Zoom Communications, Inc. This package is not affiliated with or endorsed by Zoom.
Intent
Reusable Zoom REST helpers for Kody agents. One package covers bring-your-own user OAuth applications and Server-to-Server OAuth secrets for users, meetings, recordings, and webinars. Multi-account routing is zoom / zoom-* via integrationName or account — there are no hard-coded personal aliases or meeting IDs.
This listing is meant to be forked. After you fork, connect your Zoom account. Do not treat the live @kody/zoom package as a shared meeting calendar.
Share this listing at https://kody.codes/@kody/zoom
What this package does
After you connect Zoom to Kody, agents can:
- Call the Zoom REST API with the correct saved credential (
request,paginate) - Verify which Zoom identity will perform an action (
get-current-user) - List and fetch users, meetings, recordings, and webinars
- Preview or apply meeting and webinar writes (
meetings/create,meetings/update,meetings/delete, and the matching webinar helpers)
It does not register a Zoom Marketplace app for you. There is no built-in Zoom platform app.
Auth lanes
| Lane | Credential | When to use |
|---|---|---|
| A. User OAuth | Saved integration named zoom (or zoom-* via account / integrationName) | Refreshable user OAuth. me works for the connected user. |
| B. Server-to-Server OAuth | User secrets zoomAccountId, zoomClientId, zoomS2sClientSecret | Account-level automations without a user consent screen. Pass auth: 's2s'. |
Required hosts: api.zoom.us and zoom.us. Approve them in the account secrets UI.
auth: 's2s' or any S2S secret override selects the Server-to-Server lane and ignores integrationName.
Lane A: bring-your-own OAuth application
There is no built-in Zoom OAuth app. Create a General app, then connect it.
- Open Zoom Marketplace → Build an app and create a General OAuth app.
- Set the Redirect URL for OAuth exactly to
https://kody.codes/connect/oauth(self-hosted Kody uses that deployment origin plus/connect/oauth). - Add the user-level scopes listed below (or the subset you need).
- Copy the client ID and client secret. Never paste the secret into chat.
- Connect:
https://kody.codes/connect/oauth?provider=zoom&authorizeUrl=https%3A%2F%2Fzoom.us%2Foauth%2Fauthorize&tokenUrl=https%3A%2F%2Fzoom.us%2Foauth%2Ftoken&flow=confidential&scopes=user%3Aread%3Auser%20meeting%3Aread%3Alist_meetings%20meeting%3Aread%3Ameeting%20meeting%3Awrite%3Ameeting%20meeting%3Aupdate%3Ameeting%20meeting%3Adelete%3Ameeting%20cloud_recording%3Aread%3Alist_user_recordings%20cloud_recording%3Aread%3Arecording%20webinar%3Aread%3Alist_webinars%20webinar%3Aread%3Awebinar%20webinar%3Awrite%3Awebinar%20webinar%3Aupdate%3Awebinar%20webinar%3Adelete%3Awebinar&allowedHosts=api.zoom.us%2Czoom.us&apiBaseUrl=https%3A%2F%2Fapi.zoom.us%2Fv2&dashboardUrl=https%3A%2F%2Fmarketplace.zoom.us%2Fdevelop%2FcreateDecoded: authorize https://zoom.us/oauth/authorize, token https://zoom.us/oauth/token, flow=confidential, hosts api.zoom.us and zoom.us. Paste the client ID and secret into the Kody setup form, then authorize Zoom.
Default helper input: omit integrationName, account, and auth. The package uses OAuth integration zoom.
Reconnect later at https://kody.codes/connect/oauth?provider=zoom (or ?provider=<your-integration-name>).
Lane B: Server-to-Server OAuth secrets
- Open Zoom Marketplace → Build an app and create a Server-to-Server OAuth app.
- Add the admin scopes listed below, then Activate the app.
- Copy the account ID, client ID, and client secret from the app credentials page. Never paste them into chat.
- Save each secret and approve hosts
api.zoom.usandzoom.us:
https://kody.codes/account/secrets/new?name=zoomAccountId&description=Zoom%20Server-to-Server%20account%20ID&allowedHosts=api.zoom.us%2Czoom.us&scope=userhttps://kody.codes/account/secrets/new?name=zoomClientId&description=Zoom%20Server-to-Server%20client%20ID&allowedHosts=api.zoom.us%2Czoom.us&scope=userhttps://kody.codes/account/secrets/new?name=zoomS2sClientSecret&description=Zoom%20Server-to-Server%20client%20secret&allowedHosts=api.zoom.us%2Czoom.us&scope=userzoomS2sClientSecret is intentional. /connect/oauth may already store an OAuth app client secret as zoomClientSecret — do not reuse that name for Server-to-Server.
- Call helpers with
auth: 's2s'.
Helpers mint a one-hour access token via grant_type=account_credentials and never return or log that token.
Scopes
User-level (Lane A):
| Scope | Needed for |
|---|---|
user:read:user | ./get-current-user, ./users/get |
meeting:read:list_meetings / meeting:read:meeting | Meeting reads |
meeting:write:meeting / meeting:update:meeting / meeting:delete:meeting | Meeting writes |
cloud_recording:read:list_user_recordings / cloud_recording:read:recording | Recording reads |
webinar:read:list_webinars / webinar:read:webinar | Webinar reads |
webinar:write:webinar / webinar:update:webinar / webinar:delete:webinar | Webinar writes |
Server-to-Server (Lane B) uses the matching :admin scopes, plus user:read:list_users:admin for ./users/list.
If Zoom returns 401/403, helpers throw a message that names the next setup URL.
Multiple accounts
Every export accepts:
integrationName— exact saved OAuth name (zoom-work)account—work→zoom-work/zoomAccountId-work/ …;zoom-workused as-is; omitted →zoomauth—'oauth'or's2s'accountIdSecret/clientIdSecret/clientSecretSecret— S2S secret overrides
Connect extra OAuth accounts by changing provider in the connect URL:
https://kody.codes/connect/oauth?provider=zoom-work&authorizeUrl=https%3A%2F%2Fzoom.us%2Foauth%2Fauthorize&tokenUrl=https%3A%2F%2Fzoom.us%2Foauth%2Ftoken&flow=confidential&scopes=user%3Aread%3Auser%20meeting%3Aread%3Alist_meetings%20meeting%3Aread%3Ameeting&allowedHosts=api.zoom.us%2Czoom.us&apiBaseUrl=https%3A%2F%2Fapi.zoom.us%2Fv2Do not hard-code a personal meeting ID or alias in forks of this package. Pass meetingId, webinarId, or a zoom.us/j/{id} / zoom.us/w/{id} URL at call time.
import getZoomCurrentUser from 'kody:@kody/zoom/get-current-user'
export default async function main() {
return await getZoomCurrentUser({ integrationName: 'zoom-work' })
}Mutations and dryRun
Create, update, and delete for meetings and webinars — and REST methods other than GET / HEAD / OPTIONS — require:
dryRun: true— validate and return a preview; Zoom is not writtenconfirm: true— perform the live write
import createZoomMeeting from 'kody:@kody/zoom/meetings/create'
export default async function main() {
return await createZoomMeeting({
topic: 'Example meeting',
type: 2,
start_time: '2030-01-15T17:00:00',
duration: 30,
timezone: 'UTC',
dryRun: true,
})
}Do not create a live meeting unless the user confirmed the exact topic, time, and host.
Jobs
upcoming-meetings is declared and disabled by default. It lists upcoming meetings for me when an operator enables it after a successful smoke test.
Smoke tests
Run these from execute after connect (or after S2S host approval). Prefer a static kody:@kody/zoom import for the package overview.
Package overview (no credentials)
import describeZoom from 'kody:@kody/zoom'
export default async function main() {
return await describeZoom()
}A successful response includes publicUrl: 'https://kody.codes/@kody/zoom', the OAuth connect URL, and the three S2S secret URLs.
Mutation preview (no credentials)
import createZoomMeeting from 'kody:@kody/zoom/meetings/create'
export default async function main() {
return await createZoomMeeting({
topic: 'Example meeting',
type: 2,
start_time: '2030-01-15T17:00:00',
duration: 30,
timezone: 'UTC',
dryRun: true,
})
}Identity (Lane A — OAuth)
import getZoomCurrentUser from 'kody:@kody/zoom/get-current-user'
export default async function main() {
return await getZoomCurrentUser()
}Identity (Lane B — Server-to-Server)
import getZoomCurrentUser from 'kody:@kody/zoom/get-current-user'
export default async function main() {
return await getZoomCurrentUser({ auth: 's2s' })
}Exports
kody:@kody/zoom— package overview and setup URLskody:@kody/zoom/accounts— OAuth vs Server-to-Server lane guidancekody:@kody/zoom/get-current-user— identity smoke testkody:@kody/zoom/paginate—next_page_tokenhelperkody:@kody/zoom/request— REST request helperkody:@kody/zoom/types— shared TypeScript typeskody:@kody/zoom/smoke-test— local checks; passlive: truefor/users/mekody:@kody/zoom/users/list— list account userskody:@kody/zoom/users/get— fetch one userkody:@kody/zoom/meetings/list— list meetingskody:@kody/zoom/meetings/get— fetch one meetingkody:@kody/zoom/meetings/create— create a meeting (dryRun/confirm)kody:@kody/zoom/meetings/update— update a meeting (dryRun/confirm)kody:@kody/zoom/meetings/delete— delete a meeting (dryRun/confirm)kody:@kody/zoom/recordings/list— list user recordingskody:@kody/zoom/recordings/get— fetch meeting recordingskody:@kody/zoom/webinars/list— list webinarskody:@kody/zoom/webinars/get— fetch one webinarkody:@kody/zoom/webinars/create— create a webinar (dryRun/confirm)kody:@kody/zoom/webinars/update— update a webinar (dryRun/confirm)kody:@kody/zoom/webinars/delete— delete a webinar (dryRun/confirm)
Meeting locators: { meetingId }, { meeting_id }, { id }, or { meetingUrl: 'https://zoom.us/j/11111111111' }. Webinar locators accept webinarId or https://zoom.us/w/{id}.
Examples
Upcoming meetings (default OAuth zoom):
import listZoomMeetings from 'kody:@kody/zoom/meetings/list'
export default async function main() {
return await listZoomMeetings({ type: 'upcoming', page_size: 10 })
}Recordings for a date window on a second account:
import listZoomRecordings from 'kody:@kody/zoom/recordings/list'
export default async function main() {
return await listZoomRecordings({
from: '2030-01-01',
to: '2030-01-31',
account: 'work',
})
}Unwrapped REST:
import zoomRequest from 'kody:@kody/zoom/request'
export default async function main() {
return await zoomRequest({
path: '/users/me/meetings',
query: { type: 'upcoming', page_size: 5 },
})
}Troubleshooting
The redirect URI mismatch: callback must be exactlyhttps://kody.codes/connect/oauth.401 Invalid access tokenwith OAuth: reconnect athttps://kody.codes/connect/oauth?provider=zoom.401on Server-to-Server: the app must be activated; all three secrets must belong to the same app; approvezoom.usandapi.zoom.us.400/ missing scope on webinars: the host needs a webinar license and the matching webinar scopes.- Writes rejected with a mutation-guard error: pass
dryRun: trueorconfirm: true.