Sales and support teams run most of their calls on Zoom, and the transcript is where the value sits: objections, commitments, and the action items a rep forgot to write down. Zoom’s own cloud recording transcribes after the call ends and lives in a per-account vault, which is hard to pipe into your own systems. With Notetaker you send a bot to the Zoom join URL, and you get back a speaker-labelled transcript and an MP4 recording through one API.
This recipe covers sending the bot, pulling the results, and the Zoom-specific behavior you’ll hit in production. If you’ve evaluated recall.ai for the same job, Notetaker covers Zoom, Google Meet, and Microsoft Teams behind the same grant-based API.
Send a Notetaker bot to a Zoom meeting
Section titled “Send a Notetaker bot to a Zoom meeting”Send a bot to a Zoom call with a POST /v3/grants/{grant_id}/notetakers request where meeting_link is the Zoom join URL. Set transcription to true so Notetaker returns a speaker-labelled transcript. The bot joins immediately when you omit join_time, or at a scheduled Unix timestamp when you pass one.
The request below records audio and video, transcribes the call, and leaves after silence. The leave_after_silence_seconds field accepts a value between 10 and 3,600 seconds; the example uses 360 so the bot drops off six minutes after the room goes quiet. The API supports Zoom, Google Meet, and Teams, so the same body works across all three.
curl --request POST \ --url "https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/notetakers" \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json' \ --data '{ "join_time": 1732657774, "meeting_link": "https://meet.google.com/xyz-abcd-ijk", "meeting_settings": { "action_items": true, "action_items_settings": { "custom_instructions": "Only return the 5 most important action items." }, "audio_recording": true, "leave_after_silence_seconds": 360, "summary": true, "summary_settings": { "custom_instructions": "Return this summary in the MEDPIC sales methodology." }, "transcription": true, "transcription_settings": { "expected_languages": ["en", "es"], "fallback_language": "en" }, "video_recording": true }, "name": "Nylas Notetaker" }'import Nylas from "nylas";
const nylas = new Nylas({ apiKey: "<NYLAS_API_KEY>", apiUri: "<NYLAS_API_URI>",});
async function inviteNotetaker() { try { const notetaker = await nylas.notetakers.create({ identifier: "<NYLAS_GRANT_ID>", requestBody: { meetingLink: "https://meet.google.com/abc-defg-hij", name: "Nylas Notetaker", meetingSettings: { videoRecording: true, audioRecording: true, transcription: true, }, }, });
console.log("Notetaker:", notetaker); } catch (error) { console.error("Error inviting notetaker:", error); }}
inviteNotetaker();from nylas import Client
nylas = Client( "<NYLAS_API_KEY>", "<NYLAS_API_URI>",)
notetaker = nylas.notetakers.invite( request_body={ "meeting_link": "https://meet.google.com/abc-defg-hij", "name": "Nylas Notetaker", "meeting_settings": { "video_recording": True, "audio_recording": True, "transcription": True, }, }, identifier="<NYLAS_GRANT_ID>",)
print("Invited notetaker:", notetaker)For Zoom, set meeting_link to the full join URL (it starts with https://zoom.us/j/ or a vanity domain) including the ?pwd= passcode. For a deeper walkthrough of every meeting_settings field, see the Notetaker API guide.
Get the transcript and recording
Section titled “Get the transcript and recording”Fetch the results with a GET /v3/grants/{grant_id}/notetakers/{notetaker_id}/media request. The response returns a transcript object (a JSON file with speaker labels and millisecond timing) and a recording object (an MP4 at 1280x720), each with its own download URL. The endpoint only returns media once processing finishes, which takes a few minutes after the bot leaves.
Each download URL carries a ttl of 3,600 seconds, so the link expires one hour after you generate it. The recording object also reports duration in seconds and size in bytes. Call the endpoint again any time to mint fresh URLs; it’s read-only and idempotent.
curl --request GET \ --url "https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/notetakers/<NOTETAKER_ID>/media" \ --header 'Accept: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>'{ "request_id": "5fa64c92-e840-4357-86b9-2aa364d35b88", "data": { "action_items": { "created_at": 1703088000, "expires_at": 1704297600, "name": "meeting_action_items.json", "size": 289, "ttl": 3600, "type": "application/json", "url": "https://storage.googleapis.com/nylas-notetaker-uc1-prod-notetaker/..." }, "recording": { "created_at": 1703088000, "duration": 1800, "expires_at": 1704297600, "name": "meeting_recording.mp4", "size": 52428800, "ttl": 3600, "type": "video/mp4", "url": "https://storage.googleapis.com/nylas-notetaker-uc1-prod-notetaker/..." }, "summary": { "created_at": 1703088000, "expires_at": 1704297600, "name": "meeting_summary.json", "size": 437, "ttl": 3600, "type": "application/json", "url": "https://storage.googleapis.com/nylas-notetaker-uc1-prod-notetaker/..." }, "thumbnail": { "created_at": 1703088000, "expires_at": 1704297600, "name": "thumbnail.png", "size": 437, "ttl": 3600, "type": "image/png", "url": "https://storage.googleapis.com/nylas-notetaker-uc1-prod-notetaker/..." }, "transcript": { "created_at": 1703088000, "expires_at": 1704297600, "name": "transcript.json", "size": 10240, "ttl": 3600, "type": "application/json", "url": "https://storage.googleapis.com/nylas-notetaker-uc1-prod-notetaker/..." } }}Download the files to your own storage before the URLs expire. Nylas keeps media for a maximum of 14 days, so don’t treat these links as permanent. For the full retention and download model, see Get a transcript and recording.
Transcribe automatically with webhooks
Section titled “Transcribe automatically with webhooks”Polling the media endpoint wastes requests when you don’t know when processing finishes. Subscribe to the notetaker.media webhook trigger instead, and Nylas calls your server the moment the transcript and recording are ready. The payload carries the same media URLs, each valid for 3,600 seconds.
Wire this into a download pipeline so a Zoom call becomes a stored transcript with no manual step. For the end-to-end flow, including signature verification and a sample handler, see the Notetaker webhooks recipe. The same notetaker.media trigger fires for Google Meet and Teams, so one handler covers every provider.
Things to know about Zoom meetings
Section titled “Things to know about Zoom meetings”Zoom hosts more than 300 million daily meeting participants, and a few platform behaviors affect every bot you send. The bot joins as an unauthenticated guest, so the host’s meeting policies decide whether it gets in. Plan for the waiting room and consent prompts before you ship.
A Zoom join URL looks like https://zoom.us/j/1234567890?pwd=aBcD1234. The numeric path segment is the meeting ID and the pwd query parameter is the embedded passcode. Pass the entire URL as meeting_link. If you strip the pwd value, the bot can’t authenticate into the room and the join fails.
A few things to watch for:
- Waiting room admission. When the host enables the waiting room, someone has to admit the bot. If nobody admits it within 10 minutes of the join time, the attempt times out and Nylas sends a
notetaker.meeting_statenotification withstatusset tofailed_entry. - Recording consent. A few minutes after joining, the bot posts a chat message telling participants the meeting is being recorded and transcribed. Collecting consent remains the host’s responsibility, and some organizations enforce a consent disclaimer through account settings.
- Authentication policies. Hosts can require that only signed-in or same-account users join. Because the bot is always an unauthenticated guest, those meetings reject it. Loosen the policy or admit the bot manually from the waiting room.
- Passcode placement. Embedding the passcode in the link (
?pwd=) is the reliable path. A passcode that isn’t in the URL can’t be supplied separately to the bot.
For the host-side settings that govern these behaviors, see the Zoom support documentation. Don’t hardcode assumptions about a single account; meeting policies vary by Zoom plan and admin configuration.
What’s next
Section titled “What’s next”- Notetaker API guide for every
meeting_settingsfield and bot lifecycle state - Get a transcript and recording for the full media retention and download model
- Transcribe a Google Meet meeting to run the same flow on Google Meet
- Using Nylas Notetaker for calendar sync, silence detection, and language hints