How to manage calendar availability with Nylas

9 min read

Key takeaways

This blog walks you through how to efficiently manage and display real-time calendar availability using the Nylas API.

  1. How to manage calendar availability: The Nylas API allows you to manage and display availability across multiple calendars in one unified, scalable system, reducing complexity and saving time.
  2. Comprehensive guide for all users: This guide offers both high-level concepts for product managers and detailed implementation steps for developers, making it accessible to a wide range of audiences.
  3. Use case versatility: This solution applies to various industries—such as healthcare, education, and recruitment—by supporting efficient availability management for providers, tutors, interviewers, and more.

By implementing the steps outlined in this blog, you can build a robust scheduling tool that enhances user experiences and streamlines operations.

Managing availability for scheduling on multiple calendars—whether for healthcare providers, tutors, interviewing or other professionals—can be complex and resource-intensive. This blog provides a comprehensive solution for efficiently querying and managing availability using the Nylas API. With real-world examples and code snippets, you’ll learn how to build a scalable, real-time availability scheduler tailored for your application.

This solution helps you efficiently expose calendar availability for tens, hundreds, or even thousands of accounts by integrating with the Nylas API. It provides a clear setup guide, from authentication to implementation, and includes both high-level concepts and practical steps with code examples. Whether you’re a product manager looking for feasibility insights or an engineer ready to build, this guide is for you.

What is an availability scheduler and how are they used?

An availability scheduler, or calendar, visually displays when a person or resource is available for meetings or appointments. It’s commonly used for managing resource allocation and booking online appointments, reservations, and events.

These calendars typically present days, weeks, or months in a grid format, with color coding to indicate availability. For example, green may represent an open time slot, while red shows a blocked period. Availability calendars help prevent scheduling conflicts, enhance time management, and simplify the scheduling process.

They are used for:

  • Appointment scheduling: Allows customers to self-book appointments directly on your platform, helping businesses reduce scheduling conflicts and manage bookings efficiently.
  • Business marketplaces: Helps online marketplaces manage available services or goods, keeping users engaged and enabling direct actions without leaving the platform.
  • Employee availability: Businesses can manage team schedules, assign tasks, and ensure adequate coverage while tracking work hours and streamlining payroll processes.
  • Group meetings: Simplifies scheduling group meetings by automatically aligning attendee availability and sending invites to avoid conflicts and minimize rescheduling.
  • Work events: For conferences or training sessions, they can help coordinate participant invitations, manage resource allocation, and reduce no-shows by scheduling events at optimal times.

How to manage calendar availability with Nylas: A step-by-step guide

1. Start an authorization request. Usually this is a button or link that the end user clicks.

Purpose: Allow users (e.g., healthcare providers, coaches, tutors) to connect their email accounts, enabling your app to fetch calendar data.

Code example:

import 'dotenv/config'
import express from 'express'
import Nylas from 'nylas'

const config = {
 clientId: process.env.NYLAS_CLIENT_ID,
 callbackUri: "http://localhost:3000/oauth/exchange",
 apiKey: process.env.NYLAS_API_KEY,
 apiUri: process.env.NYLAS_API_URI
}

const nylas = new Nylas({
 apiKey: config.apiKey,
 apiUri: config.apiUri
})

const app = express()
const port = 3000

// Route to initialize authentication
app.get('/nylas/auth', (req, res) => { 
 const authUrl = nylas.auth.urlForOAuth2({
   clientId: config.clientId,
   provider: 'google',
   redirectUri: config.callbackUri,
   loginHint: 'email_to_connect',
 })

 res.redirect(authUrl)
})

2. Fetch availability for connected accounts using the Nylas /availability endpoint.

Purpose: Surface available time slots for end-users in your application. 

  • Input: List of emails, time ranges, meeting duration.
  • Output: Calendar availability data for requested accounts.

Code example:

import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
 apiKey: process.env.NYLAS_API_KEY,
 apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

const email = process.env.EMAIL

