FIELD NOTES / 4 MIN READ

Can You Give a Bot Calendar Write Access Without Delete Permission?

Neither Google Calendar nor Microsoft Graph offers an OAuth scope that grants event creation and edits but blocks deletion. If your bot needs write access, it gets delete access on the same calendar unless you add a restriction outside the OAuth layer, such as a dedicated app-created calendar or an application-side guard.

AI-assisted editorial: researched and drafted with AI using the primary sources linked below. Examples are illustrative; they are not measured product results. Editorial policy.

Key takeaways

  • Google's calendar.events and calendar scopes authorize event deletion using the exact same grant as event creation and editing — there is no write-only variant.
  • Microsoft Graph's Calendars.ReadWrite is the least-privileged permission that allows delete, and it also grants create, read and update; no finer Graph permission exists.
  • If you need write without delete, isolate the bot to a secondary calendar it created (Google's calendar.app.created) or add an application-layer check that rejects delete calls before they reach the API.

The direct answer

No. Neither of the two calendar APIs most bots connect to — Google Calendar and Microsoft Graph — has a scope that separates "create and edit events" from "delete events." If your bot's OAuth grant lets it insert or update an event, that same grant lets it call the delete endpoint on the identical calendar. The split you might expect, something like calendar.write versus calendar.delete, doesn't exist in either provider's scope list.

This matters because a lot of calendar-bot designs assume OAuth scoping is the access boundary. For calendars, it isn't fine-grained enough to do that job alone. If you want a bot that can reschedule your meetings but can't wipe your calendar, you have to build that boundary somewhere else — either by restricting what calendar the bot can touch, or by putting a check in front of the API call.

What Google Calendar's scopes actually authorize

Google's events.delete endpoint lists its accepted scopes explicitly. It will accept a request authorized with any of calendar, calendar.events, calendar.app.created, or calendar.events.owned. Google's own reference states this request requires authorization with at least one of those scopes.

Look at what two of those same scopes authorize for writing. The calendar.events scope is described as letting an app view and edit events on all your calendars, and the broader calendar scope lets an app see, edit, share, and permanently delete all the calendars you can access. In other words, the scope that gives a bot permission to edit an event is the same scope that gives it permission to delete that event. Google does not expose a narrower write-only event scope.

There's one partial exception. The calendar.app.created scope lets an app make secondary Google calendars, and see, create, change, and delete events on them. It still bundles delete with write, but it confines both to calendars the app itself created — not the user's primary calendar. That's a containment boundary, not a delete-permission boundary, but it's useful: a bot restricted to calendar.app.created can delete events, just never anything outside its own sandboxed calendar.

Sources: Events: delete, Choose Google Calendar API scopes.

Microsoft Graph has the same gap

Microsoft Graph's pattern is identical. The delete-event endpoint's permissions table lists Calendars.ReadWrite as the permission, from least to most privileged, for delegated work or school accounts, delegated personal accounts, and application access alike. There's no lower-privileged permission that unlocks delete; Calendars.ReadWrite is already the floor.

That same permission is what you request to create or modify an event in the first place. Microsoft's permissions reference describes it as allowing the app to create, read, update, and delete events in user calendars. A bot asking for write access to update event times is, by definition, asking for the permission that also deletes events — there's no way to carve delete out of Calendars.ReadWrite at the OAuth layer.

Microsoft does offer Calendars.Read as a strictly read-only step down, and Calendars.ReadWrite.Shared for shared/delegate calendars, but neither changes the core fact: once you cross into write, delete comes bundled in.

Sources: Delete event - Microsoft Graph v1.0, Microsoft Graph permissions reference - Microsoft Graph.

Worked example: a scheduling bot for a small team

Say you're building a bot (illustrative, not a real product) that reschedules meetings when someone replies "can we move this." It needs to update start/end times on existing events on a shared team calendar. You request calendar.events for Google or Calendars.ReadWrite for Microsoft, because that's what the "update an event" API call requires.

At that point, the bot's OAuth token can also call events.delete or DELETE /me/events/{id}. If the bot has a bug — say it treats a cancellation reply as a delete-and-recreate instead of an update, or a prompt injection in a calendar invite description tricks it into calling the delete tool — there's no OAuth-level wall stopping it from removing events on the shared calendar. The scope you needed for the legitimate feature also grants the capability you didn't want.

The failure path to watch for specifically: a tool-calling LLM that has both an update_event and a delete_event function exposed, operating on a token scoped to calendar.events. If the model mis-classifies a user message, it calls delete_event, and the token happily authorizes it. The scope was never the safeguard; it only looked like one.

What to do instead

Since the OAuth scope can't exclude delete, move the boundary somewhere it can actually hold. Three practical options, in order of how much they rely on the provider versus your own code:

First, confine the bot to a calendar it owns. On Google, request calendar.app.created and have the bot operate only on a secondary calendar it created for this purpose, never the user's primary calendar. A delete call can still fire, but the blast radius is the bot's own calendar, not the one the human actually uses.

Second, add an application-layer guard between the model and the API client: strip or disable the delete_event tool entirely unless a specific, auditable condition is met (for example, a human approval step), rather than exposing every CRUD operation the scope happens to allow. The token sets the ceiling, your code sets the actual limit.

Third, log and alert on every delete call before it executes, even if you can't block it outright. If the scope can't stop the action, a review step or a kill switch on the delete path is the next-best control. None of this is a BotBento feature today — BotBento is still pre-release — but it's the same logic you'd apply to any tool call that a scope alone can't constrain.

Primary sources

Sources checked 2026-10-09. Standards and product documentation can change; follow the linked version when implementing.

  1. Events: delete — Google Developers
  2. Choose Google Calendar API scopes — Google Developers
  3. Delete event - Microsoft Graph v1.0 — Microsoft Learn
  4. Microsoft Graph permissions reference - Microsoft Graph — Microsoft Learn

BotBento is in development. Suggest a correction.