# Quickstart: Calendar and Events APIs

Source: https://developer.nylas.com/docs/v3/getting-started/calendar/

The Nylas Calendar API lets you schedule meetings with participants, check availability across calendars, and RSVP to events -- across Google Calendar, Outlook, Exchange, and iCloud through a single API. Instead of building separate integrations for each provider, you write your code once and Nylas handles the differences.

This quickstart walks you through the things developers actually build with the Calendar API: scheduling meetings, finding available times, and responding to invites.

## Before you begin

You need two things from Nylas to make API calls:

1. **An API key** -- authenticates your application. You’ll pass it as a Bearer token.
2. **A grant ID** -- identifies which user’s calendar to act on. You get one when you connect an account to Nylas.

If you don’t have these yet, follow one of the setup guides first:

- **[Get started with the CLI](/docs/v3/getting-started/cli/)** -- run `nylas init` to create an account, generate an API key, and connect a test account in one command.
- **[Get started with the Dashboard](/docs/v3/getting-started/dashboard/)** -- do the same steps through the web UI.

Then install the Nylas SDK for your language:

```bash [installSdk-Node.js]
npm install nylas
```

```bash
pip install nylas
```

```bash
gem install nylas
```

For Java and Kotlin, see the [Kotlin/Java SDK setup guide](/docs/v3/sdks/kotlin-java/).