async function getCalendarAvailability() {
  try {
    const calendar = await nylas.calendars.getAvailability({
      requestBody: {
        startTime: 1630435200,
        endTime: 1630521600,
        duration_minutes: 30,
        participants: [{email}] //if empty, Nylas uses the primary calendar id (participant email needs to be authenticated to your Nylas app)
      }
    })

    console.log('Calendar:', calendar)
  } catch (error) {
    console.error('Error to create calendar:', error)
  }
}

getCalendarAvailability()

Store the results in Redis or your cache of choice (be sure to structure your cache so it’s efficient for batch querying).

// Store availability data 
redisClient.set('[email protected]',JSON.stringify(availability); 
// Retrieve availability data 
redisClient.get('[email protected]', (err, data) => { const availability = JSON.parse(data); });

3. Subscribe to webhooks.

Purpose: Keep your application up-to-date with any changes. 

Register webhooks to monitor calendar changes:

import 'dotenv/config'
import Nylas, { WebhookTriggers } from "nylas"

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

const createWebhook = async () => {
  try {
    const webhook = await nylas.webhooks.create({
      requestBody: {
        triggerTypes: [WebhookTriggers.EventCreated, WebhookTriggers.EventUpdated, WebhookTriggers.EventDeleted],
        webhookUrl: process.env.WEBHOOK_CALLBACK_URL,
        description: "My first webhook",
        notificationEmailAddress: [process.env.NOTIFICATION_EMAIL],
      }
    })

    console.log("Webhook created:", webhook)
  } catch (error) {
    console.error("Error creating webhook:", error)
  }
}

createWebhook() 


/* Example output:
Webhook created: {
  requestId: '1',
  data: {
    id: '2',
    description: 'My first webhook',
    triggerTypes: [ 'event.created' ],
    webhookUrl: 'your-webhook-callback-url',
    webhookSecret: 'webhook-secret-to-store',
    status: 'active',
    notificationEmailAddresses: null,
    statusUpdatedAt: 1710964914,
    createdAt: 1710964914,
    updatedAt: 1710964914
  }
}
*/

4. Handle webhook notifications.

Purpose: Update cache in real-time.

Set up an Express route to process webhook payloads:

import "dotenv/config";
import express from "express";
import Nylas from "nylas";
import crypto from 'crypto';

const config = {
  clientId: process.env.NYLAS_CLIENT_ID,
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
};

const nylas = new Nylas({
  apiKey: config.apiKey,
  apiUri: config.apiUri, // "https://api.us.nylas.com" or "https://api.eu.nylas.com"
});

const app = express();
const port = 3000;

// start the server
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

// route to respond to Nylas webhook creation webhook with challenge parameter
app.get("/callback/nylas", (req, res) => {
  if (req.query.challenge) {
    console.log(`Received challenge code! - ${req.query.challenge}`);
    console.log(`Now returning challenge code! - ${req.query.challenge}`);
    
    // we need to enable the webhook by responding with the challenge parameter
    return res.send(req.query.challenge);
  }
});

// route to receive webhook events after creating webhook
app.post("/callback/nylas", (req, res) => {  
  const nylasSignature = 'x-nylas-signature';
  const hashAlgorithm = 'sha256'

  /* secret is storing the webhook secret in-memory for demo purposes
  TODO: Store the secret and retrieve as needed to verify the webhook signature
  */
  const webhookSecret = process.env.WEBHOOK_SECRET;
   
  console.log('==========Webhook log start==========');
  console.log(JSON.stringify(req.body.data));

  // Verify the webhook signature
  const signature = req.headers[nylasSignature];

  const digest = crypto
    .createHmac(hashAlgorithm, webhookSecret)
    .update(req.body.data)
    .digest('hex')

  const isValidWebhook = digest === nylasSignature
  console.log({isValidWebhook})
  console.log('==========Webhook log end==========\n');

  // Responding to Nylas is important to prevent the webhook from retrying
  return res.status(200).end();
});

Store the results in Redis or your cache of choice (be sure to structure your cache so it is efficient for batch querying, like above).

5. Batch query your cache to display calendar availability to your end-user.

Purpose: Efficiently query cache to serve many users’ availability at the same time.Use Redis’ mget command to retrieve multiple keys at once:

const queryBatchAvailabilityRedis = async (userIds, startTime, endTime) => {
    const pipeline = redisClient.pipeline();

    userIds.forEach(userId => pipeline.get(userId));
    const cacheResults = await pipeline.exec();

    const results = {};
    cacheResults.forEach(([err, data], index) => {
        const userId = userIds[index];
        if (err || !data) {
            results[userId] = [];
            return;
        }

        const availability = JSON.parse(data);
        results[userId] = availability.filter(slot => {
            const slotStart = new Date(slot.start).getTime();
            const slotEnd = new Date(slot.end).getTime();
            const queryStart = new Date(startTime).getTime();
            const queryEnd = new Date(endTime).getTime();

            return slotStart >= queryStart && slotEnd <= queryEnd;
        });
    });

    return results;
};

// Example Usage:
const userIds = ['[email protected]', '[email protected]', '[email protected]'];
const startTime = '2024-01-01T10:00:00Z';
const endTime = '2024-01-01T15:00:00Z';

queryBatchAvailabilityRedis(userIds, startTime, endTime).then(batchAvailability => {
    console.log(batchAvailability);
});

For large datasets:

Chunk the queries: If you’re querying hundreds of users, process them in chunks to avoid overwhelming memory or Redis pipelines.

const chunkArray = (array, size) => {
    const chunks = [];
    for (let i = 0; i < array.length; i += size) {
        chunks.push(array.slice(i, i + size));
    }
    return chunks;
};

const userChunks = chunkArray(userIds, 50); // Process 50 users at a time
for (const chunk of userChunks) {
    const results = await queryBatchAvailabilityRedis(chunk, startTime, endTime);
    console.log(results);
}

6. Book appointments.

Purpose: Offer in-app appointment booking.

  • Input: Subject, appointment time in unix format, participants, etc.
  • Output: Event payload and status code
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
  apiKey: process.env.NYLAS_API_KEY,
  apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)

