How to Configure Microsoft Calendar (Outlook / M365) for Voce AI

Wire a Microsoft 365 mailbox calendar into Voce via Azure AD + Microsoft Graph โ€” no per-user consent flow, no refresh tokens.

AI Voice Agents

What this enables

When configured, Voce can:

  • Check real-time availability on a Microsoft 365 mailbox's calendar during a call
  • Book appointments and create events via Microsoft Graph
  • Send a calendar invite to the caller's email (if provided)
  • Respect per-tenant booking windows so only specific days/hours are offered
Per-tenant: each Voce tenant uses their own Azure AD app registration and target mailbox. The procedure below is repeated for each new tenant.
Difference from the Google flow: Microsoft uses app-only (client-credentials) OAuth โ€” no per-user consent flow, no refresh token, no OAuth Playground. Instead, you register an app in Azure AD, grant it permission to access calendars, and let it act as the app itself (no human user signing in). The app gets a new access token each time using just tenant_id + client_id + client_secret.

Prerequisites

  • A Microsoft 365 tenant (your work/business Microsoft account, NOT a personal @outlook.com)
  • An Azure AD account with permission to register apps AND grant admin consent on application permissions (typically a Global Admin or Application Administrator role). If you don't have admin rights, your M365 admin must do Steps 2 and 3 for you.
  • The mailbox whose calendar Voce should write to (e.g. [email protected])
  • ~10 minutes

Step 1 โ€” Register an App in Azure AD

  1. Open https://portal.azure.com
  2. Search bar (top) โ†’ App registrations โ†’ click it
  3. + New registration
  4. Name: something descriptive, e.g. voce-calendar-integration
  5. Supported account types: "Accounts in this organizational directory only (Single tenant)" โ€” recommended for security
  6. Redirect URI: leave blank (not needed for app-only / client-credentials flow)
  7. Register
  8. On the resulting overview page, copy these two values โ€” you'll need them in Step 5:
    • Application (client) ID
    • Directory (tenant) ID

Step 2 โ€” Grant the Calendars.ReadWrite (Application) Permission

  1. From your new app's overview page, left nav โ†’ API permissions
  2. + Add a permission โ†’ Microsoft Graph โ†’ Application permissions (CRITICAL โ€” NOT Delegated)
  3. Search for and check Calendars.ReadWrite
  4. Add permissions
  5. Back on the API permissions page, click Grant admin consent for [Your Tenant] (top of the permissions list)
    • This button requires admin rights. If you don't see it or it's grayed out, ask your M365 admin to do this step.
    • After consent, the status column should show a green checkmark โœ“
  6. Verify the row reads:
    Microsoft Graph  Calendars.ReadWrite  Application  Granted for [Tenant]
Why "Application" not "Delegated": Application permissions let the app act without a signed-in user โ€” exactly what Voce needs (it runs on a server, not in a browser). Delegated permissions require a human signing in interactively, which doesn't fit the headless-agent model.

Step 3 โ€” Create a Client Secret

  1. From your app's overview page, left nav โ†’ Certificates & secrets
  2. + New client secret
  3. Description: e.g. voce-integration-secret
  4. Expires: pick a lifetime โ€” 24 months is the longest Azure allows; you'll need to rotate before it expires
  5. Add
  6. IMMEDIATELY copy the Value column โ€” this is shown ONCE and never visible again. If you lose it, delete and create a new one.
  7. Do NOT copy the Secret ID โ€” that's a different value you don't need.

Step 4 โ€” Identify the Target Mailbox

The User Principal Name (UPN) is the email-format identifier of the mailbox Voce will read/write. Examples:

Where to find it:

  • M365 Admin Center โ†’ Users โ†’ Active users โ†’ click the user โ†’ Username/UPN field
  • Or just use the email address โ€” for most M365 setups, the email and UPN are identical

