How to create and use virtual calendars
This page describes how to authenticate a virtual account and virtual calendar, and how to add an event to your new calendar.
Before you begin
Before you can create a virtual calendar, you must complete the following tasks:
- Sign up for a Nylas developer account.
- Create a Nylas application.
- Generate an API key for your application and save it somewhere secure.
Keep in mind
Keep the following information in mind as you work with virtual calendars:
- Virtual calendars use Custom authentication only in Nylas v3.
- Virtual calendars can interact with the Grants, Calendar, and Events endpoints only.
- Each virtual account can have up to 10 virtual calendars.
Authenticate a virtual account
Before you can create a virtual calendar, you need a virtual account to represent its "owner". Virtual accounts use Custom auth in v3. You can use the same auth process each time you need to create a new grant for a virtual calendar.
In Nylas v3, you can authenticate a virtual account using either API requests or the Nylas v3 SDKs. Follow these steps to authenticate a virtual account by making API requests:
-
Create a virtual calendar connector.
curl --request POST \
--url 'https://api.us.nylas.com/v3/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--data '{
"provider": "virtual-calendar",
"name": "nylas"
}' -
Create a grant for the virtual account.
curl --request POST \
--url 'https://api.us.nylas.com/v3/connect/custom' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--data '{
"provider": "virtual-calendar",
"settings": { "email": "devrel-virtual-calendar" },
"scope": [ "calendar" ]
}'✨ In Nylas v3, the
email
property associated with a virtual account does not need to be an email-formatted string.
Authenticate a virtual account with v3 SDKs
You can also authenticate a virtual account using either the Nylas v3 SDKs. Follow these steps to authenticate a virtual account using the Nylas v3 SDKs:
-
Create a virtual calendar connector.
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)
async function createConnector() {
try {
const connector = await nylas.connectors.create({
requestBody: {
name: 'nylas',
provider: 'virtual-calendar',
}
})
console.log('Connector created:', connector)
} catch (error) {
console.error('Error creating provider:', error)
}
}
createConnector()from dotenv import load_dotenv
load_dotenv()
import os
import sys
from nylas import Client
nylas = Client(
os.environ.get('NYLAS_API_KEY'),
os.environ.get('NYLAS_API_URI')
)
connector = nylas.connectors.create(
request_body={
"name": 'nylas',
"provider": "virtual-calendar"
}
)
print(connector)require 'nylas'
nylas = Nylas::Client.new(api_key: '<NYLAS_API_KEY>')
request_body = {
name: 'Nylas',
provider: 'virtual-calendar'
}
begin
nylas.connectors.create(request_body: request_body)
rescue Exception => exception
puts exception
endimport com.nylas.NylasClient;
import com.nylas.models.*;
public class connector {
public static void main(String[] args) throws
NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
CreateConnectorRequest request =
new CreateConnectorRequest.VirtualCalendar();
Response<Connector> connectorResponse =
nylas.connectors().create(request);
System.out.println(connectorResponse);
}
}import com.nylas.NylasClient
import com.nylas.models.CreateConnectorRequest
fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(
apiKey = "<NYLAS_API_KEY>"
)
val request = CreateConnectorRequest.VirtualCalendar()
val connector = nylas.connectors().create(request)
print(connector.data)
} -
Create a grant for the virtual account.
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)
async function createVirtualCalendarGrant() {
try {
const response = await nylas.auth.grants.create({
requestBody: {
provider: 'virtual-calendar',
settings: {
email: 'devrel-virtual-calendar'
},
scope: ['calendar']
}
})
console.log('Grant created:', response)
} catch (error) {
console.error('Error creating grant:', error)
}
}
createVirtualCalendarGrant()from dotenv import load_dotenv
load_dotenv()
import os
import sys
from nylas import Client
nylas = Client(
os.environ.get('NYLAS_API_KEY'),
os.environ.get('NYLAS_API_URI')
)
grant_id = nylas.auth.custom_authentication(
request_body={
"provider": "virtual-calendar",
"settings": {
"email": 'devrel-virtual-calendar',
},
"scope": ['calendar']
}
)
print(grant_id)# frozen_string_literal: true
require 'nylas'
require 'sinatra'
set :show_exceptions, :after_handler
error 404 do
'No authorization code returned from Nylas'
end
error 500 do
'Failed to exchange authorization code for token'
end
nylas = Nylas::Client.new(api_key: '<NYLAS_API_KEY>')
get '/nylas/auth' do
request_body = {
provider: 'virtual-calendar',
settings: {
email: "nylas-virtual-calendar"
}
}
response = nylas.auth.custom_authentication(request_body)
"#{response}"
endimport java.util.*;
import static spark.Spark.*;
import com.nylas.NylasClient;
import com.nylas.models.*;
public class AuthRequest {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
get("/nylas/auth", (request, response) -> {
Map<String, String> settings = new HashMap<>();
settings.put("email", "nylas-virtual-calendar");
List<String> scopes = new ArrayList<>();
scopes.add("openid");
CreateGrantRequest requestBody = new CreateGrantRequest.
Builder(AuthProvider.VIRTUAL_CALENDAR, settings).
scopes(scopes).state("xyz").build();
Response<Grant> authResponse = nylas.auth().customAuthentication(requestBody);
return "%s".formatted(authResponse);
});
}
}import com.nylas.NylasClient
import com.nylas.models.*
import spark.kotlin.Http
import spark.kotlin.ignite
fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
val http: Http = ignite()
http.get("/nylas/auth") {
val settings = mapOf("email" to "nylas-virtual-calendar")
val scopes = listOf("openapi")
val requestBody = CreateGrantRequest.
Builder(AuthProvider.VIRTUAL_CALENDAR, settings).
scopes(scopes).
state("xyz").
build()
var authResponse : Response<Grant>
nylas.auth().customAuthentication(requestBody).also { authResponse = it }
authResponse
}
}✨ In Nylas v3, the
email
property associated with a virtual account does not need to be an email-formatted string.
After you create a virtual account you can see it on the Grants page of the Nylas v3 Dashboard.
Create a virtual calendar
Now that you have a virtual account in Nylas, you can create a virtual calendar for the Connected Account or grant.
To create a virtual calendar, make a Create Calendar request or use the v3 SDKs.
curl --request POST \
--url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/calendars' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--data '{
"name": "Nylas DevRel",
"description": "Nylas Developer Relations"
}'
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)
async function createVirualCalendar() {
try {
const calendar = await nylas.calendars.create({
identifier: process.env.VIRTUAL_CALENDAR_GRANT_ID,
requestBody: {
name: 'Nylas DevRel',
description: 'Nylas Developer Relations',
}
})
console.log('Virtual Calendar:', calendar)
} catch (error) {
console.error('Error to create virtual calendar:', error)
}
}
createVirualCalendar()
from dotenv import load_dotenv
load_dotenv()
import os
import sys
from nylas import Client
nylas = Client(
os.environ.get('NYLAS_API_KEY'),
os.environ.get('NYLAS_API_URI')
)
grant_id = os.environ.get("VIRTUAL_CALENDAR_GRANT_ID")
calendar = nylas.calendars.create(
grant_id,
request_body={
"name": 'Nylas DevRel',
"description": 'Nylas Developer Relations'
}
)
print(calendar)
require 'nylas'
nylas = Nylas::Client.new(api_key: '<NYLAS_API_KEY>')
request_body = {
"name": "Nylas DevRel",
"description": "Nylas Developer Relations",
"timezone": "America/Toronto"
}
begin
calendars, _request_ids = nylas.calendars.create(
identifier: '<VIRTUAL_CALENDAR_ID>',
request_body: request_body)
puts calendars
rescue Exception => exception
puts exception
end
import com.nylas.NylasClient;
import com.nylas.models.*;
import java.util.HashMap;
public class CreateVirtualCalendar {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
CreateCalendarRequest requestBody = new CreateCalendarRequest(
"Nylas DevRel",
"Nylas Developer Relations",
"Nylas Headquarters",
"America/Toronto",
new HashMap<String, String>());
try {
Response<Calendar> calendar = nylas.calendars().create(
"<VIRTUAL_CALENDAR_GRANT_ID>",
requestBody);
System.out.println(calendar);
} catch(Exception e) {
System.out.printf(" %s%n", e);
}
}
}
import com.nylas.NylasClient
import com.nylas.models.*
fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
val requestBody = CreateCalendarRequest(
"Nylas DevRel",
"Nylas Developer Relations",
"Nylas Headquarters",
"America/Toronto",
mapOf<String, String>()
)
val calendar: Response<Calendar> = nylas.calendars().create(
"<VIRTUAL_CALENDAR_GRANT_ID>",
requestBody)
print(calendar.data)
}
Create an event on a virtual calendar
Now that you have both a virtual account and a virtual calendar associated with it, you can start creating events.
⚠️ Virtual calendars do not send invitations to event participants.
To create an event on your virtual calendar, make a Create Event request or use the v3 SDKs.
curl --request POST \
--url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events?calendar_id=<CALENDAR_ID>¬ify_participants=true' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--data '{
"when": {
"start_time": 1704302073,
"end_time": 1704305673
},
"title": "Build With Nylas"
}'
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)
async function createAnEvent() {
try {
const event = await nylas.events.create({
identifier: process.env.VIRTUAL_CALENDAR_GRANT_ID,
requestBody: {
title: 'Build With Nylas',
when: {
startTime: now,
endTime: now + 3600,
}
},
queryParams: {
calendarId: process.env.VIRTUAL_CALENDAR_ID,
},
})
console.log('Event:', event)
} catch (error) {
console.error('Error creating event:', error)
}
}
createAnEvent()
from dotenv import load_dotenv
load_dotenv()
import os
import sys
from nylas import Client
nylas = Client(
os.environ.get('NYLAS_API_KEY'),
os.environ.get('NYLAS_API_URI')
)
grant_id = os.environ.get("VIRTUAL_CALENDAR_GRANT_ID")
calendar_id = os.environ.get("VIRTUAL_CALENDAR_ID")
events = nylas.events.create(
grant_id,
request_body={
"title": 'Build With Nylas',
"when": {
"start_time": 1609372800,
"end_time": 1609376400
},
},
query_params={
calendar_id
}
)
print(events)
require 'nylas'
nylas = Nylas::Client.new(api_key: '<NYLAS_API_KEY>')
query_params = {
calendar_id: '<VIRTUAL_CALENDAR_ID>'
}
start_time = Time.now.to_i
end_time = start_time + 3600
request_body = {
when: {
start_time: start_time,
end_time: end_time
},
title: "Build With Nylas",
}
events, _request_ids = nylas.events.create(
identifier: '<VIRTUAL_CALENDAR_GRANT_ID>',
query_params: query_params,
request_body: request_body)
if _request_ids != ""
puts events[:id]
puts events[:title]
puts "Event created successfully"
else
puts "There was an error creating the event"
end
import com.nylas.NylasClient;
import com.nylas.models.*;
public class CreateVirtualEvent {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
CreateEventRequest.When.Timespan timespan = new CreateEventRequest.When.Timespan.
Builder(Math.toIntExact("<START_TIME>"),
Math.toIntExact("<END_TIME>")).
build();
CreateEventRequest request = new CreateEventRequest.Builder(timespan).
title("Build With Nylas").
build();
CreateEventQueryParams queryParams = new CreateEventQueryParams.Builder("<VIRTUAL_CALENDAR_ID>").build();
Response<Event> event = nylas.events().create(
"<VIRTUAL_CALENDAR_GRANT_ID",
request,
queryParams);
System.out.println(event);
}
}
import com.nylas.NylasClient
import com.nylas.models.*
fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
val eventWhenObj: CreateEventRequest.When = CreateEventRequest.When.Timespan(<START_TIME>, <END_TIME>)
val eventRequest: CreateEventRequest = CreateEventRequest.Builder(eventWhenObj).
title("Nylas DevRel").
description("Nylas Developer Relations").
location("Nylas Headquarters").
build()
val eventQueryParams: CreateEventQueryParams = CreateEventQueryParams("<VIRTUAL_CALENDAR_ID>")
val event: Response<Event> = nylas.events().create(
"<VIRTUAL_CALENDAR_GRANT_ID>",
eventRequest,
eventQueryParams)
print(event.data)
}
Nylas creates the event and adds it to the virtual calendar.