const now = Math.floor(Date.now() / 1000) // Time in Unix timestamp format (in seconds)

async function createAnEvent() {
  try {
    const event = await nylas.events.create({
      identifier: process.env.NYLAS_GRANT_ID,
      requestBody: {
        title: 'Tutoring Session',
        when: {
          startTime: now,
          endTime: now + 3600,
        },
	  location:'Class Room E475',
	  conferencing: {CONFERENCING_DOCS},
	  participants: [{
  	email: "[email protected]",
	name: "Student Name"
  }]
      },
      queryParams: {
        calendarId: process.env.CALENDAR_ID,
      },
    })

    console.log('Event:', event);
  } catch (error) {
    console.error('Error creating event:', error)
  }
}

createAnEvent()

7. Update cache to remove free slot.

Purpose: Any booked time slots will not show as free once the cache is updated.

8. Monitor calendar availability.

Purpose: Accurately display available time slots to end users.

  • Regularly update the cache using Nylas webhooks
  • Serve availability queries directly from the cache to ensure low latency

Build smarter availability scheduling with Nylas

Managing calendar availability across multiple accounts doesn’t have to be overwhelming. With the Nylas API, you can streamline the process, whether you’re working with a handful of schedules or thousands. By following this guide, you’ve learned how to authenticate, query availability, and build a real-time availability scheduler tailored to your needs.

Whether you’re developing scheduling solutions for healthcare providers, tutors, or interviewers, the Nylas API offers the tools to build a robust, scalable solution with ease. Sign up for free and start building your availability scheduler today.

Related resources

How to build an email outreach tool with Nylas

Key takeaways By the end of this how-to guide, you’ll learn: You’ll understand the key…

How to combine Supabase Google Auth and Google App Permissions in a Next.js Application

Combine Next.js Supabase Google Auth with Nylas Auth lets you seamlessly access Email and Calendar data in your Next.js application. In this guide we’ll walk through configuring both providers, handling refresh tokens, and enabling advanced email and calendar features.

How to customize the Nylas Scheduler workflow with custom events

We’re excited to announce the launch of the Nylas Scheduler v3! Efficient scheduling is essential…