Step 5 โ€” Configure in the Voce Dashboard

  1. Open the Voce tuning dashboard
  2. Scroll to Integrations ยท Microsoft Calendar credentials
  3. Fill in:
    • Azure Tenant ID โ€” from Step 1.8 (Directory ID, looks like xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
    • App Client ID โ€” from Step 1.8 (Application ID, same UUID format)
    • App Client Secret โ€” from Step 3.6 (the Value, NOT the Secret ID)
    • Mailbox (user principal name) โ€” from Step 4
  4. Scroll up to Integrations ยท Calendar backend (which one is active)
  5. Active calendar backend โ†’ Microsoft Calendar
  6. Booking Windows (optional but recommended) โ€” restrict bookable times, e.g.:
    tue 14:00-17:00, thu 14:00-17:00
    Empty = 9-5 M-F default.
  7. Save

Step 6 โ€” Verify

Voce will use the new calendar on the next inbound call. The operator can run the smoke script on the Voce VM to validate the plumbing without a phone call (covers token acquisition + free/busy query).

A successful test outputs:

โœ… ms_calendar_token_refreshed
โœ… free/busy returned N busy ranges for today
โœ… End-to-end Microsoft Calendar integration is working.

Common Errors and Fixes

Error messageWhat it meansFix
AADSTS7000215: Invalid client secret providedSecret is wrong or has expiredRe-check Step 3.6 (the Value, not the Secret ID); if expired, create a new secret and re-paste
AADSTS700016: Application with identifier ... was not foundClient ID or Tenant ID has a typoRe-copy both UUIDs from Step 1.8
AADSTS65001: The user or administrator has not consentedApplication permission not yet admin-consentedStep 2.5 โ€” admin must click Grant admin consent
Forbidden / HTTP 403 on /calendar/getSchedule or /eventsCalendars.ReadWrite (Application) permission missing or scoped to a different resourceStep 2 โ€” confirm permission is Application (not Delegated) and shows โœ“ "Granted for [Tenant]"
ResourceNotFound โ€” The specified object was not found for the UPNUPN typo, mailbox doesn't exist, or no Exchange Online license on that userVerify UPN in M365 Admin Center; confirm the user has an active Exchange Online license
Permissions appear granted but calls still failPermission propagation lag (rare)Wait ~5 minutes and retry. If still failing, try removing + re-adding the permission.

โš ๏ธ Important Security Consideration

By default, an app with Calendars.ReadWrite Application permission can read and write EVERY mailbox in your tenant โ€” not just the one you specified in the UPN. For most installs, this is acceptable trust (the secret stays secret, the app code only ever uses the configured UPN). For tighter security, you can scope the app to a single mailbox using PowerShell.
# Run as an Exchange admin (Exchange Online PowerShell module)
New-DistributionGroup -Name "VoceCalendarAccess" -Type Security
Add-DistributionGroupMember -Identity "VoceCalendarAccess" `
    -Member "[email protected]"
New-ApplicationAccessPolicy -AppId <client-id-from-step-1> `
    -PolicyScopeGroupId "[email protected]" `
    -AccessRight RestrictAccess `
    -Description "Restrict Voce to the scheduling mailbox only"

This locks Voce's access to only the [email protected] mailbox. Other mailboxes in the tenant become unreachable to the app even if its secret leaks. Recommended for HIPAA-regulated tenants or anywhere with sensitive mailbox content beyond the scheduling box.


Operational Notes

  • Client secrets are long-lived but EXPIRE (default โ‰ค24 months). Mark your calendar to rotate before expiry, or you'll get AADSTS7000215 errors on the day it expires and bookings will fail.
  • No refresh tokens โ€” Microsoft Graph access tokens (~1hr lifetime) are acquired fresh each time using just tenant_id + client_id + client_secret. Voce caches them in-process.
  • Client secret is a long-lived secret โ€” marked secret in the Voce dashboard, never logged. Treat like a password.
  • Permission propagation can lag โ€” newly-granted permissions sometimes take a couple of minutes to take effect. If a fresh setup fails, wait 5 min and retry before debugging.
  • Per-tenant: every tenant onboarding repeats Steps 1โ€“5 with their own Azure tenant, app registration, and credentials. Each tenant's config lives in Voce's per-tenant Postgres store.
  • Switching backends: Voce can use either Google Calendar OR Microsoft Calendar per tenant. The "Active calendar backend" dropdown picks which is in use. Both can be configured simultaneously and switched without a restart.

Related

  • Google Calendar setup โ€” uses OAuth 2.0 refresh tokens via OAuth Playground. Different procedure, same dashboard fields.
  • Booking windows format โ€” see dashboard field help text for the full syntax (DOW HH:MM-HH:MM, comma-separated, multiple windows per day allowed).
  • Sales demo flow โ€” when a calendar backend is active, Voce automatically offers booking as a third option for sales-interested callers ("Connect now / Book demo / Callback").