Msg.Planner.Plans (msg v0.3.8)
Manage Microsoft Planner Plans.
Planner Plans are containers for tasks. Each Microsoft 365 Group can have multiple Plans, which provide project management functionality within Teams and other Microsoft 365 apps.
Required Permissions
Group Plans
- Application: ❌ Not supported
- Delegated:
Tasks.ReadWriteorGroup.ReadWrite.All- required for group plans
User-Accessible Plans
- Application:
Tasks.ReadWrite.All- read/write all plans - Delegated:
Tasks.ReadWrite- read/write user's accessible plans
Authentication
- Group plans (
/groups/{group_id}/planner/plans): Requires delegated permissions - User-accessible plans (
/users/{user_id}/planner/plans): Works with application-only
Etag-Based Concurrency
Planner API requires etags for all update and delete operations to prevent conflicts.
Etags are returned in the @odata.etag field and must be included in the If-Match
header for PATCH and DELETE requests.
Examples
# List plans for a group (requires delegated permissions)
delegated_client = Msg.Client.new(refresh_token, credentials)
{:ok, plans} = Msg.Planner.Plans.list(delegated_client, group_id: "group-id")
# Create a plan
{:ok, plan} = Msg.Planner.Plans.create(delegated_client, %{
owner: "group-id",
title: "Project: Q1 Marketing Campaign"
})
# Update a plan (requires etag)
{:ok, updated} = Msg.Planner.Plans.update(delegated_client, plan_id, %{
title: "Updated Title"
}, etag: plan["@odata.etag"])
# Delete a plan (requires etag)
:ok = Msg.Planner.Plans.delete(delegated_client, plan_id, plan["@odata.etag"])References
Summary
Functions
Creates a new Planner Plan.
Deletes a Planner Plan.
Gets a single Planner Plan by ID.
Lists Planner Plans.
Updates a Planner Plan.
Functions
@spec create(Req.Request.t(), map()) :: {:ok, map()} | {:error, term()}
Creates a new Planner Plan.
Parameters
client- Authenticated Req.Request clientplan- Map with plan properties::owner(required) - Group ID that owns the plan:title(required) - Plan name
Returns
{:ok, plan}- Created plan with generatedidand@odata.etag{:error, :unauthorized}- Invalid or expired token{:error, {:invalid_request, message}}- Validation error{:error, term}- Other errors
Examples
{:ok, plan} = Msg.Planner.Plans.create(client, %{
owner: "group-id-here",
title: "Project: Q1 Marketing Campaign"
})
@spec delete(Req.Request.t(), String.t(), String.t()) :: :ok | {:error, term()}
Deletes a Planner Plan.
Important: Requires the current etag for concurrency control.
Parameters
client- Authenticated Req.Request clientplan_id- ID of plan to deleteetag- Current etag for concurrency control
Returns
:ok- Plan deleted successfully (204 status){:error, {:etag_mismatch, current_etag}}- Etag conflict (412){:error, :not_found}- Plan doesn't exist{:error, term}- Other errors
Examples
{:ok, plan} = Msg.Planner.Plans.get(client, plan_id)
:ok = Msg.Planner.Plans.delete(client, plan_id, plan["@odata.etag"])
@spec get(Req.Request.t(), String.t()) :: {:ok, map()} | {:error, term()}
Gets a single Planner Plan by ID.
Parameters
client- Authenticated Req.Request clientplan_id- ID of the plan to retrieve
Returns
{:ok, plan}- Plan map with details including@odata.etag{:error, :not_found}- Plan doesn't exist{:error, term}- Other errors
Examples
{:ok, plan} = Msg.Planner.Plans.get(client, "plan-id")
etag = plan["@odata.etag"]
@spec list( Req.Request.t(), keyword() ) :: {:ok, [map()]} | {:ok, map()} | {:error, term()}
Lists Planner Plans.
Parameters
client- Authenticated Req.Request clientopts- Keyword list of options::group_id- Group ID (for group's plans - primary use case):user_id- User ID or UPN (for user's accessible plans):auto_paginate- Boolean, default true (fetch all pages)
Note: Either :group_id or :user_id is required.
Returns
{:ok, [plan]}- List of plans (when auto_paginate: true){:ok, %{items: [plan], next_link: url}}- First page with next link (when auto_paginate: false){:error, term}- Error
Examples
# List plans for a group
{:ok, plans} = Msg.Planner.Plans.list(client, group_id: "group-id")
# List plans accessible by user
{:ok, plans} = Msg.Planner.Plans.list(client, user_id: "user@contoso.com")
Updates a Planner Plan.
Important: Requires the current etag for concurrency control. If the etag doesn't match the current version, the update will fail with a 412 Precondition Failed error.
Parameters
client- Authenticated Req.Request clientplan_id- ID of plan to updateupdates- Map of fields to update (typically just:title)opts- Keyword list of options::etag(required) - Current etag from the plan
Returns
{:ok, plan}- Updated plan with new@odata.etag{:error, {:etag_mismatch, current_etag}}- Etag conflict (412){:error, :not_found}- Plan doesn't exist{:error, term}- Other errors
Examples
# Get current plan first to obtain etag
{:ok, plan} = Msg.Planner.Plans.get(client, plan_id)
{:ok, updated} = Msg.Planner.Plans.update(client, plan_id,
%{title: "Updated Project Name"},
etag: plan["@odata.etag"]
)