Outlook Calendar (Microsoft 365)
Let hires read your Outlook calendar, find times when everyone is free, book and move meetings, and answer invitations.
Explore 9 actions and their permissionsExact inputs, sign-in scopes, access limits and approval rules.
With Outlook Calendar, a hire can do everything it does with Google Calendar, in the same way:
- list your calendars and what's on them, and read an event with who's coming and how they answered,
- see when colleagues are busy, and suggest times when everyone is free inside working hours,
- put events on a calendar, with a Teams meeting and invitations if you like,
- move, rename or cancel meetings it organised, and add or remove guests,
- accept, decline or say maybe to invitations, with a note to the organiser.
It's how a personal-assistant hire keeps someone's diary in Microsoft 365.
1. Register an app in Microsoft Entra
If you already registered one for Outlook mail, use the same app: add the permissions below and a second redirect URI.
- Open entra.microsoft.com → App registrations → New registration (or open your Roster app).
- Supported account types: Accounts in this organizational directory only for your own organisation.
- Redirect URI: platform Web, the address Roster shows on the Outlook Calendar
connection. It ends in
/api/integrations/microsoft-calendar/oauth/callback. - Copy the Application (client) ID and the Directory (tenant) ID from Overview.
- API permissions → Add a permission → Microsoft Graph → Delegated permissions: add
User.Read,Calendars.ReadWriteandoffline_access. If Microsoft says your organisation must approve the app, ask whoever manages your Microsoft 365 to grant consent on this page. - Certificates & secrets → New client secret, and copy its Value.
2. Connect it in Roster
- Open Integrations → Tools → Add a tool, search for Outlook Calendar and choose it.
- Paste the OAuth app client ID (the Application ID) and OAuth app client secret.
- Tenant: your Directory (tenant) ID or domain, or
common. - Time zone: the zone hires read and write times in, like
Asia/Dubai. Set this: without it, hires use UTC. - Click Connect, then Connect with Outlook Calendar on the new connection, sign in with the calendar's account and click Accept.
What Roster asks Microsoft for
| Permission | Why |
|---|---|
User.Read | Know the account's own address |
Calendars.ReadWrite | Read events and availability; book, change, cancel and answer (only hires allowed to) |
offline_access | Stay connected without signing in again |
3. Give hires access
On the hire's Tools tab, click Give access on Outlook Calendar:
- Read only: it can list calendars and events, see who's free and suggest times, and nothing else.
- Read and write: it can also book, change and cancel events and answer invitations.
- Calendars: the calendars it may use, by name;
primaryis the account's main calendar. Leave it empty for every calendar. - Who it may invite: domains of people it may invite, like
yourbusiness.com. Leave it empty to let it invite anyone.
Microsoft 365 always tells attendees when a meeting is booked, changed or cancelled; a hire can't do any of those quietly. Inviting someone outside your team is a promise made in your business's name, so it waits for a person's approval: when a hire books or changes a meeting that invites anyone outside your team's domains, or moves a meeting someone outside is on, nothing is sent until the approver says yes, and then Roster books exactly that meeting. To change this for a hire, use When it asks first on its Tools tab. To keep a hire to your own team altogether, put your domain in Who it may invite.
Waking a hire when the calendar changes
A hire's responsibility can watch Outlook Calendar: it's woken when events in the next three months on the main calendar change or are cancelled, or when a new invitation arrives. Checking costs nothing when nothing changed.
If something goes wrong
- "Isn't connected yet": press Connect with Outlook Calendar on the connection.
- "Can't see their calendar" when finding a time: that person is outside your organisation or doesn't share their availability. Finding times isn't available for personal Outlook.com accounts.
- Times are a few hours off: set the connection's Time zone.
- Microsoft says the app needs approval: whoever manages your Microsoft 365 grants consent on the app's API permissions page.
Tools and permissions reference
This reference is built from the same definitions Roster uses to connect Outlook Calendar (Microsoft 365) and give hires access. It updates with each release.
Authentication and requested permissions
The account or app you connect sets the outer limit. Each hire's access can narrow it further. Connecting a tool gives it to no hire until you give access on that hire's Tools tab.
OAuth 2.0
The Application (client) ID of the app you registered for Roster in Microsoft Entra.
Requested scopes:
offline_accessUser.ReadCalendars.ReadWrite
Connection fields
| Field | What to provide |
|---|---|
OAuth app client IDclientIdOptional | The Application (client) ID of the app you registered for Roster in Microsoft Entra. |
OAuth app client secretclientSecretOptional · sealed secret | Use the value for your account or connection. |
TenanttenantOptional | Your Microsoft 365 organisation's tenant ID or domain (in Microsoft Entra → Overview). Leave it as common to let any work, school or personal account sign in. Starts with: |
Time zonetimeZoneOptional | The time zone hires read and write times in. Leave empty to use the calendar's own. |
Per-hire limits
Read-only hires receive only actions that read. Read-and-write access also allows actions that change things, where the connection itself permits them. An empty resource allowlist usually means everything the connected account can reach; each field below explains its meaning.
| Field | What to provide |
|---|---|
CalendarscalendarsOptional | Calendars the hire may use, by name or ID; primary is the account's own. Leave empty for every calendar. A watch checks these (or primary). |
Who it may inviteinviteDomainsOptional | Domains of people the hire may invite to events, like example.com. Leave empty to let it invite anyone. |
Actions
9 actions: 5 only read and 4 change something. A read action may still need approval when your workspace or hire is set to ask. A locked approval requirement always applies.
9 of 9 actions. Open an action for its arguments and full input schema.
list_calendarsRead only
The calendars this hire can use: name, ID, whether it can change them, and their time zone.
Approval: Uses your workspace and hire approval settings.
This action takes no arguments.
Full input schema (JSON)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {}
}list_eventsRead only
Events on a calendar between two times (default: the next 7 days), soonest first, recurring ones expanded. Optionally only those matching words.
Approval: Uses your workspace and hire approval settings.
| Argument | Type | Details |
|---|---|---|
calendarOptional | string | calendar name or ID; primary is the account's ownDefault: "primary" |
fromOptional | string | from (default now): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day |
toOptional | string | until (default a week after from): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day |
queryOptional | string | words in the title, description, place or attendees |
limitOptional | integer | See input schema below.Default: 25 |
Full input schema (JSON)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"calendar": {
"default": "primary",
"description": "calendar name or ID; primary is the account's own",
"type": "string",
"minLength": 1,
"maxLength": 300
},
"from": {
"type": "string",
"minLength": 10,
"maxLength": 40,
"description": "from (default now): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day"
},
"to": {
"type": "string",
"minLength": 10,
"maxLength": 40,
"description": "until (default a week after from): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day"
},
"query": {
"description": "words in the title, description, place or attendees",
"type": "string",
"minLength": 1,
"maxLength": 200
},
"limit": {
"default": 25,
"type": "integer",
"minimum": 1,
"maximum": 100
}
}
}read_eventRead only
Read one event: when, where, the video call, who's invited and how they answered, and its notes.
Approval: Uses your workspace and hire approval settings.
| Argument | Type | Details |
|---|---|---|
calendarOptional | string | calendar name or ID; primary is the account's ownDefault: "primary" |
idRequired | string | the event's id, from list_events |
Full input schema (JSON)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"calendar": {
"default": "primary",
"description": "calendar name or ID; primary is the account's own",
"type": "string",
"minLength": 1,
"maxLength": 300
},
"id": {
"type": "string",
"minLength": 1,
"maxLength": 1100,
"description": "the event's id, from list_events"
}
},
"required": [
"id"
]
}free_busyRead only
When people are busy between two times (default: the next 7 days), from their calendars. Works for colleagues whose calendars share free/busy.
Approval: Uses your workspace and hire approval settings.
| Argument | Type | Details |
|---|---|---|
peopleOptional | string[] | email addresses (or calendar IDs); primary for the account's own calendarDefault: ["primary"] |
fromOptional | string | from (default now): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day |
toOptional | string | until (default a week after from): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day |
Full input schema (JSON)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"people": {
"default": [
"primary"
],
"maxItems": 50,
"type": "array",
"items": {
"type": "string",
"minLength": 3,
"maxLength": 320
},
"description": "email addresses (or calendar IDs); primary for the account's own calendar"
},
"from": {
"type": "string",
"minLength": 10,
"maxLength": 40,
"description": "from (default now): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day"
},
"to": {
"type": "string",
"minLength": 10,
"maxLength": 40,
"description": "until (default a week after from): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day"
}
}
}find_timeRead only
Suggest times when everyone is free for a meeting of a given length, inside working hours on working days, in the calendar's time zone.
Approval: Uses your workspace and hire approval settings.
| Argument | Type | Details |
|---|---|---|
peopleOptional | string[] | email addresses (or calendar IDs); primary for the account's own calendarDefault: ["primary"] |
duration_minutesOptional | integer | See input schema below.Default: 30 |
fromOptional | string | earliest (default now): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day |
toOptional | string | latest (default a week after from): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day |
day_startOptional | string | working hours start, HH:MMDefault: "09:00" |
day_endOptional | string | working hours end, HH:MMDefault: "18:00" |
daysOptional | "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | "sun"[] | working daysDefault: ["mon","tue","wed","thu","fri"] |
limitOptional | integer | See input schema below.Default: 5 |
Full input schema (JSON)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"people": {
"default": [
"primary"
],
"maxItems": 50,
"type": "array",
"items": {
"type": "string",
"minLength": 3,
"maxLength": 320
},
"description": "email addresses (or calendar IDs); primary for the account's own calendar"
},
"duration_minutes": {
"default": 30,
"type": "integer",
"minimum": 10,
"maximum": 480
},
"from": {
"type": "string",
"minLength": 10,
"maxLength": 40,
"description": "earliest (default now): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day"
},
"to": {
"type": "string",
"minLength": 10,
"maxLength": 40,
"description": "latest (default a week after from): 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day"
},
"day_start": {
"default": "09:00",
"description": "working hours start, HH:MM",
"type": "string",
"pattern": "^\\d{2}:\\d{2}$"
},
"day_end": {
"default": "18:00",
"description": "working hours end, HH:MM",
"type": "string",
"pattern": "^\\d{2}:\\d{2}$"
},
"days": {
"default": [
"mon",
"tue",
"wed",
"thu",
"fri"
],
"description": "working days",
"minItems": 1,
"type": "array",
"items": {
"type": "string",
"enum": [
"mon",
"tue",
"wed",
"thu",
"fri",
"sat",
"sun"
]
}
},
"limit": {
"default": 5,
"type": "integer",
"minimum": 1,
"maximum": 10
}
}
}create_eventRead and write
Put an event on a calendar, optionally inviting people (they get an invitation) and adding a video call. Inviting people outside the team commits the business to them, so such a call waits for a person's approval: Roster asks for you and makes it, exactly as you called it, once they approve.
Approval: when it invites someone outside your team, or moves an event they're on.
| Argument | Type | Details |
|---|---|---|
calendarOptional | string | calendar name or ID; primary is the account's ownDefault: "primary" |
titleRequired | string | See input schema below. |
startRequired | string | start: 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day |
endOptional | string | end; or give duration_minutes |
duration_minutesOptional | integer | See input schema below. |
locationOptional | string | See input schema below. |
descriptionOptional | string | See input schema below. |
attendeesOptional | string[] | email addresses to inviteDefault: [] |
video_callOptional | boolean | add a video call linkDefault: false |
notifyOptional | boolean | send invitations by emailDefault: true |
Full input schema (JSON)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"calendar": {
"default": "primary",
"description": "calendar name or ID; primary is the account's own",
"type": "string",
"minLength": 1,
"maxLength": 300
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 300
},
"start": {
"type": "string",
"minLength": 10,
"maxLength": 40,
"description": "start: 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day"
},
"end": {
"description": "end; or give duration_minutes",
"type": "string",
"minLength": 10,
"maxLength": 40
},
"duration_minutes": {
"type": "integer",
"minimum": 5,
"maximum": 1440
},
"location": {
"type": "string",
"minLength": 1,
"maxLength": 500
},
"description": {
"type": "string",
"minLength": 1,
"maxLength": 8000
},
"attendees": {
"default": [],
"description": "email addresses to invite",
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"minLength": 3,
"maxLength": 320
}
},
"video_call": {
"default": false,
"description": "add a video call link",
"type": "boolean"
},
"notify": {
"default": true,
"description": "send invitations by email",
"type": "boolean"
}
},
"required": [
"title",
"start"
]
}update_eventRead and write
Change an event: its title, time, place, notes, or who's invited (attendees are told when notify is on). Inviting people outside the team commits the business to them, so such a call waits for a person's approval: Roster asks for you and makes it, exactly as you called it, once they approve.
Approval: when it invites someone outside your team, or moves an event they're on.
| Argument | Type | Details |
|---|---|---|
calendarOptional | string | calendar name or ID; primary is the account's ownDefault: "primary" |
idRequired | string | the event's id, from list_events |
titleOptional | string | See input schema below. |
startOptional | string | new start: 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day |
endOptional | string | new end: 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day |
locationOptional | string | See input schema below. |
descriptionOptional | string | See input schema below. |
add_attendeesOptional | string[] | See input schema below.Default: [] |
remove_attendeesOptional | string[] | See input schema below.Default: [] |
notifyOptional | boolean | tell attendees by emailDefault: true |
Full input schema (JSON)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"calendar": {
"default": "primary",
"description": "calendar name or ID; primary is the account's own",
"type": "string",
"minLength": 1,
"maxLength": 300
},
"id": {
"type": "string",
"minLength": 1,
"maxLength": 1100,
"description": "the event's id, from list_events"
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 300
},
"start": {
"type": "string",
"minLength": 10,
"maxLength": 40,
"description": "new start: 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day"
},
"end": {
"type": "string",
"minLength": 10,
"maxLength": 40,
"description": "new end: 2026-11-10T14:00 in the calendar's time zone, or 2026-11-10 for a day"
},
"location": {
"type": "string",
"maxLength": 500
},
"description": {
"type": "string",
"maxLength": 8000
},
"add_attendees": {
"default": [],
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"minLength": 3,
"maxLength": 320
}
},
"remove_attendees": {
"default": [],
"maxItems": 100,
"type": "array",
"items": {
"type": "string",
"minLength": 3,
"maxLength": 320
}
},
"notify": {
"default": true,
"description": "tell attendees by email",
"type": "boolean"
}
},
"required": [
"id"
]
}cancel_eventRead and write
Cancel an event this calendar organised, telling attendees (with an optional note) when notify is on. For someone else's event, decline it with respond_to_invitation instead.
Approval: Uses your workspace and hire approval settings.
| Argument | Type | Details |
|---|---|---|
calendarOptional | string | calendar name or ID; primary is the account's ownDefault: "primary" |
idRequired | string | the event's id, from list_events |
noteOptional | string | a short message to attendees, where the calendar supports it |
notifyOptional | boolean | See input schema below.Default: true |
Full input schema (JSON)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"calendar": {
"default": "primary",
"description": "calendar name or ID; primary is the account's own",
"type": "string",
"minLength": 1,
"maxLength": 300
},
"id": {
"type": "string",
"minLength": 1,
"maxLength": 1100,
"description": "the event's id, from list_events"
},
"note": {
"description": "a short message to attendees, where the calendar supports it",
"type": "string",
"minLength": 1,
"maxLength": 2000
},
"notify": {
"default": true,
"type": "boolean"
}
},
"required": [
"id"
]
}respond_to_invitationRead and write
Accept, decline or say maybe to an event someone else invited this calendar to, with an optional note to the organiser.
Approval: Uses your workspace and hire approval settings.
| Argument | Type | Details |
|---|---|---|
calendarOptional | string | calendar name or ID; primary is the account's ownDefault: "primary" |
idRequired | string | the event's id, from list_events |
responseRequired | "accept" | "decline" | "maybe" | See input schema below. |
noteOptional | string | See input schema below. |
Full input schema (JSON)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"calendar": {
"default": "primary",
"description": "calendar name or ID; primary is the account's own",
"type": "string",
"minLength": 1,
"maxLength": 300
},
"id": {
"type": "string",
"minLength": 1,
"maxLength": 1100,
"description": "the event's id, from list_events"
},
"response": {
"type": "string",
"enum": [
"accept",
"decline",
"maybe"
]
},
"note": {
"type": "string",
"minLength": 1,
"maxLength": 2000
}
},
"required": [
"id",
"response"
]
}Watches and incoming events
- This integration supports a responsibility that watches for changes. The guide above explains what it checks and how to limit it.
- No incoming webhook handler is declared for this integration.
Limits and troubleshooting
- Permission errors: check both the connected account's rights and the hire's resource and read/write limits.
- Expired or revoked access: reconnect or replace the key on the connection.
- Rate limits and unavailable services can interrupt work. The hire's timecard records the outcome.
- The action schema describes accepted inputs. It does not grant additional access or bypass approvals.