> **Info:** 
> **You’ll need a calendar ID.** Every event belongs to a calendar. Most providers have a `primary` calendar -- use that for testing, or [list the user’s calendars](#list-a-users-calendars) to find the right one.

## Schedule a meeting with participants

The most common use case: create an event on a user’s calendar and invite participants. Nylas sends the invitations automatically. Replace `<NYLAS_GRANT_ID>`, `<NYLAS_API_KEY>`, and `<CALENDAR_ID>` with your values.

```bash
curl --request POST \
  --url ‘https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events?calendar_id=<CALENDAR_ID>’ \
  --header ‘Authorization: Bearer <NYLAS_API_KEY>’ \
  --header ‘Content-Type: application/json’ \
  --data ‘{
    "title": "Project kickoff",
    "description": "Review goals and assign workstreams",
    "when": {
      "start_time": 1735689600,
      "end_time": 1735693200,
      "start_timezone": "America/New_York",
      "end_timezone": "America/New_York"
    },
    "participants": [
      { "name": "Alice", "email": "alice@example.com" },
      { "name": "Bob", "email": "bob@example.com" }
    ],
    "location": "Conference Room B"
  }’
```

```js [createEvent-Node.js]


const nylas = new Nylas({ apiKey: process.env.NYLAS_API_KEY });

const now = Math.floor(Date.now() / 1000);

const event = await nylas.events.create({
  identifier: process.env.NYLAS_GRANT_ID,
  requestBody: {
    title: "Project kickoff",
    description: "Review goals and assign workstreams",
    when: {
      startTime: now + 3600,
      endTime: now + 7200,
    },
    participants: [
      { name: "Alice", email: "alice@example.com" },
      { name: "Bob", email: "bob@example.com" },
    ],
    location: "Conference Room B",
  },
  queryParams: {
    calendarId: "<CALENDAR_ID>",
  },
});

console.log("Created event:", event.data.id);
```

```python
from nylas import Client

nylas = Client(os.environ["NYLAS_API_KEY"])

now = int(time.time())

event = nylas.events.create(
    os.environ["NYLAS_GRANT_ID"],
    request_body={
        "title": "Project kickoff",
        "description": "Review goals and assign workstreams",
        "when": {
            "start_time": now + 3600,
            "end_time": now + 7200,
        },
        "participants": [
            {"name": "Alice", "email": "alice@example.com"},
            {"name": "Bob", "email": "bob@example.com"},
        ],
        "location": "Conference Room B",
    },
    query_params={"calendar_id": "<CALENDAR_ID>"},
)

print("Created event:", event.data.id)
```

```ruby
require 'nylas'

nylas = Nylas::Client.new(api_key: ENV['NYLAS_API_KEY'])

now = Time.now.to_i

event, _ = nylas.events.create(
  identifier: ENV['NYLAS_GRANT_ID'],
  request_body: {
    title: 'Project kickoff',
    description: 'Review goals and assign workstreams',
    when: {
      start_time: now + 3600,
      end_time: now + 7200
    },
    participants: [
      { name: 'Alice', email: 'alice@example.com' },
      { name: 'Bob', email: 'bob@example.com' }
    ],
    location: 'Conference Room B'
  },
  query_params: { calendar_id: '<CALENDAR_ID>' }
)

puts "Created event: #{event[:id]}"
```

```java
public class CreateEvent {
  public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
    NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

    long now = Instant.now().getEpochSecond();

    CreateEventRequest.When.Timespan when = new CreateEventRequest.When.Timespan.Builder(
        (int) (now + 3600), (int) (now + 7200)
    ).build();

    CreateEventRequest requestBody = new CreateEventRequest.Builder(when)
        .title("Project kickoff")
        .description("Review goals and assign workstreams")
        .participants(List.of(
            new CreateEventRequest.Participant("alice@example.com", ParticipantStatus.NOREPLY, "Alice", "", ""),
            new CreateEventRequest.Participant("bob@example.com", ParticipantStatus.NOREPLY, "Bob", "", "")
        ))
        .location("Conference Room B")
        .build();

    CreateEventQueryParams queryParams = new CreateEventQueryParams.Builder("<CALENDAR_ID>").build();
    Response<Event> event = nylas.events().create("<NYLAS_GRANT_ID>", requestBody, queryParams);

    System.out.println("Created event: " + event.getData().getId());
  }
}
```

```kt
fun main() {
    val nylas = NylasClient(apiKey = "<NYLAS_API_KEY>")

    val now = Instant.now().epochSecond

    val when = CreateEventRequest.When.Timespan(
        startTime = (now + 3600).toInt(),
        endTime = (now + 7200).toInt()
    )

    val requestBody = CreateEventRequest(
        `when` = `when`,
        title = "Project kickoff",
        description = "Review goals and assign workstreams",
        participants = listOf(
            CreateEventRequest.Participant("alice@example.com", ParticipantStatus.NOREPLY, "Alice"),
            CreateEventRequest.Participant("bob@example.com", ParticipantStatus.NOREPLY, "Bob")
        ),
        location = "Conference Room B"
    )

    val queryParams = CreateEventQueryParams("<CALENDAR_ID>")
    val event = nylas.events().create("<NYLAS_GRANT_ID>", requestBody, queryParams)

    println("Created event: ${event.data.id}")
}
```

```bash
nylas calendar events create \
  --title "Project kickoff" \
  --start "tomorrow 9am" \
  --end "tomorrow 10am" \
  --participant alice@example.com \
  --participant bob@example.com
```

The event appears on the user’s calendar and invitations go out to participants immediately. That same code works whether the user is on Google Calendar, Outlook, or any other supported provider.

## Check availability

Before scheduling, find times when participants are free. The availability endpoint checks across multiple users’ calendars and returns open time slots.

```bash
curl --request POST \
  --url ‘https://api.us.nylas.com/v3/calendars/availability’ \
  --header ‘Authorization: Bearer <NYLAS_API_KEY>’ \
  --header ‘Content-Type: application/json’ \
  --data ‘{
    "start_time": 1735689600,
    "end_time": 1735776000,
    "duration_minutes": 30,
    "participants": [
      { "email": "alice@example.com" },
      { "email": "bob@example.com" }
    ]
  }’
```

```js [checkAvailability-Node.js]
const availability = await nylas.calendars.getAvailability({
  requestBody: {
    startTime: Math.floor(Date.now() / 1000),
    endTime: Math.floor(Date.now() / 1000) + 86400,
    durationMinutes: 30,
    participants: [
      { email: "alice@example.com" },
      { email: "bob@example.com" },
    ],
  },
});

availability.data.timeslots.forEach((slot) => {
  console.log(`Available: ${new Date(slot.startTime * 1000).toISOString()}`);
});
```

```python
availability = nylas.calendars.get_availability(
    request_body={
        "start_time": int(time.time()),
        "end_time": int(time.time()) + 86400,
        "duration_minutes": 30,
        "participants": [
            {"email": "alice@example.com"},
            {"email": "bob@example.com"},
        ],
    },
)

for slot in availability.data.time_slots:
    print(f"Available: {slot.start_time}")
```

```ruby
availability, _ = nylas.calendars.get_availability(
  request_body: {
    start_time: Time.now.to_i,
    end_time: Time.now.to_i + 86400,
    duration_minutes: 30,
    participants: [
      { email: 'alice@example.com' },
      { email: 'bob@example.com' }
    ]
  }
)

availability[:time_slots].each do |slot|
  puts "Available: #{Time.at(slot[:start_time])}"
end
```

```java
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

long now = Instant.now().getEpochSecond();

GetAvailabilityRequest request = new GetAvailabilityRequest.Builder(
    (int) now, (int) (now + 86400), 30,
    List.of(
        new GetAvailabilityRequest.Participant("alice@example.com"),
        new GetAvailabilityRequest.Participant("bob@example.com")
    )
).build();

Response<GetAvailabilityResponse> availability = nylas.calendars().getAvailability(request);
```

```kt
val now = Instant.now().epochSecond

val request = GetAvailabilityRequest(
    startTime = now.toInt(),
    endTime = (now + 86400).toInt(),
    durationMinutes = 30,
    participants = listOf(
        GetAvailabilityRequest.Participant("alice@example.com"),
        GetAvailabilityRequest.Participant("bob@example.com")
    )
)

val availability = nylas.calendars().getAvailability(request)
```

```bash
nylas calendar schedule ai "Find time for a 30-minute meeting with alice@example.com and bob@example.com tomorrow"
```

This is the foundation for building scheduling features -- find open slots, present them to the user, then create an event in one of the available windows. For a complete scheduling solution with a pre-built UI, see [Nylas Scheduler](/docs/v3/scheduler/).

## RSVP to an event

Respond to a calendar invitation on behalf of a user. Pass the event ID and calendar ID along with the RSVP status (`yes`, `no`, or `maybe`).

```bash
curl --request POST \
  --url ‘https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events/<EVENT_ID>/send-rsvp?calendar_id=<CALENDAR_ID>’ \
  --header ‘Authorization: Bearer <NYLAS_API_KEY>’ \
  --header ‘Content-Type: application/json’ \
  --data ‘{ "status": "yes" }’
```

```js [rsvp-Node.js]
await nylas.events.sendRsvp({
  identifier: process.env.NYLAS_GRANT_ID,
  eventId: "<EVENT_ID>",
  requestBody: { status: "yes" },
  queryParams: { calendarId: "<CALENDAR_ID>" },
});
```

```python
nylas.events.send_rsvp(
    os.environ["NYLAS_GRANT_ID"],
    event_id="<EVENT_ID>",
    request_body={"status": "yes"},
    query_params={"calendar_id": "<CALENDAR_ID>"},
)
```

```ruby
nylas.events.send_rsvp(
  identifier: ENV['NYLAS_GRANT_ID'],
  event_id: '<EVENT_ID>',
  request_body: { status: 'yes' },
  query_params: { calendar_id: '<CALENDAR_ID>' }
)
```

```java
SendRsvpRequest rsvpRequest = new SendRsvpRequest("yes");
SendRsvpQueryParams rsvpParams = new SendRsvpQueryParams.Builder("<CALENDAR_ID>").build();

nylas.events().sendRsvp("<NYLAS_GRANT_ID>", "<EVENT_ID>", rsvpRequest, rsvpParams);
```

```kt
val rsvpRequest = SendRsvpRequest(status = "yes")
val rsvpParams = SendRsvpQueryParams("<CALENDAR_ID>")

nylas.events().sendRsvp("<NYLAS_GRANT_ID>", "<EVENT_ID>", rsvpRequest, rsvpParams)
```

```bash
nylas calendar events rsvp <EVENT_ID> --status yes
```

## List a user’s calendars

Each user can have multiple calendars (work, personal, shared team calendars). Use this to find the right `calendar_id` for the operations above.

```bash
curl --request GET \
  --url ‘https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/calendars’ \
  --header ‘Authorization: Bearer <NYLAS_API_KEY>’
```

```js [listCalendars-Node.js]
const calendars = await nylas.calendars.list({
  identifier: process.env.NYLAS_GRANT_ID,
});

calendars.data.forEach((cal) => {
  console.log(`${cal.name} (${cal.id}) -- primary: ${cal.isPrimary}`);
});
```

```python
calendars = nylas.calendars.list(os.environ["NYLAS_GRANT_ID"])

for cal in calendars.data:
    print(f"{cal.name} ({cal.id}) -- primary: {cal.is_primary}")
```

```ruby
calendars, _ = nylas.calendars.list(identifier: ENV['NYLAS_GRANT_ID'])

calendars.each do |cal|
  puts "#{cal[:name]} (#{cal[:id]}) -- primary: #{cal[:is_primary]}"
end
```

```java
ListResponse<Calendar> calendars = nylas.calendars().list("<NYLAS_GRANT_ID>");

for (Calendar cal : calendars.getData()) {
  System.out.println(cal.getName() + " (" + cal.getId() + ") -- primary: " + cal.getIsPrimary());
}
```

```kt
val calendars = nylas.calendars().list("<NYLAS_GRANT_ID>").data

for (cal in calendars) {
    println("${cal.name} (${cal.id}) -- primary: ${cal.isPrimary}")
}
```

```bash
nylas calendar list
```

## What’s next

- **[Authentication](/docs/v3/auth/)** -- set up OAuth so your users can connect their accounts
- **[Availability deep dive](/docs/v3/calendar/calendar-availability/)** -- open hours, buffers, round-robin, and collective availability
- **[Scheduler](/docs/v3/scheduler/)** -- drop-in scheduling UI your users can share
- **[Webhooks](/docs/v3/notifications/)** -- get notified when events are created, updated, or deleted
- **[Events API reference](/docs/reference/api/events/get-all-events/)** -- full endpoint documentation
- **[Manage calendars from the terminal](https://cli.nylas.com/guides/manage-calendar-from-terminal)** -- quick testing with the Nylas CLI