Skip to content

How to auto-log meeting notes to your CRM

Meeting notes are the most valuable artifact a sales team produces. They capture what a prospect said in their own words, what objections came up, and what everyone agreed to do next. But they almost never make it into the CRM. Reps finish a call, jump straight into the next one, and by the end of the day, whatever happened in that 10 AM demo is a blur. The CRM record stays blank, pipeline reviews rely on memory, and managers have no visibility into what was actually discussed.

This tutorial builds a webhook-driven pipeline that fixes that problem. Nylas Notetaker records and transcribes your meetings, then your webhook handler picks up the summary and action items, matches them to the right CRM record, and pushes everything in automatically. No manual entry, no lost context.

The pipeline follows this flow:

  1. Notetaker joins a meeting (either manually triggered or auto-scheduled through calendar sync) and records the conversation.
  2. Nylas processes the recording after the meeting ends, generating a transcript, summary, and action items.
  3. Nylas fires a notetaker.media webhook when the processed files are ready to download.
  4. Your webhook handler receives the notification, downloads the summary and action items, and fetches the calendar event to identify participants.
  5. Your handler matches participant emails against contacts or deals in your CRM.
  6. Your handler pushes a structured meeting record to your CRM’s API with the summary, action items, and transcript attached.

This approach works with any CRM that exposes a REST API: Salesforce, HubSpot, Pipedrive, Close, or a custom internal system. The examples use generic REST endpoints so you can adapt them to your specific CRM.

Make sure you have the following before starting this tutorial:

  • A Nylas account with an active application
  • A valid API key from your Nylas Dashboard
  • At least one connected grant (an authenticated user account) for the provider you want to work with
  • Node.js 18+ or Python 3.8+ installed (depending on which code samples you follow)

New to Nylas? Start with the quickstart guide to set up your app and connect a test account before continuing here.

You also need:

  • A connected grant with calendar access so you can look up event participants
  • Notetaker enabled on your Nylas plan (check your Nylas Dashboard to confirm)
  • A CRM (or any external system) with a REST API you can push meeting records to
  • A publicly accessible HTTPS endpoint to receive webhook notifications

Nylas blocks requests to ngrok URLs. Use VS Code port forwarding or Hookdeck to expose your local server during development.

Subscribe to the notetaker.media trigger so Nylas notifies your endpoint when a recording has been processed and the summary, action items, and transcript are available for download. You can also add notetaker.meeting_state if you want to track when Notetaker joins and leaves calls.

Nylas responds with the webhook ID and a webhook_secret you use to verify incoming notifications. Store that secret securely. After creating the webhook, Nylas sends a verification GET request with a challenge query parameter to your endpoint. Your server must return the exact challenge value in a 200 OK response. See Using webhooks with Nylas for the full verification flow.

Your endpoint must respond within 10 seconds. If verification fails, Nylas marks the webhook as inactive. Make sure your server is running and accessible before creating the webhook.

When Notetaker finishes processing a recording, Nylas sends a notetaker.media webhook. The payload contains the Notetaker ID and URLs for each available media file. Here is what it looks like:

Your handler needs to verify the state is available, download the summary and action items, look up the calendar event for participant data, and then push the meeting record to your CRM. Here is a complete Node.js Express handler:

Media URLs expire after 60 minutes. Download the summary, action items, and transcript as soon as you receive the webhook. If you need to access them later, make a GET /v3/grants/<NYLAS_GRANT_ID>/notetakers/<NOTETAKER_ID>/media request to get fresh URLs.

The calendar event’s participants array is your key to linking a meeting to the right CRM record. Each participant has an email and (usually) a name. The matching strategy depends on your CRM’s data model, but most CRMs let you search contacts by email address.

Here is a practical approach:

  1. Extract participant emails from the calendar event.
  2. Filter out internal emails (your own domain) so you only match against external contacts.
  3. Look up each external email in your CRM’s contacts endpoint.
  4. If a contact matches, pull the associated deal or opportunity record.
  5. Attach the meeting notes to both the contact and the deal.

Not every participant will match a CRM contact. That is expected. Log the unmatched emails so your team can decide whether to create new contacts from them. Some teams auto-create contacts for unknown participants; others prefer a manual review step.

A few things to consider when designing your matching logic:

  • Email aliases can cause missed matches. A contact might be stored as [email protected] in your CRM but attend from [email protected]. Fuzzy matching on domain plus first name can help, but it introduces false positives. Start with exact email matching and refine from there.
  • Multiple contacts from the same company are common in enterprise deals. Match all of them so the meeting record appears on every relevant contact timeline.
  • Internal-only meetings (where all participants share your domain) probably should not create CRM records. Filter these out early to avoid cluttering your CRM with standup notes.

Once you have matched participants to CRM records, format the meeting data and push it. Most CRMs support a “meeting” or “activity” record type that you can associate with contacts and deals. Adapt the schema below to match your CRM’s API.

Store the Notetaker ID as a foreign key in your CRM. This gives you a deduplication key: if you receive the same notetaker.media webhook twice (Nylas guarantees at-least-once delivery), check whether a CRM record with that external_notetaker_id already exists before creating a duplicate.

Manually sending Notetaker to each meeting works for testing, but the real value comes from full automation. Nylas supports calendar sync rules that automatically schedule a Notetaker for meetings that match your criteria. Combined with the webhook handler you built above, this creates a fully hands-free pipeline.

For example, to have Notetaker auto-join all external meetings (where at least one participant is outside your organization):

With calendar sync enabled, Nylas evaluates every event on the calendar against your rules. When a meeting qualifies, it automatically schedules a Notetaker. When the meeting ends, your webhook handler picks up the processed media and logs it to your CRM. The entire chain runs without anyone doing anything.

You can customize the rules further. Use "event_selection": ["internal", "external"] to record all meetings, or set "participants_gte": 3 to skip one-on-one calls. See the calendar sync documentation for the full set of rule options.

Here are practical details to keep in mind as you build and run this pipeline in production.

The URLs in the notetaker.media webhook payload are signed and expire after 60 minutes. Always download the files immediately inside your webhook handler. If you miss the window, you can request fresh URLs by calling GET /v3/grants/<NYLAS_GRANT_ID>/notetakers/<NOTETAKER_ID>/media, but the underlying files are only retained for 14 days. After that, they are permanently deleted. If your CRM needs to store meeting recordings or transcripts long-term, download them to your own infrastructure as part of the webhook processing flow.

Notetaker does not deliver media instantly after a meeting ends. Nylas needs time to process the recording, generate the transcript, and produce the summary and action items. Expect a delay of a few minutes for short meetings and longer for recordings that run over an hour. Your CRM records will not update in real time, but they will consistently populate well before any human would have gotten around to writing notes manually.

Notetaker joins meetings as a non-signed-in user. If the meeting has a lobby or waiting room enabled, someone in the meeting needs to admit the bot manually. If nobody admits it within 10 minutes of the scheduled join time, Notetaker times out and reports a failed_entry state. For fully automated workflows, configure your meeting provider to bypass the lobby for Notetaker, or instruct meeting organizers to admit the bot promptly.

This is the most common failure mode in production. Consider subscribing to notetaker.meeting_state webhooks and alerting your team when a Notetaker gets stuck in the lobby.

Nylas typically returns speaker-labelled transcripts with timestamps and speaker names. In rare cases, it may return a raw text transcript without speaker attribution. Your code should handle both formats by checking the type field in the transcript JSON: it will be either "speaker_labelled" or "raw". See Handling Notetaker media files for details on both formats.

Nylas guarantees at-least-once delivery for webhooks, which means you may receive the same notetaker.media notification more than once. Before creating a CRM record, check whether one already exists with the same Notetaker ID. Use the external_notetaker_id field from the examples above as your deduplication key. If the record already exists, update it instead of creating a duplicate.

By default, Notetaker leaves a meeting after 5 minutes of continuous silence. This prevents the bot from lingering in dead calls. You can adjust this threshold with leave_after_silence_seconds in your meeting settings (between 10 and 3600 seconds). Silence detection only activates after at least one participant has spoken, so the bot will not leave immediately on join if nobody has spoken yet.

The AI-generated summary and action items work best with clear, structured conversations. For unstructured calls, you can pass custom instructions to improve output quality:

{
"meeting_settings": {
"summary": true,
"summary_settings": {
"custom_instructions": "Focus on decisions made, objections raised, and next steps agreed upon."
},
"action_items": true,
"action_items_settings": {
"custom_instructions": "Assign each action item to the person responsible. Include deadlines if mentioned."
}
}
}

Custom instructions are limited to 1,500 characters each.