diff --git a/docs/embedded/spe-docs-agent-ready/README.md b/docs/embedded/spe-docs-agent-ready/README.md new file mode 100644 index 000000000..60c531129 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/README.md @@ -0,0 +1,45 @@ +# SharePoint Embedded — agent-ready documentation set + +This folder is a **proposed, drop-in agent-ready revamp** of the public SharePoint Embedded (SPE) +documentation under `learn.microsoft.com/sharepoint/dev/embedded/**`. Every page is rewritten so an +AI agent (Claude Code, ChatGPT, Copilot, Cursor, etc.) can read it and execute the next step without +human-only affordances (no "click here", no screenshots, no buried GUIDs). + +It is structured to be uploaded as a single folder into a GitHub docs repo (e.g. `sp-dev-docs`), +mirroring the live Learn folder layout. + +## What governs these pages + +| File | Role | +|---|---| +| `index.md` | Persona-tagged routing landing page + machine-readable navigation manifest. The canonical **structure** model. | +| `_TEMPLATE-AND-RULES.md` | Per-page authoring spec (frontmatter shape, body templates by `task_type`, hard rules). | +| `api-surface.json` | Every Microsoft Graph operation referenced by SPE docs (method, path, permissions, stability) + known API gaps. | +| `toc.yml` | Table of contents for the set. | + +Each page carries an `agent:` frontmatter block, a `` status banner, stable +section anchors, typed inputs/outputs, explicit failure modes, Verify and Troubleshooting sections, +and `manual:` blocks for any unavoidable portal/PowerShell step. + +## Page inventory + +Pages mirror the live Learn paths called out in the `index.md` navigation manifest: + +- `overview.md`, `scenarios-and-use-cases.md`, `whats-new.md` +- `getting-started/` — `spembedded-for-vscode`, `containertypes`, `register-api-documentation` +- `development/` — `app-architecture`, `auth`, `sharing-and-perm`, `limits-calling`, `fluid` +- `development/declarative-agent/` — `sharepoint-embedded-knowledge-source` +- `development/content-experiences/` — `office-experience`, `user-experiences-overview`, `search-content` +- `development/tutorials/` — `launch-experience`, `metadata`, `using-file-preview`, `doc-processing-acs`, `using-webhooks`, `migrate-abs-to-spe`, `vendor-install-app-customer` +- `administration/billing/` — `billing`, `billingmanagement`, `meters` +- `administration/developer-admin/` — `dev-admin` +- `administration/` — `adminrole` +- `administration/consuming-tenant-admin/` — `cta`, `ctapowershell`, `ctaux` +- `compliance/` — `security-and-compliance` + +## Status + +All pages are marked `last_validated: proposed`. Validate every endpoint against `api-surface.json` +and run an end-to-end harness before publishing. + +Author: Shreyas Saravanan diff --git a/docs/embedded/spe-docs-agent-ready/_TEMPLATE-AND-RULES.md b/docs/embedded/spe-docs-agent-ready/_TEMPLATE-AND-RULES.md new file mode 100644 index 000000000..db3dd3f92 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/_TEMPLATE-AND-RULES.md @@ -0,0 +1,172 @@ +# Agent-Ready Page Template & Rules (authoring spec for the revamped SPE docs) + +> Every `.md` file under `revamped-docs/` MUST follow this spec. It operationalizes +> `spe-agent-ready-standards.md` (v0.1) and the per-page requirements in +> `spe-per-document-changes.md`. Use real Graph endpoints from `api-surface.json`. +> These are PROPOSED drop-in replacements for `sp-dev-docs/docs/embedded/**`. + +## 0. Status banner (top of every page body, after frontmatter) +Add this HTML comment as the first line of the body: +`` + +## 1. Frontmatter (every page) +Preserve realistic Learn frontmatter, then add the `agent:` block. + +```yaml +--- +title: +description: +ms.topic:
+ms.service: sharepoint-online +ms.author: vesaj +author: VesaJuvonen +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: + outcome: # how-to/quickstart only + estimated_minutes: # how-to/quickstart only + difficulty: + roles: [] + prerequisites: + - uri: /sharepoint/dev/embedded/ + kind: + - capability: + api_surface: # every endpoint this page tells the reader to call; omit if none + - id: + method: POST + path: /storage/fileStorage/containers + permissions: [FileStorageContainer.Selected] + inputs: # every {placeholder} used in code; omit if none + - name: container-id + type: uuid + source: + outputs: # observable success criteria; omit if none + - name: container-id + type: uuid + verify: GET /storage/fileStorage/containers/{container-id} returns 200 + next_steps: + - uri: /sharepoint/dev/embedded/ + when: + related: + - uri: /sharepoint/dev/embedded/ + stability: + last_validated: proposed # literal string "proposed" until an end-to-end harness run stamps a date +--- +``` + +## 2. Body templates by task_type + +### how-to / quickstart (REQUIRED section order) +``` +# {Title} + + +{One short paragraph: what the reader will have at the end. No marketing.} + +## Prerequisites +- [](/sharepoint/dev/embedded/) — +- Capability: (e.g., an Entra app with Application Administrator role) + +## Inputs +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{container-id}` | uuid | A prior step / user-supplied | + +## Steps + +### Step 1 — {Imperative verb phrase, one outcome} {#step-1} +{One sentence of why, then the action.} + +```http +POST https://graph.microsoft.com/v1.0/storage/fileStorage/containers +Authorization: Bearer {token} +Content-Type: application/json + +{ "displayName": "{display-name}", "containerTypeId": "{container-type-id}" } +``` + +**Expected response:** `201 Created` with a `fileStorageContainer` whose `status` is `inactive`. + +**On failure:** +- `403 Forbidden` (`accessDenied`) → admin consent not granted. See [Grant ... permissions](...). +- `400 Bad Request` → `containerTypeId` not registered on this tenant. + +### Step 2 — ... {#step-2} +... + +## Verify +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containers/{container-id} +``` +Returns `200 OK` with `status` equal to `active`. + +## Troubleshooting +| Symptom | Likely cause | Fix | +|---|---|---| +| `401 Unauthorized` | Token missing/expired or wrong scope | Re-acquire a token with the permission in **Inputs** | +| `403 Forbidden` | Admin consent not granted | Grant consent, then re-acquire the token | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps +- [](/sharepoint/dev/embedded/) + +## Related +- [](/sharepoint/dev/embedded/) +``` + +### concept (REQUIRED section order) +``` +# {Title} + + +## What it is +## Why it matters / when to use +## When NOT to use +## Key terms +## How it fits together (owning vs consuming tenant, content vs control plane, where relevant) +## Related +``` +Concept pages MUST NOT contain imperative steps or API call instructions — link to the how-to instead. + +### reference (REQUIRED section order) +``` +# {Title} + + +## (structured tables only) +## Examples +## See also +``` + +## 3. Hard rules (enforced; CI would block on these) +- Every fenced code block declares a language: `http`, `bash`, `pwsh`, `json`, `yaml`, `csharp`, `typescript`, `python`. No bare ```` ``` ````. +- Every `{placeholder}` in a code block is kebab-case and declared in `agent.inputs`. Never `{your-client-id}`, never ``. +- Every how-to/quickstart step ends in a real call (```http``` / ```bash``` / ```pwsh```) or a `manual:` block; declares an expected status; and lists ≥1 named failure mode. +- A portal/PowerShell-only action uses a `manual:` block carrying `ui_path` + `api_equivalent` (or `api_equivalent: none — see api-surface.json gap ` if no API exists) + a `verify`. +- Callouts use `> [!NOTE]` / `> [!IMPORTANT]` / `> [!WARNING]`. No bare **Note:** lines. +- BANNED in step bodies (outside `manual:`): "click", "tap", "press", "navigate to" (without a URL), "see the screenshot", "as shown above/below", "simply", "just", "easily", "should be familiar with", "in a previous step" (use `{#step-n}` anchors). +- Section anchors are stable: `{#step-1}`, `{#verify}`, `{#troubleshooting}`. +- Permission GUIDs / endpoint metadata go in JSON or tables, never prose bullets. +- For any endpoint, pull method/path/permissions/stability from `api-surface.json`. If it's `beta`, say so and mark `stability: beta`. If it's a `gaps[]` entry, document the manual path AND reference the gap id. + +## 4. `manual:` block shape (for unavoidable portal/PowerShell steps) +```yaml +manual: + description: Activate pay-as-you-go billing for SharePoint Embedded. + ui_path: Microsoft 365 admin center → Setup → Pay-as-you-go services → SharePoint Embedded + api_equivalent: none — no Graph API today; see api-surface.json gap "activateConsumingTenantPayg" + verify: + method: GET + path: /storage/fileStorage/containerTypes/{container-type-id} +``` + +## 5. File naming & placement +- Use the path given in your assignment, under `revamped-docs/`, mirroring Learn folders. +- One outcome per file. Split pages get separate files as named. +- Lowercase kebab-case filenames. + +## 6. Tone +Second-person imperative for steps; third-person declarative for concepts. Present tense. Quantify or omit ("up to 25 container types per tenant", not "many"). +``` diff --git a/docs/embedded/spe-docs-agent-ready/administration/adminrole.md b/docs/embedded/spe-docs-agent-ready/administration/adminrole.md new file mode 100644 index 000000000..02962c802 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/administration/adminrole.md @@ -0,0 +1,108 @@ +--- +title: SharePoint Embedded Administrator role +description: What the SharePoint Embedded Administrator role grants, how it differs from a SharePoint admin, and the tasks it enables in developer and consuming tenants. +ms.topic: concept-article +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: concept + difficulty: beginner + roles: [owning-admin, consuming-admin, m365-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + - capability: global-admin + api_surface: [] + next_steps: + - uri: /sharepoint/dev/embedded/administration/developer-admin/dev-admin + when: always + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + when: admin-consuming-tenant + related: + - uri: /sharepoint/dev/embedded/administration/developer-admin/dev-admin + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell + stability: ga + last_validated: proposed +--- + +# SharePoint Embedded Administrator role + + +## What it is + +The **SharePoint Embedded Administrator** is a dedicated Microsoft Entra / Microsoft 365 role for managing SharePoint Embedded container types and containers through [SharePoint PowerShell](https://learn.microsoft.com/powershell/module/sharepoint-online/connect-sposervice) and the SharePoint admin center. The role is required for [developer admins](/sharepoint/dev/embedded/administration/developer-admin/dev-admin) to create container types through PowerShell cmdlets, and for consuming tenant admins to manage containers created in their tenants. + +The role is available in both **Microsoft Entra** and the **Microsoft 365 admin center**. The **Global Administrator** role already has all the permissions of the SharePoint Embedded Administrator role; a Global Administrator can assign the role to a user so that user can act as a developer admin or a consuming tenant admin for SharePoint Embedded. + +> [!IMPORTANT] +> The SharePoint Embedded Administrator role does **not** have access to site management. A holder can't see the **Active sites** or **Deleted sites** pages in the SharePoint admin center and can't run site-specific PowerShell cmdlets. The role is scoped to SharePoint Embedded container types and containers only. + +## Why it matters / when to use + +Assign this role to grant SharePoint Embedded administration without granting full SharePoint or tenant administration. + +- Assign it to a **developer admin** who needs to create and manage container types and billing in the developer (owning) tenant. +- Assign it to a **consuming tenant admin** who needs to manage the containers created in their tenant. +- Prefer it over Global Administrator for least-privilege: it covers SharePoint Embedded tasks without the broad surface of Global Administrator and without SharePoint site management. + +## When NOT to use + +- Do not assign it when the user needs to manage SharePoint **sites** (active/deleted sites, site-specific cmdlets); it has no site-management access. Use a SharePoint or Global admin role for that. +- Do not assign a separate SharePoint Embedded Administrator role to an existing **Global Administrator**; that role already includes all SharePoint Embedded Administrator permissions. +- Do not rely on this role for Azure billing setup. Attaching a billing profile requires owner or contributor permissions on an **Azure subscription**, which is a separate authorization. See [Developer admin](/sharepoint/dev/embedded/administration/developer-admin/dev-admin#roles-and-permissions). + +## Key terms + +| Term | Meaning | +|---|---| +| SharePoint Embedded Administrator | Dedicated Entra / Microsoft 365 role for SharePoint Embedded container type and container management; no site-management access. | +| Global Administrator | Tenant-wide admin role that already includes all SharePoint Embedded Administrator permissions and can assign the role. | +| Developer (owning) tenant | The tenant where container types are created and standard billing is configured. | +| Consuming tenant | The tenant where a registered application's containers are created and managed. | +| Developer admin | A SharePoint Embedded Administrator (or Global Administrator) acting in the developer tenant. | +| Consuming tenant admin | A SharePoint Embedded Administrator (or Global/SharePoint Administrator) acting in a consuming tenant. | + +## How it fits together + +The same role label applies in two contexts, with different supported tasks depending on which tenant the holder operates in. + +### Tasks in the developer (owning) tenant + +A SharePoint Embedded Administrator in the developer tenant can, through PowerShell: + +- Create container types: + - Standard container type with standard billing. + - Standard container type with direct-to-customer (passthrough) billing. + - Trial container type. +- Manage container types: + - View container types in the developer tenant. + - Edit properties of a container type. + - Set configuration properties of a container type. + - Manage billing of applications / container types for standard billing. + +For the cmdlets, see [Developer admin](/sharepoint/dev/embedded/administration/developer-admin/dev-admin). + +### Tasks in the consuming tenant + +A SharePoint Embedded Administrator in a consuming tenant can, through PowerShell, perform application administration (get details of all SharePoint Embedded applications, get a specific application, get permissions of owning applications, configure external sharing of a container) and container administration (get details of all containers — including sorted by storage and archived — get a specific container, set the sensitivity label of a container, soft-delete a container, list soft-deleted containers, restore a soft-deleted container, and permanently delete a soft-deleted container). + +Through the SharePoint admin center, the same role can view the Active, Archived, and Deleted container pages and a container's details, and can archive an active container, reactivate an archived container, soft-delete a container, restore a deleted container, and purge a deleted container. + +For the consuming-tenant cmdlets and UX, see [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) and [Container management in PowerShell](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell). + +### Assigning the role + +A Global Administrator assigns the SharePoint Embedded Administrator role through either Microsoft Entra or the Microsoft 365 admin center. For the step-by-step assignment procedure, see [Developer admin — Assign the SharePoint Embedded Administrator role](/sharepoint/dev/embedded/administration/developer-admin/dev-admin#step-1). + +## Related + +- [Developer admin](/sharepoint/dev/embedded/administration/developer-admin/dev-admin) +- [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) +- [Container management in PowerShell](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell) +- [Pay-as-you-go billing](/sharepoint/dev/embedded/administration/billing/billing) +- [Connect-SPOService](https://learn.microsoft.com/powershell/module/sharepoint-online/connect-sposervice) diff --git a/docs/embedded/spe-docs-agent-ready/administration/billing/billing.md b/docs/embedded/spe-docs-agent-ready/administration/billing/billing.md new file mode 100644 index 000000000..fb222d391 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/administration/billing/billing.md @@ -0,0 +1,97 @@ +--- +title: Pay-as-you-go billing for SharePoint Embedded +description: How SharePoint Embedded meters consumption and the two billing models — standard and passthrough — that a container type can use. +ms.topic: concept-article +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: concept + difficulty: beginner + roles: [owning-admin, consuming-admin, app-developer, enterprise-developer] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + - capability: azure-subscription + api_surface: [] + next_steps: + - uri: /sharepoint/dev/embedded/administration/billing/billingmanagement + when: always + - uri: /sharepoint/dev/embedded/administration/billing/meters + when: always + related: + - uri: /sharepoint/dev/embedded/administration/billing/meters + - uri: /sharepoint/dev/embedded/administration/billing/billingmanagement + - uri: /sharepoint/dev/embedded/administration/developer-admin/dev-admin + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + stability: ga + last_validated: proposed +--- + +# Pay-as-you-go billing for SharePoint Embedded + + +## What it is + +SharePoint Embedded is a consumption-based, pay-as-you-go (PAYG) offering: you pay only for what you use, metered through an Azure subscription. Consumption is measured across four meters — storage, archived storage, API transactions, and egress. For the meter definitions, see [SharePoint Embedded meters](/sharepoint/dev/embedded/administration/billing/meters). + +Each container type carries one of two **billing models**, chosen when the container type is created. The billing model determines which tenant is charged for the consumption that the container type's application generates. + +| Billing model | Also called | Who is charged | Who sets up the billing profile | +|---|---|---|---| +| Standard | — | The developer (owning) tenant that creates and owns the application | Developer admin, in the owning tenant | +| Passthrough | Direct-to-customer (`directToCustomer`) | The consuming tenant registered to use the application | Consuming tenant admin (SharePoint admin or Global admin), in the consuming tenant | + +> [!IMPORTANT] +> Once a container type is created, its billing model can't be changed. To change the billing model, create a new container type with the desired model. + +## Why it matters / when to use + +Choose a billing model to match who bears the storage and transaction cost of your application. + +- **Standard billing** centralizes all consumption charges on the developer tenant. After creating the container type, the developer admin must establish a valid billing profile before the container type can be used. That profile is charged for all consumption incurred by every consuming tenant that uses the application associated with the container type. Use standard billing when the ISV absorbs storage cost (for example, a SaaS product with usage priced into the subscription). To set up the profile, see [set the billing profile](/sharepoint/dev/embedded/getting-started/containertypes#set-the-billing-profile). +- **Passthrough billing** charges each consuming tenant directly for its own consumption. The developer admin does **not** set up a billing profile for a passthrough container type. After the container type is registered in a consuming tenant, the consuming tenant admin sets up the billing profile there. Use passthrough billing when each customer pays for their own storage and transactions. + +Both billing models use the same four meters. See [SharePoint Embedded meters](/sharepoint/dev/embedded/administration/billing/meters). + +## When NOT to use + +- Do not expect to defer billing setup for a **standard** container type. The container type can't be used until a valid billing profile exists in the developer tenant. +- Do not use a **trial** container type for production. Trial container types exist to evaluate SharePoint Embedded and expire after 30 days; they are not a billing model and don't carry production consumption guarantees. See [creating container types](/sharepoint/dev/embedded/getting-started/containertypes#creating-container-types). +- Do not attempt to switch an existing container type's billing model. Create a new container type instead. + +## Key terms + +| Term | Meaning | +|---|---| +| Pay-as-you-go (PAYG) | Consumption-based pricing metered through an Azure subscription; you pay only for what you use. | +| Standard billing | All consumption-based charges are billed to the developer (owning) tenant. | +| Passthrough billing | Consumption-based charges are billed to the consuming tenant; also called direct-to-customer billing. | +| `billingClassification` | The container type property set to `directToCustomer` for passthrough billing. | +| Billing profile | The Azure subscription association that consumption charges are billed against. | +| Container type | The 1:1-with-app definition that carries the billing model. Up to 25 standard container types per owning tenant. | +| Meter | A unit of metered consumption: storage, archived storage, API transactions, or egress. | + +## How it fits together + +In the **owning (developer) tenant**, the developer admin creates a container type and selects its billing model. For **standard** billing, the same admin attaches a billing profile backed by an Azure subscription on which they hold owner or contributor permissions; that profile is charged for all downstream consumption. For **passthrough** billing, the developer admin sets `billingClassification` to `directToCustomer` and attaches no profile. + +In each **consuming tenant**, the container type is registered and containers are created and used. For a **passthrough** container type, the consuming tenant admin sets up a billing profile in the consuming tenant before the application can be used there; that profile is charged for the consuming tenant's own consumption. See the [setup guide in the consuming tenant admin center](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta#set-up-billing-for-passthrough-container-type). + +You can read billing properties of a standard container type with the `fileStorageContainerType` APIs — [list container types](https://learn.microsoft.com/graph/api/filestorage-list-containertypes) and [get container type](https://learn.microsoft.com/graph/api/filestoragecontainertype-get). To create or update the billing profile, see [Billing management](/sharepoint/dev/embedded/administration/billing/billingmanagement) and [Developer admin](/sharepoint/dev/embedded/administration/developer-admin/dev-admin). + +> [!NOTE] +> Setting up the billing profile for a standard container type has no Microsoft Graph API today; it is done through the SharePoint Online Management Shell. See [Billing management](/sharepoint/dev/embedded/administration/billing/billingmanagement) and api-surface.json gap `setUpContainerTypeBilling`. + +## Related + +- [SharePoint Embedded meters](/sharepoint/dev/embedded/administration/billing/meters) +- [Billing management](/sharepoint/dev/embedded/administration/billing/billingmanagement) +- [Developer admin](/sharepoint/dev/embedded/administration/developer-admin/dev-admin) +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) +- [SharePoint Embedded product page (pricing)](https://adoption.microsoft.com/en-us/sharepoint/embedded/) diff --git a/docs/embedded/spe-docs-agent-ready/administration/billing/billingmanagement.md b/docs/embedded/spe-docs-agent-ready/administration/billing/billingmanagement.md new file mode 100644 index 000000000..3d5b53bbe --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/administration/billing/billingmanagement.md @@ -0,0 +1,181 @@ +--- +title: View SharePoint Embedded consumption in Microsoft Cost Management +description: Track SharePoint Embedded pay-as-you-go costs by app, tenant, and container type using Microsoft Cost Management in the Azure portal. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: The reader can view, filter, and forecast SharePoint Embedded consumption costs in Microsoft Cost Management and set budget alerts. + estimated_minutes: 20 + difficulty: beginner + roles: [owning-admin, consuming-admin, m365-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/administration/billing/billing + kind: concept + - uri: /sharepoint/dev/embedded/administration/billing/meters + kind: reference + - capability: azure-subscription + api_surface: [] + inputs: + - name: azure-subscription-id + type: uuid + source: user-supplied + - name: budget-amount + type: string + source: user-supplied + outputs: + - name: cost-analysis-view + type: string + verify: Cost analysis in Microsoft Cost Management shows SharePoint Embedded meter costs filtered by app ID, tenant ID, or container type ID + - name: budget-alert + type: string + verify: A budget with at least one alert threshold exists in Cost Management for the subscription + next_steps: + - uri: /sharepoint/dev/embedded/administration/billing/meters + when: always + - uri: /sharepoint/dev/embedded/administration/developer-admin/dev-admin + when: always + related: + - uri: /sharepoint/dev/embedded/administration/billing/billing + - uri: /sharepoint/dev/embedded/administration/billing/meters + - uri: /sharepoint/dev/embedded/administration/developer-admin/dev-admin + stability: ga + last_validated: proposed +--- + +# View SharePoint Embedded consumption in Microsoft Cost Management + + +At the end of this task you can see SharePoint Embedded pay-as-you-go costs in Microsoft Cost Management, broken down by SharePoint Embedded meters and filtered by app ID, tenant ID, or container type ID, and you have a budget with at least one spending alert. + +> [!NOTE] +> Microsoft Cost Management is a portal and Cost Management REST experience; SharePoint Embedded exposes no Graph API for reading consumption. The steps below are portal actions captured in `manual:` blocks. There is no api-surface.json operation for this workflow. + +## Prerequisites + +- [Pay-as-you-go billing](/sharepoint/dev/embedded/administration/billing/billing) — to know which billing model (standard or passthrough) determines who is charged. +- [SharePoint Embedded meters](/sharepoint/dev/embedded/administration/billing/meters) — to interpret the storage, archived storage, API transaction, and egress lines. +- Capability: an Azure subscription with a SharePoint Embedded billing profile attached, and an account with read access to that subscription's costs (for example, a Billing reader or subscription Reader role). + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{azure-subscription-id}` | uuid | The Azure subscription attached to the container type's billing profile (user-supplied) | +| `{budget-amount}` | string | The monthly spending cap you want to track against (user-supplied) | + +## Steps + +### Step 1 — Open Microsoft Cost Management for your subscription {#step-1} + +Sign in to the Azure portal and open Cost Management scoped to the subscription that carries SharePoint Embedded consumption. + +```yaml +manual: + description: Open Cost Management + Billing in the Azure portal and select the subscription with SharePoint Embedded consumption. + ui_path: https://portal.azure.com → Cost Management + Billing → Billing scopes / Subscriptions → select {azure-subscription-id} + api_equivalent: none — no Graph API; Cost Management exposes a separate Azure REST API (Microsoft.CostManagement). See api-surface.json (no SPE operation for consumption reads). + verify: + ui_path: The subscription Overview page loads and shows current spend, forecasted cost, and any spending anomalies for {azure-subscription-id}. +``` + +**Expected response:** the subscription **Overview** page renders with current spending, forecasted costs, and any spending anomalies. + +**On failure:** +- Subscription not listed → the signed-in account lacks a cost role on `{azure-subscription-id}`, or the wrong directory is selected. Switch directory or request a Billing reader / Reader assignment. +- No SharePoint Embedded costs shown → no billing profile is attached to the container type, or no consumption has been metered yet. Confirm billing setup in [Developer admin](/sharepoint/dev/embedded/administration/developer-admin/dev-admin). + +### Step 2 — Break down cost by SharePoint Embedded meter and tag {#step-2} + +Open **Cost analysis** and filter to isolate SharePoint Embedded consumption by meter and by SharePoint Embedded tags. + +```yaml +manual: + description: In Cost analysis, set the date range and group/filter SharePoint Embedded costs by meter and by app ID, tenant ID, or container type ID. + ui_path: Cost Management + Billing → (subscription {azure-subscription-id}) → Cost Management → Cost analysis → set date range → Filter/Group by → Meter, and by tag (app ID, tenant ID, container type ID) + api_equivalent: none — Cost Management query is the Azure REST API Query - Usage (Microsoft.CostManagement); not part of the SPE Graph surface. + verify: + ui_path: Cost analysis displays SharePoint Embedded meter rows (Storage, Archived Storage, API Transactions, Egress) and the chart updates when filtered by app ID, tenant ID, or container type ID. +``` + +**Expected response:** Cost analysis shows SharePoint Embedded meter rows (storage, archived storage, API transactions, egress); filtering by tag (app ID, tenant ID, or container type ID) updates the chart. + +**On failure:** +- No meter rows appear → the date range predates any consumption, or filters exclude all rows. Widen the date range and clear filters. +- Tag filter empty → tags propagate after consumption is metered and may lag. Re-check after the next metering cycle. See [SharePoint Embedded meters](/sharepoint/dev/embedded/administration/billing/meters). + +### Step 3 — Download invoices {#step-3} + +Retrieve invoices for any billing period from the **Invoices** section under Billing. + +```yaml +manual: + description: View and download SharePoint Embedded invoices for a billing period. + ui_path: Cost Management + Billing → Billing → Invoices → select billing period → Download + api_equivalent: none — invoice retrieval is the Azure REST API Invoices (Microsoft.Billing); not part of the SPE Graph surface. + verify: + ui_path: The selected billing period's invoice downloads as a PDF. +``` + +**Expected response:** the invoice for the selected billing period downloads. + +**On failure:** +- Invoices section empty or hidden → the account lacks an invoice-capable billing role (for example, Billing reader). Request the role on the billing account. + +### Step 4 — Create a budget and spending alerts {#step-4} + +Create a budget so spending against `{azure-subscription-id}` triggers alerts before it exceeds `{budget-amount}`. + +```yaml +manual: + description: Create a Cost Management budget for the subscription and add at least one alert threshold. + ui_path: Cost Management + Billing → Cost Management → Budgets → Add → set amount {budget-amount} and time period → add alert conditions (for example, 80% and 100%) → Create + api_equivalent: none — budget creation is the Azure REST API Budgets - Create Or Update (Microsoft.Consumption); not part of the SPE Graph surface. + verify: + ui_path: The new budget appears in the Budgets list for {azure-subscription-id} with at least one alert threshold. +``` + +**Expected response:** the new budget appears in the **Budgets** list with at least one alert threshold configured. + +**On failure:** +- Save blocked → the account lacks Cost Management Contributor on the scope. Request the role. +- Alerts never fire → no notification recipients were set on the budget. Edit the budget and add alert recipients. + +## Verify {#verify} + +```yaml +manual: + description: Confirm SharePoint Embedded consumption is visible and a budget alert is in place. + ui_path: Cost Management → Cost analysis (SPE meters visible, filterable by app/tenant/container type) AND Cost Management → Budgets (a budget with ≥1 alert exists for {azure-subscription-id}) + api_equivalent: none — see api-surface.json (no SPE consumption-read operation) + verify: + ui_path: Both views render as described. +``` + +Cost analysis shows the four SharePoint Embedded meters and a budget with at least one alert exists for the subscription. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| Subscription not visible in Cost Management | Wrong Entra directory, or no cost role on the subscription | Switch directory; request Billing reader or Reader on `{azure-subscription-id}` | +| No SharePoint Embedded meter rows | No billing profile attached, or no consumption yet | Confirm billing setup in [Developer admin](/sharepoint/dev/embedded/administration/developer-admin/dev-admin); widen the date range | +| Tag filter (app/tenant/container type ID) returns nothing | Tags propagate after metering and can lag | Re-check after the next metering cycle | +| Budget save fails | Missing Cost Management Contributor on the scope | Request the role, then retry | +| Costs lower than expected | Exempt transactions/egress (eDiscovery, admin actions, Office/WAC downloads) aren't billed | Confirm against [meter exemptions](/sharepoint/dev/embedded/administration/billing/meters#api-transaction-exemptions) | + +## Next steps + +- [SharePoint Embedded meters](/sharepoint/dev/embedded/administration/billing/meters) +- [Developer admin](/sharepoint/dev/embedded/administration/developer-admin/dev-admin) + +## Related + +- [Pay-as-you-go billing](/sharepoint/dev/embedded/administration/billing/billing) +- [SharePoint Embedded meters](/sharepoint/dev/embedded/administration/billing/meters) +- [Microsoft Cost Management](https://ms.portal.azure.com/) diff --git a/docs/embedded/spe-docs-agent-ready/administration/billing/meters.md b/docs/embedded/spe-docs-agent-ready/administration/billing/meters.md new file mode 100644 index 000000000..9f9d706e0 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/administration/billing/meters.md @@ -0,0 +1,92 @@ +--- +title: SharePoint Embedded billing meters +description: Reference for the four SharePoint Embedded pay-as-you-go meters — storage, archived storage, API transactions, and egress — plus their exemptions. +ms.topic: reference +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: reference + difficulty: beginner + roles: [owning-admin, consuming-admin, app-developer, enterprise-developer] + prerequisites: + - uri: /sharepoint/dev/embedded/administration/billing/billing + kind: concept + api_surface: [] + next_steps: + - uri: /sharepoint/dev/embedded/administration/billing/billingmanagement + when: always + related: + - uri: /sharepoint/dev/embedded/administration/billing/billing + - uri: /sharepoint/dev/embedded/administration/billing/billingmanagement + stability: ga + last_validated: proposed +--- + +# SharePoint Embedded billing meters + + +SharePoint Embedded uses a pay-as-you-go (PAYG) billing model through an Azure subscription. Billing is determined by how much data (in GB) you store in active and archived states, the transactions used to access and modify containers and their contents, and the data egressed from the SharePoint Embedded platform. You can view usage and billing details in [Azure Cost Management](https://ms.portal.azure.com/). Both standard billing and passthrough billing container types use the same meters. + +SharePoint Embedded has four billing meters. For pricing details, see the [product page](https://adoption.microsoft.com/en-us/sharepoint/embedded/). + +## Meters + +| Meter | Unit | What it measures | +|---|---|---| +| Storage | GB | Storage used by files and documents along with their metadata and versions, including all content in the recycle bin and the deleted container collection. | +| Archived storage | GB | Storage consumed by archived containers within a tenant. Archiving moves data to the cold storage tier, which has lower storage cost than active storage. | +| API transactions | transaction (count) | Each Microsoft Graph call made explicitly by the SharePoint Embedded application counts as one transaction. | +| Egress | GB | Total volume of data transferred out of the SharePoint Embedded platform (for example, a document downloaded to a client device, or data transferred to a customer-operated server). | + +> [!NOTE] +> Rates are not published in this article. For the per-unit price of each meter, see the [SharePoint Embedded product page](https://adoption.microsoft.com/en-us/sharepoint/embedded/). + +## API transaction exemptions + +Each Microsoft Graph call made explicitly by the application is a billable transaction. See [examples of Microsoft Graph calls](https://learn.microsoft.com/graph/api/resources/filestoragecontainer) a SharePoint Embedded application can make. Calls made by internal services to containers, which the application has no control over, are **not** charged. + +| Exempt transaction | Why exempt | +|---|---| +| Queries by the eDiscovery service searching container content for compliance or legal purposes | Internal service call; not initiated by the application | +| Admin actions by the SharePoint Embedded admin or Global admin on containers through SharePoint admin center or SPO PowerShell | Administrative action; not an application Graph call | + +## Egress exemptions + +Egress is charged on the total volume of data transferred out of SharePoint Embedded, measured in GB. Certain transfers within integrated Microsoft services are exempt. + +| Exempt transfer | Why exempt | +|---|---| +| File downloads from the application server to the customer's Office desktop client | Transfer within integrated Microsoft services | +| File downloads from the application server to the Web Application Companion (WAC) | Transfer within integrated Microsoft services | + +## Pay-as-you-go message meter (private preview) + +> [!IMPORTANT] +> This meter is in **private preview**. The meter, rate, and message counts may change before general availability. + +SharePoint Embedded agents use the Copilot Studio meter. A **message** is the unit that measures agent usage. + +| Item | Value | +|---|---| +| Rate | $0.01 per message | +| Messages per agent interaction | 12 (2 for the generative answer feature + 10 for the tenant graph grounding feature) | +| Cost per agent interaction | $0.12 | + +## Examples + +- **Active storage growth.** A tenant stores 500 GB of active container content plus versions and recycle-bin items. All 500 GB is billed on the **Storage** meter. +- **Archival savings.** Moving 200 GB of inactive containers to the archive tier shifts that 200 GB from the **Storage** meter to the lower-cost **Archived storage** meter. +- **Application read.** The application calls `GET /storage/fileStorage/containers/{container-id}` to read a container. That one Graph call is billed as one **API transaction**. +- **Compliance query (exempt).** An eDiscovery search across container content is an internal service call and is **not** billed on the API transactions meter. +- **Client download (exempt).** A user opens a document in the Office desktop client; the download from the application server to that client is **not** billed on the **Egress** meter. + +## See also + +- [Pay-as-you-go billing for SharePoint Embedded](/sharepoint/dev/embedded/administration/billing/billing) +- [Billing management](/sharepoint/dev/embedded/administration/billing/billingmanagement) +- [SharePoint Embedded product page (pricing)](https://adoption.microsoft.com/en-us/sharepoint/embedded/) +- [fileStorageContainer Graph resource](https://learn.microsoft.com/graph/api/resources/filestoragecontainer) diff --git a/docs/embedded/spe-docs-agent-ready/administration/consuming-tenant-admin/cta.md b/docs/embedded/spe-docs-agent-ready/administration/consuming-tenant-admin/cta.md new file mode 100644 index 000000000..ed9bdea52 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/administration/consuming-tenant-admin/cta.md @@ -0,0 +1,108 @@ +--- +title: Consuming tenant admin for SharePoint Embedded +description: The consuming tenant admin role governs SharePoint Embedded apps and containers on a Microsoft 365 tenant via PowerShell, the SharePoint admin center, and Graph. +ms.topic: concept-article +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: concept + difficulty: intermediate + roles: [consuming-admin, m365-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + - capability: spe-admin + api_surface: + - id: listContainerTypeRegistrations + method: GET + path: /storage/fileStorage/containerTypeRegistrations + permissions: [FileStorageContainerTypeReg.Manage.All] + next_steps: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell + when: always + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaux + when: always + - uri: /sharepoint/dev/embedded/compliance/security-and-compliance + when: govern-content + related: + - uri: /sharepoint/dev/embedded/administration/adminrole + - uri: /sharepoint/dev/embedded/administration/billing/meters + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + stability: ga + last_validated: proposed +--- + +# Consuming tenant admin for SharePoint Embedded + + +## What it is + +A **consuming tenant** is a Microsoft 365 tenant that has one or more SharePoint Embedded (SPE) applications installed on it. The **consuming tenant administrator (CTA)** is the persona responsible for managing those applications and the containers that hold their content on that tenant. + +The CTA role is filled by the **SharePoint Embedded Administrator** role (available in both Microsoft Entra ID and the Microsoft 365 admin center). A Global Administrator can assign this role to a user; the Global Administrator role already includes every permission the SharePoint Embedded Administrator role grants. + +> [!IMPORTANT] +> A user must hold the SharePoint Embedded Administrator role (or Global Administrator) to run the SharePoint Embedded container cmdlets and to see the container pages in the SharePoint admin center. See [SharePoint Embedded admin role](/sharepoint/dev/embedded/administration/adminrole). + +## Why it matters / when to use + +The CTA is the tenant's control point for every SPE app another organization (or Microsoft) has installed. The role exists so that the tenant — not the app vendor — retains governance over content stored on its own Microsoft 365 tenancy. A CTA uses the role to: + +- Enumerate every SPE application registered on the tenant and the containers each one holds. +- Inspect a container's storage, ownership, owners, and sensitivity label. +- Apply tenant-level governance: sensitivity labels, external sharing capability, and membership (Owner, Manager, Writer, Reader roles). +- Manage container lifecycle: archive, reactivate, soft-delete, restore, and permanently delete. +- Ensure content meets the organization's business and compliance policies. + +Three administration surfaces are available, each documented separately: + +| Surface | Use it for | Page | +|---|---|---| +| Microsoft Graph | Container type registration management (list, get, update, delete) | [Graph reference](https://learn.microsoft.com/graph/api/resources/filestoragecontainertyperegistration) | +| SharePoint Online Management Shell (PowerShell) | Scripted enumeration, sensitivity labels, sharing capability, and container lifecycle | [Container management in PowerShell](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell) | +| SharePoint admin center (SPAC) | Point-and-click container lifecycle, membership, sorting, and filtering | [Manage containers in the SharePoint admin center](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaux) | + +## When NOT to use + +- **You own the application and container type.** Container type creation, billing classification, and owning-tenant configuration belong to the developer/owning admin, not the CTA. See [SharePoint Embedded admin overview](/sharepoint/dev/embedded/administration/adminrole). +- **You are applying compliance policies (eDiscovery, retention, DLP).** Those are configured by a compliance officer in the Microsoft Purview portal, not through the CTA container surfaces. See [Security and compliance](/sharepoint/dev/embedded/compliance/security-and-compliance). +- **You are creating, reading, or writing file content programmatically.** That is the app's content-plane work through Graph `driveItem` APIs, not a CTA task. + +## Key terms + +| Term | Meaning | +|---|---| +| Consuming tenant | A Microsoft 365 tenant where one or more SPE applications are installed and their containers are stored. | +| Consuming tenant admin (CTA) | The persona — backed by the SharePoint Embedded Administrator role — that governs SPE apps and containers on a consuming tenant. | +| SharePoint Embedded Administrator | The Entra/Microsoft 365 role that grants CTA capabilities. A subset of Global Administrator. | +| Container type registration | The `fileStorageContainerTypeRegistration` resource representing a container type's registration on the consuming tenant. Managed with the `FileStorageContainerTypeReg.Manage.All` delegated permission. | +| Active / Archived / Deleted container | The three lifecycle collections a CTA can view and act on. Deleted containers are purged after 93 days unless a retention policy applies. | +| Passthrough (direct-to-customer) billing | A billing classification where the consuming tenant pays for SPE consumption directly through its own Azure subscription via Microsoft Syntex billing. | + +## How it fits together + +SharePoint Embedded separates a **control plane** (container types, registrations, consent, billing) from a **content plane** (containers and their `driveItem` files). The CTA operates almost entirely on the consuming tenant's side of this split: + +- **Owning tenant** — the app vendor (or enterprise developer) creates the container type and sets its billing classification. This is *not* CTA work. +- **Consuming tenant** — the app is installed, the container type is registered, containers are created, and content is stored. The CTA governs everything here: the registration (`fileStorageContainerTypeRegistration`), container lifecycle, membership, sensitivity labels, and sharing capability. + +Storage, the actual files, and the Microsoft Purview compliance that governs them all live in the consuming tenant — which is why governance is a CTA and compliance-officer responsibility on that tenant, not the vendor's. + +For passthrough (direct-to-customer) apps, the CTA must also set up Microsoft Syntex billing in the [Microsoft 365 admin center](https://admin.microsoft.com/) before any user can access the app. No Graph API exists for this step today; see api-surface.json gap `activateConsumingTenantPayg`. For the billing meters that apply, see [Meters](/sharepoint/dev/embedded/administration/billing/meters). + +> [!WARNING] +> If you turn off SharePoint Embedded or disconnect the linked Azure subscription, all users immediately lose access to every application built on the service, along with their read and write permissions. + +## Related + +- [SharePoint Embedded admin role](/sharepoint/dev/embedded/administration/adminrole) +- [Container management in PowerShell](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell) +- [Manage containers in the SharePoint admin center](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaux) +- [Security and compliance](/sharepoint/dev/embedded/compliance/security-and-compliance) +- [Billing meters](/sharepoint/dev/embedded/administration/billing/meters) +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) diff --git a/docs/embedded/spe-docs-agent-ready/administration/consuming-tenant-admin/ctapowershell.md b/docs/embedded/spe-docs-agent-ready/administration/consuming-tenant-admin/ctapowershell.md new file mode 100644 index 000000000..2df22ad33 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/administration/consuming-tenant-admin/ctapowershell.md @@ -0,0 +1,185 @@ +--- +title: SharePoint Embedded container management cmdlets (PowerShell) +description: Reference for the SharePoint Online Management Shell cmdlets a consuming tenant admin uses to manage SharePoint Embedded apps and containers. +ms.topic: reference +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: reference + difficulty: intermediate + roles: [consuming-admin, m365-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + kind: concept + - capability: spe-admin + api_surface: + - id: listContainers + method: GET + path: /storage/fileStorage/containers?$filter=containerTypeId eq {container-type-id} + permissions: [FileStorageContainer.Selected] + - id: getContainer + method: GET + path: /storage/fileStorage/containers/{container-id} + permissions: [FileStorageContainer.Selected] + - id: updateContainer + method: PATCH + path: /storage/fileStorage/containers/{container-id} + permissions: [FileStorageContainer.Selected] + - id: deleteContainer + method: DELETE + path: /storage/fileStorage/containers/{container-id} + permissions: [FileStorageContainer.Selected] + - id: restoreDeletedContainer + method: POST + path: /storage/fileStorage/deletedContainers/{container-id}/restore + permissions: [FileStorageContainer.Selected] + - id: permanentDeleteContainer + method: POST + path: /storage/fileStorage/containers/{container-id}/permanentDelete + permissions: [FileStorageContainer.Selected] + inputs: + - name: owning-application-id + type: uuid + source: user-supplied + - name: application-id + type: uuid + source: user-supplied + - name: container-id + type: string + source: prior-step + - name: container-site-url + type: uri + source: prior-step + - name: sensitivity-label + type: string + source: user-supplied + - name: sharing-capability + type: enum + source: user-supplied + next_steps: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaux + when: always + - uri: /sharepoint/dev/embedded/compliance/security-and-compliance + when: govern-content + related: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + - uri: /sharepoint/dev/embedded/administration/adminrole + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + stability: ga + last_validated: proposed +--- + +# SharePoint Embedded container management cmdlets (PowerShell) + + +This page tabulates the SharePoint Online Management Shell cmdlets a consuming tenant admin (CTA) uses to enumerate and govern SharePoint Embedded applications and containers. To run these cmdlets, the caller must hold the **SharePoint Embedded Administrator** role (or Global Administrator); see [SharePoint Embedded admin role](/sharepoint/dev/embedded/administration/adminrole). + +> [!IMPORTANT] +> Use the latest version of the [SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588) to access the container administration cmdlets. Connect first with [`Connect-SPOService`](https://learn.microsoft.com/powershell/module/sharepoint-online/connect-sposervice). + +> [!NOTE] +> The cmdlets in this reference have **no Graph API equivalent today** for application-scoped enumeration and sharing capability. The container lifecycle cmdlets map to the Graph operations listed in `agent.api_surface` (`listContainers`, `getContainer`, `deleteContainer`, `restoreDeletedContainer`, `permanentDeleteContainer`). Use the Graph equivalents for unattended automation where one exists. + +## Connect + +| Cmdlet | Parameters | Description | +|---|---|---| +| `Connect-SPOService` | `-Url ` | Connect the shell to your SharePoint admin endpoint before running any container cmdlet. | + +```pwsh +Connect-SPOService -Url "https://{tenant}-admin.sharepoint.com" +``` + +## Application administration cmdlets + +| Cmdlet | Parameters | Description | +|---|---|---| +| `Get-SPOApplication` | *(none)* | List every SharePoint Embedded application registered in the tenant. | +| `Get-SPOApplication` | `-OwningApplicationId ` | Get the details of one SharePoint Embedded application. | +| `Get-SPOApplication` | `-OwningApplicationId ` `-ApplicationId ` | View the guest application permissions for a guest application that has access to the SPE application. Does not apply to Microsoft Loop. | +| `Set-SPOApplication` | `-OwningApplicationId ` `-SharingCapability ` `-OverrideTenantSharingCapability <$true \| $false>` | Set the external sharing capability for all containers of the application. | +| `Set-SPOApplicationPermission` | `-OwningApplicationId ` `-ApplicationId ` `-PermissionAppOnly ` `-PermissionDelegated ` | Add, edit, or remove guest application access to an SPE application. A guest application is any application within the enterprise applications of the owning tenant. | + +`{sharing-capability}` accepts one of: `Disabled`, `ExistingExternalUserSharingOnly`, `ExternalUserSharingOnly`, `ExternalUserAndGuestSharing`. + +## Container administration cmdlets + +| Cmdlet | Parameters | Description | +|---|---|---| +| `Get-SPOContainer` | `-OwningApplicationId ` | List all active containers of an application. | +| `Get-SPOContainer` | `-OwningApplicationId ` `-ArchiveStatus Archived` | List all archived containers of an application. | +| `Get-SPOContainer` | `-OwningApplicationId ` `-SortByStorage ` | List containers of an application sorted by storage. | +| `Get-SPOContainer` | `-Identity ` *or* `-Identity ` | Get the details of one container: `StorageUsed`, ownership, `SiteURL`, label, owner count, and more. | +| `Set-SPOContainer` | `-Identity ` `-SensitivityLabel ` | Set the sensitivity label on a container. | +| `Set-SPOContainer` | `-Identity ` `-RemoveLabel` | Remove the sensitivity label from a container. | +| `Remove-SPOContainer` | `-Identity ` | Soft-delete a container (moves it to the deleted container collection). | +| `Get-SPODeletedContainer` | *(none)* | List all soft-deleted containers in the deleted container collection. | +| `Restore-SPODeletedContainer` | `-Identity ` | Restore a soft-deleted container. If it was archived at deletion, it is restored to the archived state. | +| `Remove-SPODeletedContainer` | `-Identity ` | Permanently delete a soft-deleted container (only if no retention policy applies). | + +> [!NOTE] +> To enumerate Microsoft Loop containers, use the owning app ID `a187e399-0c36-4b98-8f04-1edc167a0996` for all container administration cmdlets. + +> [!WARNING] +> Deleting a container removes all its content and may break the SharePoint Embedded application it belongs to: data loss, broken links, and permission failures. Notify container owners before deletion. A deleted container can be restored from the deleted container collection within **93 days**; after that, or after explicit purge, it is permanently deleted and cannot be recovered. + +## Examples + +### List every SPE application, then its active containers + +```pwsh +Get-SPOApplication +Get-SPOContainer -OwningApplicationId "{owning-application-id}" | Format-Table +``` + +### List archived containers, sorted largest-first + +```pwsh +Get-SPOContainer -OwningApplicationId "{owning-application-id}" -ArchiveStatus Archived | Format-Table +Get-SPOContainer -OwningApplicationId "{owning-application-id}" -SortByStorage Descending | Format-Table +``` + +### Inspect one container by ID or by site URL + +```pwsh +Get-SPOContainer -Identity "{container-id}" +Get-SPOContainer -Identity "{container-site-url}" +``` + +### Set, then remove, a sensitivity label + +```pwsh +Set-SPOContainer -Identity "{container-id}" -SensitivityLabel "{sensitivity-label}" +Set-SPOContainer -Identity "{container-id}" -RemoveLabel +``` + +### Restrict external sharing on an application's containers + +```pwsh +Set-SPOApplication -OwningApplicationId "{owning-application-id}" -SharingCapability "Disabled" -OverrideTenantSharingCapability $true +``` + +### Soft-delete, list, restore, then permanently delete + +```pwsh +Remove-SPOContainer -Identity "{container-id}" +Get-SPODeletedContainer +Restore-SPODeletedContainer -Identity "{container-id}" +Remove-SPODeletedContainer -Identity "{container-id}" +``` + +## See also + +- [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) +- [Manage containers in the SharePoint admin center](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaux) +- [Security and compliance](/sharepoint/dev/embedded/compliance/security-and-compliance) +- [SharePoint Embedded admin role](/sharepoint/dev/embedded/administration/adminrole) +- [Get-SPOContainer cmdlet](https://learn.microsoft.com/powershell/module/sharepoint-online/get-spocontainer) +- [Get-SPOApplication cmdlet](https://learn.microsoft.com/powershell/module/sharepoint-online/get-spoapplication) +- [Remove-SPOContainer cmdlet](https://learn.microsoft.com/powershell/module/sharepoint-online/remove-spocontainer) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/administration/consuming-tenant-admin/ctaux.md b/docs/embedded/spe-docs-agent-ready/administration/consuming-tenant-admin/ctaux.md new file mode 100644 index 000000000..78991a804 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/administration/consuming-tenant-admin/ctaux.md @@ -0,0 +1,317 @@ +--- +title: Manage SharePoint Embedded containers in the SharePoint admin center +description: Archive, reactivate, delete, restore, label, and manage membership of SharePoint Embedded containers from the SharePoint admin center UI. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: how-to + outcome: A consuming tenant admin has located, governed, and lifecycle-managed SharePoint Embedded containers (archive, reactivate, delete, restore, label, membership) from the SharePoint admin center. + estimated_minutes: 15 + difficulty: intermediate + roles: [consuming-admin, m365-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + kind: concept + - capability: spe-admin + api_surface: + - id: listContainers + method: GET + path: /storage/fileStorage/containers?$filter=containerTypeId eq {container-type-id} + permissions: [FileStorageContainer.Selected] + - id: getContainer + method: GET + path: /storage/fileStorage/containers/{container-id} + permissions: [FileStorageContainer.Selected] + - id: deleteContainer + method: DELETE + path: /storage/fileStorage/containers/{container-id} + permissions: [FileStorageContainer.Selected] + - id: restoreDeletedContainer + method: POST + path: /storage/fileStorage/deletedContainers/{container-id}/restore + permissions: [FileStorageContainer.Selected] + - id: permanentDeleteContainer + method: POST + path: /storage/fileStorage/containers/{container-id}/permanentDelete + permissions: [FileStorageContainer.Selected] + - id: updateContainer + method: PATCH + path: /storage/fileStorage/containers/{container-id} + permissions: [FileStorageContainer.Selected] + - id: addContainerPermission + method: POST + path: /storage/fileStorage/containers/{container-id}/permissions + permissions: [FileStorageContainer.Selected] + inputs: + - name: container-id + type: string + source: prior-step + - name: container-name + type: string + source: user-supplied + - name: sensitivity-label + type: string + source: user-supplied + - name: principal-upn + type: string + source: user-supplied + outputs: + - name: container-id + type: string + verify: GET /storage/fileStorage/containers/{container-id} returns 200 with the expected status + next_steps: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell + when: always + - uri: /sharepoint/dev/embedded/compliance/security-and-compliance + when: govern-content + related: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + - uri: /sharepoint/dev/embedded/administration/adminrole + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + stability: ga + last_validated: proposed +--- + +# Manage SharePoint Embedded containers in the SharePoint admin center + + +By the end, a consuming tenant admin (CTA) has located SharePoint Embedded containers in the SharePoint admin center (SPAC) and run the full lifecycle and governance set against them — archive, reactivate, delete, restore, permanently delete, sensitivity labeling, and membership — using the portal UI. The SPAC actions are point-and-click only; each step lists the Microsoft Graph or PowerShell equivalent for unattended automation and a verify call. + +> [!NOTE] +> The container pages in the SharePoint admin center have no public Graph API. Each step uses a `manual:` block carrying the UI path plus the closest API equivalent for automation. The CTA must hold the **SharePoint Embedded Administrator** role; that role sees only the **Active containers** and **Deleted containers** pages, whereas a Global Administrator also sees the global admin views. + +## Prerequisites + +- [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) — what the CTA role is and which surfaces it covers. +- Capability: `spe-admin` — the SharePoint Embedded Administrator role (or Global Administrator), assigned by a Global Administrator in the [Microsoft 365 admin center](https://admin.microsoft.com/) or Microsoft Entra ID. See [SharePoint Embedded admin role](/sharepoint/dev/embedded/administration/adminrole). + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{container-id}` | string | The container row selected on the Active, Archived, or Deleted containers page | +| `{container-name}` | string | The container name shown in the grid; used for search | +| `{sensitivity-label}` | string | A sensitivity label published to the tenant | +| `{principal-upn}` | string | The user to add or reassign in the membership panel | + +## Steps + +### Step 1 — Open the containers pages and read container metadata {#step-1} + +The Active containers page lists every active container in the tenant with its name, application name, publisher, ownership type, principal owner, storage, owners, owner count, sensitivity label, and creation date. Archived and Deleted pages show parallel collections (Deleted adds a **Deleted on** date). Use search (by container name on the Active page), sorting (Storage, Created on; Deleted on adds for the Deleted page), and filtering (application name, publisher, ownership type, principal owner, owner count, created on) to find a container. + +```yaml +manual: + description: View active, archived, and deleted SharePoint Embedded containers and their metadata. + ui_path: SharePoint admin center (https://go.microsoft.com/fwlink/?linkid=2185219) → Containers → Active containers | Archived containers | Deleted containers + api_equivalent: GET /storage/fileStorage/containers?$filter=containerTypeId eq {container-type-id} # listContainers; tenant-wide enumeration across all types has no API — see api-surface.json gap "listAllContainersTenantWide" + verify: + method: GET + path: /storage/fileStorage/containers/{container-id} +``` + +**Expected response:** the selected container appears in the grid; the verify call returns `200 OK` with the container's `status`. + +**On failure:** +- The Active/Deleted pages are missing or empty for a SharePoint Embedded Administrator → confirm the role assignment took effect; sign out and back in. A Global Administrator sees additional views the SPE Admin role does not. +- `403 Forbidden` on the verify call → the app token lacks `FileStorageContainer.Selected`, or container-level permission was not granted. + +### Step 2 — View container details and membership {#step-2} + +Selecting a container opens a detail panel with two tabs: **General** (metadata, usage, configuration) and **Membership** (the users in each of the four roles). SharePoint Embedded supports four roles — Owner, Manager, Writer, Reader — though an application may use a subset or rename them. + +```yaml +manual: + description: Open the container detail panel to read general metadata and membership. + ui_path: SharePoint admin center → Containers → Active containers → select {container-name} → General tab | Membership tab + api_equivalent: GET /storage/fileStorage/containers/{container-id} # getContainer; for members use GET /storage/fileStorage/containers/{container-id}/permissions (listContainerPermissions) + verify: + method: GET + path: /storage/fileStorage/containers/{container-id}/permissions +``` + +**Expected response:** the detail panel renders both tabs; the verify call returns `200 OK` with the permission collection. + +**On failure:** +- The Membership tab shows no roles → the application defines a subset of roles; this is expected, not an error. +- `404 Not Found` on the verify call → the container was deleted or the `{container-id}` is wrong. + +### Step 3 — Set or change the sensitivity label {#step-3} + +On the Active container detail panel, the Settings area exposes the sensitivity label, selected from the labels published to the tenant. Setting a label classifies the container's content for downstream Purview enforcement. + +```yaml +manual: + description: Set a sensitivity label on an active container. + ui_path: SharePoint admin center → Containers → Active containers → select {container-name} → General → Settings → Sensitivity label → choose {sensitivity-label} + api_equivalent: PATCH /storage/fileStorage/containers/{container-id} with body { "assignedSensitivityLabel": { "displayName": "{sensitivity-label}" } } # updateContainer; PowerShell: Set-SPOContainer -Identity {container-id} -SensitivityLabel {sensitivity-label} + verify: + method: GET + path: /storage/fileStorage/containers/{container-id} +``` + +**Expected response:** the panel shows the chosen label; the verify call returns `200 OK` and the container's `assignedSensitivityLabel` reflects `{sensitivity-label}`. + +**On failure:** +- The label list is empty → no sensitivity labels are published to this tenant, or label scope excludes containers/sites. Publish a SharePoint/site-scoped label in Microsoft Purview. +- `400 Bad Request` on the verify call → the label GUID is not valid for this tenant. + +### Step 4 — Manage membership (add, reassign, remove) {#step-4} + +The Membership panel manages users per role. Adding a user already in another role converts the action to **Reassign**; **Remove** prompts for confirmation before unassigning. + +```yaml +manual: + description: Add a user to a role, reassign a user to a different role, or remove a user from a role on a container. + ui_path: SharePoint admin center → Containers → Active containers → select {container-name} → Membership → choose a role → Add | Reassign | Remove → pick {principal-upn} + api_equivalent: POST /storage/fileStorage/containers/{container-id}/permissions with body { "roles": ["owner"], "grantedToV2": { "user": { "userPrincipalName": "{principal-upn}" } } } # addContainerPermission; PATCH .../permissions/{permission-id} to reassign (updateContainerPermission); DELETE to remove (deleteContainerPermission) + verify: + method: GET + path: /storage/fileStorage/containers/{container-id}/permissions +``` + +**Expected response:** the user appears under the chosen role; the verify call returns `200 OK` listing the user with the assigned role. + +**On failure:** +- The Add action becomes Reassign unexpectedly → the user already holds a different role on this container; reassign instead of adding. +- `400 Bad Request` on the API equivalent → the `roles` value is not one of `reader`, `writer`, `manager`, `owner`. + +### Step 5 — Archive an active container {#step-5} + +Archive a container that is no longer actively used but must be retained for legal, compliance, or business reasons. The confirmation side panel explains the impact and how to recover the content before the archive proceeds. + +```yaml +manual: + description: Archive an active SharePoint Embedded container. + ui_path: SharePoint admin center → Containers → Active containers → select {container-name} → Archive → Archive (confirm) + api_equivalent: none — no Graph API for container archive today; see api-surface.json gap "listAllContainersTenantWide" (archive lifecycle is portal/PowerShell-only) + verify: + method: GET + path: /storage/fileStorage/containers/{container-id} +``` + +**Expected response:** the container moves to the Archived containers page; the verify call returns `200 OK` reflecting the archived state. + +**On failure:** +- The Archive button is disabled → no container is selected, or the container is already archived. +- The container does not appear on the Archived page → archival is eventually consistent; refresh after a short wait. + +### Step 6 — Reactivate an archived container {#step-6} + +Archived containers are inaccessible to users and apps until reactivated. Containers archived within the last seven days are **Recently archived** and reactivate quickly; older containers are **Fully archived** and take up to **24 hours**, showing a **Reactivating** state until complete. + +```yaml +manual: + description: Reactivate a recently or fully archived container. + ui_path: SharePoint admin center → Containers → Archived containers → select {container-name} → Reactivate → Reactivate (confirm) + api_equivalent: none — no Graph API for reactivation today; portal/PowerShell-only (see api-surface.json gap "uniformAsyncOperationStatus" for the missing pollable status resource) + verify: + method: GET + path: /storage/fileStorage/containers/{container-id} +``` + +**Expected response:** a recently archived container returns to Active immediately; a fully archived container shows **Reactivating** for up to 24 hours, then returns to Active. The verify call returns `200 OK` with the active status once complete. + +**On failure:** +- The container stays in **Reactivating** beyond 24 hours → reactivation is asynchronous with no pollable status API today; re-check the Archived page later before retrying. +- Users still cannot access the container → reactivation has not finished; wait for the Active page to list it. + +### Step 7 — Delete an active or archived container {#step-7} + +The Delete button is disabled until a container is selected. The confirmation panel warns about the impact on the owning application and explains the 93-day restoration window. Archived containers offer the same delete experience. + +```yaml +manual: + description: Soft-delete an active or archived container into the deleted container collection. + ui_path: SharePoint admin center → Containers → Active containers (or Archived containers) → select {container-name} → Delete → Delete container (confirm) + api_equivalent: DELETE /storage/fileStorage/containers/{container-id} # deleteContainer; PowerShell: Remove-SPOContainer -Identity {container-id} + verify: + method: GET + path: /storage/fileStorage/containers/{container-id} +``` + +**Expected response:** the container moves to the Deleted containers page; the API equivalent returns `204 No Content`. + +**On failure:** +- `423 Locked` on the API equivalent → the container is locked (`lockedReadOnly`); unlock it first with the `unlockContainer` operation. +- The owning application breaks after deletion → expected; deletion removes content and can cause data loss and broken links. Notify owners before deleting. + +> [!WARNING] +> Deleting a container removes all its content and may interrupt the SharePoint Embedded application it belongs to. Deleted containers are permanently purged after **93 days** unless a retention policy applies. + +### Step 8 — Restore a deleted container {#step-8} + +A container in the deleted collection can be restored within 93 days. Restoration runs in the background; status appears in the top-right of the page. A container archived at the time of deletion is restored to the archived state. + +```yaml +manual: + description: Restore a soft-deleted container from the deleted container collection. + ui_path: SharePoint admin center → Containers → Deleted containers → select {container-name} → Restore + api_equivalent: POST /storage/fileStorage/deletedContainers/{container-id}/restore # restoreDeletedContainer; PowerShell: Restore-SPODeletedContainer -Identity {container-id} + verify: + method: GET + path: /storage/fileStorage/containers/{container-id} +``` + +**Expected response:** the container returns to the Active page (or Archived, if it was archived when deleted); the API equivalent returns `200 OK`. + +**On failure:** +- The container is not in the Deleted collection → it was already restored or has exceeded the 93-day window and was purged. +- `404 Not Found` on the API equivalent → the container was permanently deleted and cannot be restored. + +### Step 9 — Permanently delete a container {#step-9} + +From the Deleted containers page, the CTA can purge a container ahead of the 93-day schedule. A pop-up warns that the action is irreversible before it proceeds. + +```yaml +manual: + description: Permanently delete a container from the deleted container collection. + ui_path: SharePoint admin center → Containers → Deleted containers → select {container-name} → Permanently delete → Delete (confirm) + api_equivalent: POST /storage/fileStorage/containers/{container-id}/permanentDelete # permanentDeleteContainer + verify: + method: GET + path: /storage/fileStorage/containers/{container-id} +``` + +**Expected response:** the container is removed from the Deleted collection and cannot be restored; the API equivalent returns `204 No Content`. + +**On failure:** +- The Permanently delete button is disabled → no container is selected on the Deleted page. +- A retention policy blocks the purge → the container is held by a retention/hold policy; the policy must be resolved in Microsoft Purview before permanent deletion. + +## Verify {#verify} + +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containers/{container-id} +Authorization: Bearer {token} +``` + +Returns `200 OK` for an active or archived container reflecting the expected `status`, or `404 Not Found` for a permanently deleted container — matching the lifecycle action you performed. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| Only Active and Deleted pages are visible | Signed in as SharePoint Embedded Administrator, not Global Administrator | Expected — the SPE Admin role sees a subset of SPAC views. Use a Global Administrator for the global views. | +| Container pages are empty or missing | Role assignment not yet effective | Confirm the SharePoint Embedded Administrator role, then sign out and back in. | +| `403 Forbidden` on a verify call | App token missing `FileStorageContainer.Selected` or container permission | Re-acquire a token with the permission; grant the app access to the container. | +| `423 Locked` on delete | Container is `lockedReadOnly` | Unlock with `unlockContainer`, then retry. | +| Reactivation stuck in **Reactivating** | Fully archived reactivation takes up to 24 hours; no pollable status API | Wait up to 24 hours; re-check the Archived page. See gap `uniformAsyncOperationStatus`. | +| `429 Too Many Requests` on API equivalents | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling). | + +## Next steps + +- [Container management in PowerShell](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell) +- [Security and compliance](/sharepoint/dev/embedded/compliance/security-and-compliance) + +## Related + +- [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) +- [SharePoint Embedded admin role](/sharepoint/dev/embedded/administration/adminrole) +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) diff --git a/docs/embedded/spe-docs-agent-ready/administration/developer-admin/dev-admin.md b/docs/embedded/spe-docs-agent-ready/administration/developer-admin/dev-admin.md new file mode 100644 index 000000000..66177df83 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/administration/developer-admin/dev-admin.md @@ -0,0 +1,225 @@ +--- +title: Manage SharePoint Embedded container types as a developer admin +description: Assign the SharePoint Embedded Administrator role, then create and manage container types and billing with SharePoint Online Management Shell cmdlets. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: A user holds the SharePoint Embedded Administrator role and has created a container type and attached a standard billing profile using the SharePoint Online Management Shell. + estimated_minutes: 15 + difficulty: intermediate + roles: [owning-admin, m365-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/administration/adminrole + kind: concept + - uri: /sharepoint/dev/embedded/administration/billing/billing + kind: concept + - capability: global-admin + - capability: azure-subscription + api_surface: + - id: createContainerType + method: POST + path: /storage/fileStorage/containerTypes + permissions: [FileStorageContainerType.Manage.All] + - id: listContainerTypes + method: GET + path: /storage/fileStorage/containerTypes + permissions: [FileStorageContainerType.Manage.All] + - id: updateContainerType + method: PATCH + path: /storage/fileStorage/containerTypes/{containerTypeId} + permissions: [FileStorageContainerType.Manage.All] + inputs: + - name: user-principal-name + type: string + source: user-supplied + - name: container-type-name + type: string + source: user-supplied + - name: owning-application-id + type: uuid + source: app-registration + - name: azure-subscription-id + type: uuid + source: user-supplied + - name: resource-group + type: string + source: user-supplied + - name: region + type: string + source: user-supplied + - name: container-type-id + type: uuid + source: prior-step + outputs: + - name: container-type-id + type: uuid + verify: Get-SPOContainerType -ContainerTypeId {container-type-id} returns the container type + - name: standard-billing-profile + type: string + verify: Get-SPOContainerType -ContainerTypeId {container-type-id} shows the Azure subscription / resource group on a standard container type + next_steps: + - uri: /sharepoint/dev/embedded/administration/billing/billingmanagement + when: always + - uri: /sharepoint/dev/embedded/getting-started/containertypes + when: always + related: + - uri: /sharepoint/dev/embedded/administration/adminrole + - uri: /sharepoint/dev/embedded/administration/billing/billing + - uri: /sharepoint/dev/embedded/getting-started/containertypes + stability: ga + last_validated: proposed +--- + +# Manage SharePoint Embedded container types as a developer admin + + +At the end of this task a user holds the **SharePoint Embedded Administrator** role and has used the SharePoint Online Management Shell to create a container type, set its configuration, and (for standard billing) attach an Azure billing profile. + +> [!IMPORTANT] +> Container type billing setup has no Microsoft Graph API today; it is done through the SharePoint Online Management Shell only. See api-surface.json gap `setUpContainerTypeBilling`. Container type create/list/update over Graph (`createContainerType`, `listContainerTypes`, `updateContainerType`) is **beta** only — see gap `promoteContainerTypeCrudToGa`. This page uses the supported PowerShell path. + +## Prerequisites + +- [SharePoint Embedded Administrator role](/sharepoint/dev/embedded/administration/adminrole) — the role this page assigns and uses. +- [Pay-as-you-go billing](/sharepoint/dev/embedded/administration/billing/billing) — to choose standard vs. passthrough before creating the container type. +- Capability: a Global Administrator to assign the role (Step 1). +- Capability: an Azure subscription on which the billing user holds **owner or contributor** permissions (Step 4, standard billing only). If you don't have one, [create a subscription](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/initial-subscriptions). +- The latest version of the SharePoint Online Management Shell, connected with [Connect-SPOService](https://learn.microsoft.com/powershell/module/sharepoint-online/connect-sposervice). + +> [!WARNING] +> You must use the latest version of SharePoint PowerShell to run the container type administration cmdlets. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{user-principal-name}` | string | The user to receive the SharePoint Embedded Administrator role (user-supplied) | +| `{container-type-name}` | string | A display name for the new container type (user-supplied) | +| `{owning-application-id}` | uuid | The app registration ID of your SharePoint Embedded application (1:1 with the container type) | +| `{azure-subscription-id}` | uuid | The Azure subscription for standard billing (user-supplied) | +| `{resource-group}` | string | The Azure resource group for the billing profile (user-supplied) | +| `{region}` | string | The Azure region for the billing profile (user-supplied) | +| `{container-type-id}` | uuid | Returned when the container type is created (prior step) | + +## Steps + +### Step 1 — Assign the SharePoint Embedded Administrator role {#step-1} + +A Global Administrator grants `{user-principal-name}` the role so they can run the container type cmdlets. The Global Administrator role already includes these permissions; assign the dedicated role for least privilege. + +```yaml +manual: + description: Assign the SharePoint Embedded Administrator role to a user via the Microsoft 365 admin center. + ui_path: https://admin.microsoft.com → Users → Active users → select {user-principal-name} → Roles → Manage roles → Admin center access → Collaboration → SharePoint Embedded administrator → Save changes + api_equivalent: POST /servicePrincipals/{servicePrincipalId}/appRoleAssignedTo (role-assignment pattern; see api-surface.json grantAdminConsentEquivalent) — directory role assignment uses POST /roleManagement/directory/roleAssignments + verify: + method: GET + path: /roleManagement/directory/roleAssignments?$filter=principalId eq '{user-id}' +``` + +> [!NOTE] +> To assign through Microsoft Entra instead: Microsoft Entra admin center → Users → All users → select `{user-principal-name}` → Assigned roles → Add assignments → search **SharePoint Embedded** → select **SharePoint Embedded administrator** → Add. + +**Expected response:** the role appears under the user's roles in the Microsoft 365 admin center (or Entra **Assigned roles**). + +**On failure:** +- Role not listed → the signed-in admin is not a Global Administrator. Sign in as a Global Administrator. +- User can't run cmdlets after assignment → directory role assignments can take time to propagate. Re-sign-in and retry. + +### Step 2 — Create the container type {#step-2} + +The role holder creates a container type bound 1:1 to `{owning-application-id}`. Choose the cmdlet form that matches the billing model. + +```powershell +# Standard billing container type +New-SPOContainerType -ContainerTypeName "{container-type-name}" -OwningApplicationId {owning-application-id} + +# Passthrough (direct-to-customer) billing container type +New-SPOContainerType -IsPassThroughBilling -ContainerTypeName "{container-type-name}" -OwningApplicationId {owning-application-id} + +# Trial container type (valid 30 days) +New-SPOContainerType -TrialContainerType -ContainerTypeName "{container-type-name}" -OwningApplicationId {owning-application-id} +``` + +**Expected response:** the cmdlet returns the new container type, including its `ContainerTypeId` (`{container-type-id}`). + +**On failure:** +- Cmdlet not found → the SharePoint Online Management Shell is outdated. Update to the latest version. +- Access denied → the caller lacks the SharePoint Embedded Administrator (or Global Administrator) role. Complete [Step 1](#step-1). +- `OwningApplicationId` already mapped → a container type already exists for that app (1:1 mapping). Reuse it or use a different app registration. + +### Step 3 — Set container type configuration (optional) {#step-3} + +Adjust discoverability, sharing restriction, or archival on the container type. + +```powershell +# Hide container content from other Microsoft 365 surfaces (MRU, etc.); $true is the default +Set-SPOContainerTypeConfiguration -ContainerTypeId {container-type-id} -DiscoverabilityDisabled $true + +# Restrict sharing so only manager and owner can share files +Set-SPOContainerTypeConfiguration -ContainerTypeId {container-type-id} -SharingRestricted $true + +# Read back the configuration +Get-SPOContainerTypeConfiguration -ContainerTypeId {container-type-id} +``` + +**Expected response:** `Set-SPOContainerTypeConfiguration` completes without error; `Get-SPOContainerTypeConfiguration` reflects the new values. + +**On failure:** +- Parameter not recognized → outdated shell. Update to the latest version. +- Container type not found → wrong `{container-type-id}`. Confirm with `Get-SPOContainerType`. + +### Step 4 — Attach the standard billing profile {#step-4} + +For a **standard** container type, attach an Azure subscription so the container type can be used. The user running this must hold owner or contributor on `{azure-subscription-id}`. Skip this step for passthrough and trial container types. + +```powershell +Add-SPOContainerTypeBilling -ContainerTypeId {container-type-id} -AzureSubscriptionId {azure-subscription-id} -ResourceGroup "{resource-group}" -Region "{region}" +``` + +> [!NOTE] +> To change an existing standard billing profile later, use `Set-SPOContainerType -ContainerTypeId {container-type-id} -AzureSubscriptionId {azure-subscription-id} -ResourceGroup "{resource-group}"`. + +**Expected response:** the cmdlet completes without error; the container type is now backed by a billing profile. + +**On failure:** +- Authorization failed on the subscription → the caller lacks owner/contributor on `{azure-subscription-id}`. Obtain the role, or use a subscription you own. [Create a subscription](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/initial-subscriptions). +- Resource group not found → `{resource-group}` doesn't exist in `{azure-subscription-id}`. Create it or correct the name. + +## Verify {#verify} + +```powershell +# Confirm the container type exists and (for standard) shows the billing profile +Get-SPOContainerType -ContainerTypeId {container-type-id} +``` + +The cmdlet returns `{container-type-id}` with `{container-type-name}` and `{owning-application-id}`; a standard container type also shows the attached Azure subscription / resource group. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `Connect-SPOService` fails | Not signed in as SharePoint Embedded / Global admin, or wrong admin URL | Reconnect with an account holding the role and the correct `-Url` | +| Container type cmdlets missing | Outdated SharePoint Online Management Shell | Update to the latest version | +| Access denied on container type cmdlets | Missing SharePoint Embedded Administrator / Global Administrator role | Assign the role in [Step 1](#step-1) | +| `Add-SPOContainerTypeBilling` authorization error | No owner/contributor on the Azure subscription | Obtain owner/contributor on `{azure-subscription-id}` | +| Standard container type unusable | No billing profile attached | Run [Step 4](#step-4) | + +## Next steps + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [View consumption in Microsoft Cost Management](/sharepoint/dev/embedded/administration/billing/billingmanagement) + +## Related + +- [SharePoint Embedded Administrator role](/sharepoint/dev/embedded/administration/adminrole) +- [Pay-as-you-go billing](/sharepoint/dev/embedded/administration/billing/billing) +- [New-SPOContainerType](https://learn.microsoft.com/powershell/module/sharepoint-online/new-spocontainertype) +- [fileStorageContainerType Graph resource](https://learn.microsoft.com/graph/api/resources/filestoragecontainertype) +- [fileStorageContainerTypeRegistration Graph resource](https://learn.microsoft.com/graph/api/resources/filestoragecontainertyperegistration) diff --git a/docs/embedded/spe-docs-agent-ready/api-surface.json b/docs/embedded/spe-docs-agent-ready/api-surface.json new file mode 100644 index 000000000..c4411c7fa --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/api-surface.json @@ -0,0 +1,479 @@ +{ + "$schema": "https://learn.microsoft.com/sharepoint/dev/embedded/api-surface.schema.json", + "name": "SharePoint Embedded — Microsoft Graph API surface", + "description": "Machine-readable index of every SharePoint Embedded Graph operation an agent may need to plan a workflow. Curated, SPE-scoped subset of Microsoft Graph. Generated artifact: keep in sync with the live $metadata and the per-page agent.api_surface frontmatter.", + "version": "0.1-draft", + "lastGenerated": "2026-06-16", + "author": "Shreyas Saravanan", + "hosts": { + "v1.0": "https://graph.microsoft.com/v1.0", + "beta": "https://graph.microsoft.com/beta" + }, + "sources": { + "metadata_v1.0": "https://graph.microsoft.com/v1.0/$metadata", + "openapi": "https://github.com/microsoftgraph/msgraph-metadata/blob/master/openapi/v1.0/openapi.yaml", + "reference_root": "https://learn.microsoft.com/graph/api/resources/filestoragecontainer" + }, + "notes": [ + "paths are relative to hosts[version]; prepend the host for the operation's `version`.", + "expectedStatus values are indicative and MUST be confirmed by the end-to-end execution harness before a page's last_validated is stamped.", + "permissions list Graph permission names; `application` = app-only, `delegated` = on-behalf-of-user.", + "the `gaps` array lists operations that SHOULD exist for full agent automation but have no Graph API today (see spe-agent-scenario-flow-analysis.md §5.2)." + ], + "stabilityLegend": { + "ga": "Generally available on the v1.0 endpoint.", + "beta": "Available only on the /beta endpoint; shape may change.", + "preview": "Public preview; not for production." + }, + "operations": [ + { + "id": "listContainers", + "area": "containers", + "method": "GET", + "version": "v1.0", + "path": "/storage/fileStorage/containers?$filter=containerTypeId eq {containerTypeId}", + "summary": "List the fileStorageContainer objects of a container type accessible to the caller. A containerTypeId filter is required.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "inputs": [{ "name": "containerTypeId", "type": "uuid", "in": "query" }], + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestorage-list-containers" + }, + { + "id": "createContainer", + "area": "containers", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers", + "summary": "Create a new fileStorageContainer. Containers are created inactive and must be activated.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "inputs": [ + { "name": "displayName", "type": "string", "in": "body" }, + { "name": "containerTypeId", "type": "uuid", "in": "body" } + ], + "expectedStatus": 201, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-post" + }, + { + "id": "getContainer", + "area": "containers", + "method": "GET", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}", + "summary": "Read the properties and relationships of a fileStorageContainer. Use as the Verify call after create/activate.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "inputs": [{ "name": "containerId", "type": "string", "in": "path" }], + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-get" + }, + { + "id": "updateContainer", + "area": "containers", + "method": "PATCH", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}", + "summary": "Update displayName, description, customProperties, settings, or assignedSensitivityLabel of a container.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-update" + }, + { + "id": "deleteContainer", + "area": "containers", + "method": "DELETE", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}", + "summary": "Soft-delete a container (moves to the deleted container collection).", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 204, + "docs": "https://learn.microsoft.com/graph/api/filestorage-delete-containers" + }, + { + "id": "activateContainer", + "area": "containers", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/activate", + "summary": "Activate an inactive container. Inactive containers are auto-deleted after 24 hours.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-activate" + }, + { + "id": "restoreDeletedContainer", + "area": "containers", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/deletedContainers/{containerId}/restore", + "summary": "Restore a soft-deleted container from the deleted container collection.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-restore" + }, + { + "id": "permanentDeleteContainer", + "area": "containers", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/permanentDelete", + "summary": "Permanently delete a container. Irreversible.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 204, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-permanentdelete" + }, + { + "id": "lockContainer", + "area": "containers-lifecycle", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/lock", + "summary": "Lock a container to lockedReadOnly.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 204, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-lock" + }, + { + "id": "unlockContainer", + "area": "containers-lifecycle", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/unlock", + "summary": "Unlock a container back to unlocked.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 204, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-unlock" + }, + { + "id": "getContainerDrive", + "area": "content", + "method": "GET", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/drive", + "summary": "Get the drive resource of a container. All files/folders are driveItem resources under this drive.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-get-drive" + }, + { + "id": "listDriveItems", + "area": "content", + "method": "GET", + "version": "v1.0", + "path": "/drives/{driveId}/items/{itemId}/children", + "summary": "List children of a folder in a container's drive. Use the standard driveItem surface once you have driveId from getContainerDrive.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/driveitem-list-children" + }, + { + "id": "uploadFile", + "area": "content", + "method": "PUT", + "version": "v1.0", + "path": "/drives/{driveId}/items/{parentId}:/{filename}:/content", + "summary": "Upload (small) file content to a container's drive. Use createUploadSession for large files.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 201, + "docs": "https://learn.microsoft.com/graph/api/driveitem-put-content" + }, + { + "id": "downloadFile", + "area": "content", + "method": "GET", + "version": "v1.0", + "path": "/drives/{driveId}/items/{itemId}/content", + "summary": "Download file content from a container's drive.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/driveitem-get-content" + }, + { + "id": "listContainerPermissions", + "area": "permissions", + "method": "GET", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/permissions", + "summary": "List permissions on a container. Use as the Verify call after granting access.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-list-permissions" + }, + { + "id": "addContainerPermission", + "area": "permissions", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/permissions", + "summary": "Add a permission (roles: reader | writer | manager | owner) for a user on a container.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "inputs": [ + { "name": "roles", "type": "string[]", "in": "body", "enum": ["reader", "writer", "manager", "owner"] }, + { "name": "grantedToV2", "type": "object", "in": "body" } + ], + "expectedStatus": 201, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-post-permissions" + }, + { + "id": "updateContainerPermission", + "area": "permissions", + "method": "PATCH", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/permissions/{permissionId}", + "summary": "Update the role on an existing container permission.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-update-permissions" + }, + { + "id": "deleteContainerPermission", + "area": "permissions", + "method": "DELETE", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/permissions/{permissionId}", + "summary": "Remove a permission from a container.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 204, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-delete-permissions" + }, + { + "id": "upsertContainerPermissions", + "area": "permissions", + "method": "PATCH", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/permissions", + "summary": "Create or update up to 10 permissions on a container in a single request (batch).", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-patch-permissions" + }, + { + "id": "listColumns", + "area": "metadata", + "method": "GET", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/columns", + "summary": "List the columnDefinition resources (structured metadata schema) of a container.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-list-columns" + }, + { + "id": "createColumn", + "area": "metadata", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/columns", + "summary": "Create a column (columnDefinition) so files can carry queryable structured metadata.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 201, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-post-columns" + }, + { + "id": "listContainerCustomProperties", + "area": "metadata", + "method": "GET", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/customProperties", + "summary": "List custom (key/value) properties on a container.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-list-customproperty" + }, + { + "id": "addContainerCustomProperty", + "area": "metadata", + "method": "PATCH", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/customProperties", + "summary": "Add or set custom properties on a container.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-post-customproperty" + }, + { + "id": "listRecycleBinItems", + "area": "recycle-bin", + "method": "GET", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/recycleBin/items", + "summary": "List items in a container's recycle bin.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-list-recyclebinitem" + }, + { + "id": "restoreRecycleBinItems", + "area": "recycle-bin", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/recycleBin/items/restore", + "summary": "Restore items from a container's recycle bin.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-restore-recyclebinitem" + }, + { + "id": "createMigrationJob", + "area": "migration", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/migrationJobs", + "summary": "Create a sharePointMigrationJob to migrate content from intermediary storage into the container.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 201, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-post-migrationjobs" + }, + { + "id": "provisionMigrationContainers", + "area": "migration", + "method": "POST", + "version": "v1.0", + "path": "/storage/fileStorage/containers/{containerId}/provisionMigrationContainers", + "summary": "Provision SharePoint-managed Azure blob containers as temporary staging for migration content and metadata.", + "permissions": { "application": ["FileStorageContainer.Selected"], "delegated": ["FileStorageContainer.Selected"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainer-provisionmigrationcontainers" + }, + { + "id": "createContainerType", + "area": "container-types", + "method": "POST", + "version": "beta", + "path": "/storage/fileStorage/containerTypes", + "summary": "Create a container type on the owning tenant. billingClassification is trial | standard | directToCustomer.", + "permissions": { "application": ["FileStorageContainerType.Manage.All"], "delegated": [] }, + "inputs": [ + { "name": "name", "type": "string", "in": "body" }, + { "name": "owningAppId", "type": "uuid", "in": "body" }, + { "name": "billingClassification", "type": "string", "in": "body", "enum": ["trial", "standard", "directToCustomer"] } + ], + "expectedStatus": 201, + "stabilityNote": "Beta only today. Promote to v1.0 when GA (see gaps.promoteContainerTypeCrudToGa).", + "docs": "https://learn.microsoft.com/graph/api/filestorage-post-containertypes" + }, + { + "id": "listContainerTypes", + "area": "container-types", + "method": "GET", + "version": "beta", + "path": "/storage/fileStorage/containerTypes", + "summary": "List all container types the developer admin created on the tenant.", + "permissions": { "application": ["FileStorageContainerType.Manage.All"], "delegated": [] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestorage-list-containertypes" + }, + { + "id": "updateContainerType", + "area": "container-types", + "method": "PATCH", + "version": "beta", + "path": "/storage/fileStorage/containerTypes/{containerTypeId}", + "summary": "Reconfigure container type settings. Changes can take up to 24 hours to replicate to consuming tenants.", + "permissions": { "application": ["FileStorageContainerType.Manage.All"], "delegated": [] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/filestoragecontainertype-update" + }, + { + "id": "deleteContainerType", + "area": "container-types", + "method": "DELETE", + "version": "beta", + "path": "/storage/fileStorage/containerTypes/{containerTypeId}", + "summary": "Delete a container type. Only trial container types can be deleted today; all containers must be removed first.", + "permissions": { "application": ["FileStorageContainerType.Manage.All"], "delegated": [] }, + "expectedStatus": 204, + "stabilityNote": "Deletion of standard container types is not yet supported.", + "docs": "https://learn.microsoft.com/graph/api/filestorage-delete-containertypes" + }, + { + "id": "createContainerTypeRegistration", + "area": "onboarding", + "method": "POST", + "version": "beta", + "path": "/storage/fileStorage/containerTypeRegistrations", + "summary": "Register a container type in a consuming tenant and define the app's permissions on it. Prerequisite for creating containers there.", + "permissions": { "application": ["FileStorageContainerType.Manage.All"], "delegated": [] }, + "expectedStatus": 201, + "docs": "https://learn.microsoft.com/graph/api/filestorage-post-containertyperegistrations" + }, + { + "id": "grantAdminConsentEquivalent", + "area": "onboarding", + "method": "POST", + "version": "v1.0", + "path": "/servicePrincipals/{servicePrincipalId}/appRoleAssignedTo", + "summary": "API-equivalent of the portal 'Grant admin consent' click — assign an app role to the app's service principal. Use as the agent fallback for consent steps.", + "permissions": { "application": ["AppRoleAssignment.ReadWrite.All", "Application.Read.All"], "delegated": ["AppRoleAssignment.ReadWrite.All"] }, + "expectedStatus": 201, + "docs": "https://learn.microsoft.com/graph/api/serviceprincipal-post-approleassignedto" + }, + { + "id": "verifyAdminConsent", + "area": "onboarding", + "method": "GET", + "version": "v1.0", + "path": "/servicePrincipals/{servicePrincipalId}?$expand=appRoleAssignedTo", + "summary": "Verify that consent/app-role assignments are in place for the app. Use as the Verify call after consent.", + "permissions": { "application": ["Application.Read.All"], "delegated": ["Application.Read.All"] }, + "expectedStatus": 200, + "docs": "https://learn.microsoft.com/graph/api/serviceprincipal-get" + } + ], + "gaps": [ + { + "id": "setUpContainerTypeBilling", + "area": "billing", + "wantedBy": ["owning-admin", "isv-developer"], + "status": "no-graph-api", + "today": "SharePoint Online Management Shell only: Add-SPOContainerTypeBilling / Set-SPOContainerType.", + "evidence": "containertypes Learn page: 'Billing setup for standard container types is done via the SharePoint Online Management Shell. In the future, this operation will be available as a Microsoft Graph operation.'", + "priority": "P0", + "blocksPages": ["administration/billing/billingmanagement", "getting-started/set-up-container-type-billing"] + }, + { + "id": "activateConsumingTenantPayg", + "area": "billing", + "wantedBy": ["consuming-admin"], + "status": "ui-only", + "today": "Microsoft 365 admin center: Setup → Pay-as-you-go services → SharePoint Embedded.", + "priority": "P0", + "blocksPages": ["getting-started/containertypes#set-up-billing-profile-in-consuming-tenant"] + }, + { + "id": "promoteContainerTypeCrudToGa", + "area": "container-types", + "status": "beta-only", + "today": "containerTypes create/list/update/delete and containerTypeRegistrations are beta.", + "priority": "P0" + }, + { + "id": "listAllContainersTenantWide", + "area": "discovery", + "wantedBy": ["m365-admin", "agent-self-orientation"], + "status": "missing", + "today": "listContainers requires a known containerTypeId; no tenant-wide enumeration across all types.", + "priority": "P1" + }, + { + "id": "capabilityDiscovery", + "area": "discovery", + "wantedBy": ["agent-self-orientation"], + "status": "missing", + "today": "No 'what container types does this app own + their consent/permission state on this tenant' endpoint.", + "priority": "P1" + }, + { + "id": "uniformAsyncOperationStatus", + "area": "operations", + "status": "missing", + "today": "Activation, migration jobs, and 24h setting replication are eventually-consistent with no uniform pollable operation-status resource.", + "priority": "P1" + }, + { + "id": "migrationRollback", + "area": "migration", + "status": "missing", + "today": "No documented rollback for a failed migration job.", + "priority": "P2" + } + ] +} diff --git a/docs/embedded/spe-docs-agent-ready/compliance/security-and-compliance.md b/docs/embedded/spe-docs-agent-ready/compliance/security-and-compliance.md new file mode 100644 index 000000000..11fb7a03f --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/compliance/security-and-compliance.md @@ -0,0 +1,115 @@ +--- +title: Security and compliance for SharePoint Embedded +description: How SharePoint Embedded inherits Microsoft Purview compliance — audit, eDiscovery, retention, DLP, sensitivity labels, and access policies — from the consuming tenant. +ms.topic: concept-article +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: concept + difficulty: intermediate + roles: [compliance-officer, consuming-admin, m365-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + - capability: spe-admin + api_surface: + - id: updateContainer + method: PATCH + path: /storage/fileStorage/containers/{container-id} + permissions: [FileStorageContainer.Selected] + next_steps: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell + when: always + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + when: always + related: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + stability: ga + last_validated: proposed +--- + +# Security and compliance for SharePoint Embedded + + +## What it is + +SharePoint Embedded (SPE) content is governed by the same Microsoft Purview compliance and data governance solutions that govern SharePoint Online content. Because SPE storage lives in the **consuming tenant**, compliance policies configured there apply to SPE containers in the same way they apply to SharePoint sites — without separate SPE-specific configuration for tenant-wide policies. + +> [!IMPORTANT] +> SPE has **no built-in user interface by design**. Compliance scenarios that require end-user interaction (for example, a DLP override justification or a policy tip) are not natively rendered. The owning application that governs a container must surface these experiences through Microsoft Graph. + +To target a policy at a specific container, a compliance or SharePoint admin first retrieves the container's `ContainerSiteURL` with PowerShell: + +| Step | Cmdlet | Returns | +|---|---|---| +| 1 | `Get-SPOApplication` | Registered SPE applications and their `OwningApplicationId` | +| 2 | `Get-SPOContainer -OwningApplicationId ` | Containers of that application and their `ContainerID` | +| 3 | `Get-SPOContainer -OwningApplicationId -Identity ` | Container details including `ContainerSiteURL` | + +See [Get-SPOContainer](https://learn.microsoft.com/powershell/module/sharepoint-online/get-spocontainer) and [Container management in PowerShell](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell). + +## Why it matters / when to use + +Use Purview governance over SPE when the organization must manage risk, protect sensitive data, and satisfy regulatory requirements for content that an embedded application stores in its tenant. The supported capabilities split into compliance policies (applied in the Microsoft Purview portal) and security features (set with PowerShell at the container level). + +### Compliance policies (Microsoft Purview portal) + +| Capability | How it applies to SPE | Tenant-wide vs. targeted | +|---|---|---| +| **Audit** | All user and admin operations in SPE apps are captured in the organization's unified audit log, with extra fields `ContainerInstanceId` and `ContainerTypeId` to isolate SPE content. | Always on; filter by container fields. See [SharePoint Embedded audit log events](/sharepoint/dev/embedded/compliance/audit-events). | +| **eDiscovery** | Search, hold, and export SPE content with Purview eDiscovery. | Select **All** SharePoint sites to cover every container, or **Choose sites** and supply a container URL to scope to specific containers. | +| **Data Lifecycle Management (retention & holds)** | Retention and hold policies apply to SPE containers. | A policy on **All sites** covers all SharePoint sites and all containers; or supply specific container URLs to scope it. | +| **Data Loss Prevention (DLP)** | Identify, monitor, and protect sensitive items in SPE apps. | Configure on **All sites** for tenant-wide coverage, or supply container URLs to scope it. | + +For these capabilities, see [Auditing solutions](https://learn.microsoft.com/purview/audit-solutions-overview), [eDiscovery solutions](https://learn.microsoft.com/purview/ediscovery), [Data Lifecycle Management](https://learn.microsoft.com/purview/data-lifecycle-management), and [Data loss prevention](https://learn.microsoft.com/purview/dlp-learn-about-dlp). + +### Security features (PowerShell, per container) + +| Capability | Cmdlet | Notes | +|---|---|---| +| **Sensitivity labels** | `Set-SPOContainer -Identity -SensitivityLabel ` | Global Administrators and SharePoint Administrators set or remove labels on a container. See [sensitivity labels](https://learn.microsoft.com/purview/sensitivity-labels). | +| **Block download policy** | `Set-SPOSite -Identity -BlockDownloadPolicy $true` | Requires a **SharePoint Advanced Management (SAM)** license. See [Block download policy](https://learn.microsoft.com/sharepoint/block-download-from-sites). | +| **Conditional access policy** | `Set-SPOContainer -Identity -ConditionalAccessPolicy ` | Accepts `AllowFullAccess`, `AllowLimitedAccess`, or `BlockAccess`. `AuthorizationContext` support is coming. See [Control access from unmanaged devices](https://learn.microsoft.com/sharepoint/control-access-from-unmanaged-devices). | + +## When NOT to use + +- **You need a portal-rendered end-user compliance experience** (policy tips, DLP override justification, interactive retention labeling) directly from SPE. SPE has no UI; the owning application must implement these via Microsoft Graph. Do not expect SharePoint's native UI prompts to appear. +- **You want to label or lifecycle-manage containers as an everyday admin task.** Routine sensitivity labeling, archive, and delete are covered by the consuming tenant admin surfaces. See [Manage containers in the SharePoint admin center](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaux). +- **You expect Block download policy without the right license.** It requires SharePoint Advanced Management; without SAM the policy is not enforced. + +## Key terms + +| Term | Meaning | +|---|---| +| Consuming tenant | The Microsoft 365 tenant where SPE content is stored and where Purview policies apply. | +| `ContainerSiteURL` | The SharePoint site URL backing a container; the addressable unit for scoping eDiscovery, retention, DLP, block download, and conditional access policies. | +| `ContainerInstanceId` / `ContainerTypeId` | Audit-log fields that isolate SPE content within the unified audit log. | +| Policy tip | An in-product notice about a DLP-flagged file. Not natively rendered by SPE; the client app must surface it via Graph. | +| SharePoint Advanced Management (SAM) | The license required to enforce the block download policy. | + +## How it fits together + +SPE inherits compliance from the **consuming tenant**, where content physically resides. Tenant-wide policies (audit, eDiscovery on **All** sites, retention/DLP on **All sites**) flow to SPE containers automatically because each container is backed by a SharePoint site that participates in the same SharePoint workload. Targeted policies use the container's `ContainerSiteURL` to scope to individual containers. + +The split between the platform's two planes matters here: + +- **Control plane** — the consuming tenant admin governs registration, container lifecycle, sensitivity labels, and access policies (PowerShell / SharePoint admin center). +- **Content plane** — Purview policies act on the files (`driveItem` content) inside containers; interactive end-user compliance experiences must be implemented by the owning app through Microsoft Graph because SPE itself has no UI. + +For the admin surfaces that complement these compliance controls, see [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta). + +## Related + +- [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) +- [Container management in PowerShell](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell) +- [Manage containers in the SharePoint admin center](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaux) +- [SharePoint Embedded audit log events](/sharepoint/dev/embedded/compliance/audit-events) +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) +- [Microsoft Purview eDiscovery solutions](https://learn.microsoft.com/purview/ediscovery) diff --git a/docs/embedded/spe-docs-agent-ready/development/app-architecture.md b/docs/embedded/spe-docs-agent-ready/development/app-architecture.md new file mode 100644 index 000000000..7c4df12dc --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/app-architecture.md @@ -0,0 +1,116 @@ + +--- +title: SharePoint Embedded application architecture +description: How SPE apps, container types, containers, and owning vs consuming tenants fit together across the control and content planes. +ms.topic: concept-article +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: concept + difficulty: beginner + roles: [app-developer, enterprise-developer, owning-admin, consuming-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + api_surface: [] + next_steps: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + when: always + - uri: /sharepoint/dev/embedded/development/auth + when: always + related: + - uri: /sharepoint/dev/embedded/overview + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + - uri: /sharepoint/dev/embedded/api-surface.json + stability: ga + last_validated: proposed +--- + +# SharePoint Embedded application architecture + + +## What it is + +SharePoint Embedded (SPE) stores all files and documents in **containers**. Every container and all of its content is created and stored inside a Microsoft 365 tenant, and is created, managed, and accessed exclusively through a SharePoint Embedded application calling Microsoft Graph. There is no SharePoint user interface in the path; the application is the only client. + +An SPE architecture is defined by four resources and their relationships: + +| Resource | What it is | +|---|---| +| SharePoint Embedded application | A Microsoft Entra ID application registration. As the owning or guest application of a container type, it has access to containers of that type. | +| Container | The basic storage unit. A container is also a security and compliance boundary. Each container holds one drive of standard `driveItem` content. | +| Container type | A resource that defines the relationship, access privileges, and billing accountability between an application and a set of containers. It also defines behaviors on that set of containers. | +| Owning application | The single application strongly coupled to a container type. SPE mandates a 1:1 relationship between owning application and container type. | + +The container type is stamped on each container as an **immutable property** and is used across the entire SPE ecosystem. For how to create and configure container types, see [Container types](/sharepoint/dev/embedded/getting-started/containertypes). + +## Why it matters / when to use + +Understand this model before you register an app, request permissions, or create a container — the owning/consuming split and the 1:1 app-to-container-type rule determine where each Graph call must run and which permissions it requires. + +Use SPE when an application needs first-class document storage and collaboration that belongs to the application rather than to an end user's SharePoint site, and where storage must remain inside each customer's Microsoft 365 tenant boundary. The architecture supports three common deployment shapes: + +- An ISV ships one application (one container type) to many customer tenants. +- An enterprise builds a line-of-business (LOB) application for internal use. +- Multiple applications operate side by side in one tenant, each scoped to the containers of the container type it owns. + +## When NOT to use + +- When end users should own and manage their own files in personal OneDrive or a standard SharePoint site — use SharePoint or OneDrive directly. +- When you need raw object/blob storage with no document semantics — use Azure Blob Storage. +- When the application has no Microsoft Entra ID identity context to authenticate Graph calls. + +## Key terms + +| Term | Meaning | +|---|---| +| Owning tenant | The Microsoft Entra ID tenant where a container type is created. Often the same tenant where the SPE application is registered. | +| Consuming tenant | A Microsoft Entra ID tenant where a container type is used. Only a consuming tenant may hold containers of that type; all containers and content are stored within the consuming tenant's Microsoft 365 boundary. | +| Owning application | The single application coupled 1:1 to a container type. Its developer (the owning tenant) creates and manages the container type. | +| Guest application | An application granted access to containers of a container type it does not own. | +| Container | `fileStorageContainer`; the storage unit and the security/compliance boundary. | +| Container type | The resource defining access, behavior, and billing for a set of containers; immutable on each container. | +| Access model | The set of permissions configured between an application and a container type, set at container-type creation for the owning application. | + +> [!NOTE] +> The same Microsoft Entra ID tenant can be both the owning tenant and a consuming tenant of a given container type. + +## How it fits together + +### Owning tenant vs consuming tenant + +The **owning tenant** is where a container type is created and managed. This is the control-plane home of the container type: the owning application developer is responsible for creating it, configuring its permissions, and setting its behaviors. Because SPE mandates a 1:1 relationship between owning application and container type, exactly one application owns each container type. + +The **consuming tenant** is where the container type is registered and used. Containers — and all `driveItem` content within them — are created and stored inside the consuming tenant's Microsoft 365 boundary. A single tenant can act as both owning and consuming tenant for the same container type (common during development and for internal LOB apps). + +### Access model + +An application's access to containers and container content is determined by the set of permissions configured between the application and the container type it is accessing. For the owning application, this permission set is determined at container-type creation time. The ecosystem also allows an application to access containers of a container type it does **not** own, when granted guest access. + +- **Dedicated container types:** When multiple applications are deployed in one tenant — for example two ISV apps (App 1, App 2) and one LOB app (App 3) — each application can access only the stack of containers of the container type it owns. +- **Shared container types:** When App 1 and App 2 are both granted access to the same container type, both applications can access the stack of containers of that type. + +For the full permission and consent details — Microsoft Graph permissions, container type application permissions, and user permissions — see [Authentication and authorization](/sharepoint/dev/embedded/development/auth). Permissions are granted to a container type in a consuming tenant through [container type registration](/sharepoint/dev/embedded/getting-started/register-api-documentation). + +### Worked example + +Contoso, an ISV, builds a human-resources management application on SPE. The application is registered and deployed in Fabrikam, an auditing firm. Fabrikam also develops its own internal LOB auditing application on SPE. + +- Each application has its own container type. Contoso is the **owning tenant** of the HR app, and that app is the **owning application** of its container type. +- Fabrikam is the **owning tenant** of the auditing app, and that app is the **owning application** of its container type. +- Fabrikam is the **consuming tenant** for both applications — both apps' containers and content are stored inside Fabrikam's Microsoft 365 boundary. + +## Related + +- [SharePoint Embedded overview](/sharepoint/dev/embedded/overview) +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) +- [Register container type](/sharepoint/dev/embedded/getting-started/register-api-documentation) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/development/auth.md b/docs/embedded/spe-docs-agent-ready/development/auth.md new file mode 100644 index 000000000..dc6a33f70 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/auth.md @@ -0,0 +1,308 @@ + +--- +title: Configure authentication and authorization for a SharePoint Embedded app +description: Request the right Microsoft Graph permissions, grant admin consent, and gain access to containers on owning and consuming tenants. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: The application holds the correct Microsoft Graph permissions on the owning and consuming tenants, admin consent is granted, and it can acquire tokens that access containers. + estimated_minutes: 30 + difficulty: intermediate + roles: [app-developer, enterprise-developer, owning-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/development/app-architecture + kind: concept + - capability: entra-app-admin + - capability: m365-subscription + api_surface: + - id: grantAdminConsentEquivalent + method: POST + path: /servicePrincipals/{service-principal-id}/appRoleAssignedTo + permissions: [AppRoleAssignment.ReadWrite.All, Application.Read.All] + - id: verifyAdminConsent + method: GET + path: /servicePrincipals/{service-principal-id}?$expand=appRoleAssignedTo + permissions: [Application.Read.All] + inputs: + - name: app-object-id + type: uuid + source: entra-portal + - name: service-principal-id + type: uuid + source: entra-portal + - name: graph-resource-app-id + type: uuid + source: generated + - name: app-role-id + type: uuid + source: app-registration + outputs: + - name: consent-state + type: string + verify: GET /servicePrincipals/{service-principal-id}?$expand=appRoleAssignedTo returns 200 with the expected appRoleAssignment + next_steps: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + when: always + - uri: /sharepoint/dev/embedded/getting-started/register-api-documentation + when: multi-tenant-app + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + when: always + related: + - uri: /sharepoint/dev/embedded/development/app-architecture + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + - uri: /sharepoint/dev/embedded/development/limits-calling + stability: ga + last_validated: proposed +--- + +# Configure authentication and authorization for a SharePoint Embedded app + + +SharePoint Embedded (SPE) applications interact with SPE only through Microsoft Graph. Two permission layers govern every call: **Microsoft Graph permissions** allow the application to call SPE endpoints at all, and **container type application permissions** then determine which containers of which container type it may touch. Authorization is the intersection of both — and, when acting on behalf of a user, of the user's permissions as well. SPE supports both [access on behalf of a user](https://learn.microsoft.com/en-us/graph/auth-v2-user) (delegated) and [access without a user](https://learn.microsoft.com/en-us/graph/auth-v2-service) (app-only); access on behalf of a user is recommended for security and auditability. At the end of this how-to, your application holds the correct Graph permissions on the owning and consuming tenants, admin consent is granted, and it can acquire tokens that reach containers. + +> [!IMPORTANT] +> Microsoft Graph permissions let your application call SPE endpoints, but the application must also be granted permission to a container type before it can access containers of that type. Grant container type application permissions through [container type registration](/sharepoint/dev/embedded/getting-started/register-api-documentation) on the consuming tenant. + +## Prerequisites + +- [Application architecture](/sharepoint/dev/embedded/development/app-architecture) — understand owning vs consuming tenant before requesting permissions. +- Capability: a Microsoft Entra ID [application registration](https://learn.microsoft.com/en-us/graph/auth-register-app-v2). +- Capability: an Entra tenant with a Microsoft 365 subscription. +- Capability: an account with **Application Administrator** (or equivalent) to grant admin consent on each tenant. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{app-object-id}` | uuid | The application object in the Microsoft Entra admin center. | +| `{service-principal-id}` | uuid | The application's service principal (enterprise application) object ID on the target tenant. | +| `{graph-resource-app-id}` | uuid | The Microsoft Graph resource app ID, the constant `00000003-0000-0000-c000-000000000000`. | +| `{app-role-id}` | uuid | The ID of the app role (permission) being assigned; see the permission tables below. | + +### Microsoft Graph permissions used by SPE + +Request these in the application manifest (`requiredResourceAccess`). All use `resourceAppId` = `00000003-0000-0000-c000-000000000000` (Microsoft Graph). + +| Permission | Purpose | Manifest type | Permission ID | +|---|---|---|---| +| `FileStorageContainerType.Manage.All` | Create and manage container types. Owning tenant only. | `Role` | `8e6ec84c-5fcd-4cc7-ac8a-2296efc0ed9b` | +| `FileStorageContainerTypeReg.Selected` | Register the container type on consuming tenants. | `Role` | `2dcc6599-bd30-442b-8f11-90f88ad441dc` | +| `FileStorageContainer.Selected` (delegated) | Access containers on behalf of a user. | `Scope` | `085ca537-6565-41c2-aca7-db852babc212` | +| `FileStorageContainer.Selected` (app-only) | Access containers without a user. | `Role` | `40dc41bc-0f7e-42ff-89bd-d9516947e474` | +| `FileStorageContainer.Manage.All` (delegated) | Administrative actions across all governable container types, on behalf of an admin. Requires the user to be a SharePoint Embedded Administrator or Global Administrator. | `Scope` | See [Graph permissions reference](https://learn.microsoft.com/en-us/graph/permissions-reference#filestoragecontainermanageall) | + +> [!NOTE] +> When acting on behalf of a user, the effective permission is the **intersection** of the application permissions and the user permissions. App-only access instead grants the full access defined by the container type application permissions. + +### Container type application permissions + +Granted to the application per container type at registration time. These are not Graph manifest permissions. + +| Permission | Description | +|---|---| +| `None` | No access to any containers or content of this container type. | +| `ReadContent` | Read content of containers of this type. | +| `WriteContent` | Write content. Cannot be granted without `ReadContent`. | +| `Create` | Create containers of this type. | +| `Delete` | Delete containers of this type. | +| `Read` | Read container metadata. | +| `Write` | Update container metadata. | +| `EnumeratePermissions` | Enumerate members and roles. | +| `AddPermissions` | Add members. | +| `UpdatePermissions` | Change roles of existing members. | +| `DeletePermissions` | Remove other members (not self). | +| `DeleteOwnPermission` | Remove own membership. | +| `ManagePermissions` | Add, remove (including self), or update members. | +| `ManageContent` | `WriteContent` plus discard-checkout in app-only mode. | +| `Full` | All permissions for containers of this type. | + +### Container (user) permission roles {#container-user-permission-roles} + +Apply only to access on behalf of a user. Granted via [add container permission](https://learn.microsoft.com/en-us/graph/api/filestoragecontainer-post-permissions). + +| Role | Description | +|---|---| +| `reader` | Read container properties and contents. | +| `writer` | Reader plus create/update/delete content and update applicable container properties. | +| `manager` | Writer plus manage container membership. | +| `owner` | Manager plus delete and restore containers. | + +> [!NOTE] +> A user who creates a new container through a delegated call is automatically assigned the `owner` role. + +## Steps + +### Step 1 — Request container-type management permission on the owning tenant {#step-1} + +Add `FileStorageContainerType.Manage.All` to the application manifest so the app can create container types. Configure this on the **owning** tenant only. + +```json +{ + "requiredResourceAccess": [ + { + "resourceAppId": "{graph-resource-app-id}", + "resourceAccess": [ + { "id": "8e6ec84c-5fcd-4cc7-ac8a-2296efc0ed9b", "type": "Role" } + ] + } + ] +} +``` + +**Expected response:** the manifest saves and the permission appears under **API permissions** as *Not granted* until consent. + +**On failure:** +- `Insufficient privileges` → the signing-in account lacks rights to edit the app registration. Use an Application Administrator account. +- Manifest validation error → `resourceAppId` is not the Microsoft Graph constant `00000003-0000-0000-c000-000000000000`. + +### Step 2 — Grant admin consent on the owning tenant {#step-2} + +Consent assigns the requested app roles to the application's service principal. The API equivalent of the portal "Grant admin consent" action is an app-role assignment (`grantAdminConsentEquivalent`). + +```http +POST https://graph.microsoft.com/v1.0/servicePrincipals/{service-principal-id}/appRoleAssignedTo +Authorization: Bearer {token} +Content-Type: application/json + +{ + "principalId": "{service-principal-id}", + "resourceId": "{graph-service-principal-id}", + "appRoleId": "8e6ec84c-5fcd-4cc7-ac8a-2296efc0ed9b" +} +``` + +**Expected response:** `201 Created` with the `appRoleAssignment`. + +**On failure:** +- `403 Forbidden` (`accessDenied`) → caller lacks `AppRoleAssignment.ReadWrite.All`. Grant the consenting identity that permission. +- `400 Bad Request` → `appRoleId` is not a valid app role on the Graph service principal, or `resourceId` is not the Graph service principal ID on this tenant. + +### Step 3 — Create the container type, then trim owning-tenant permissions {#step-3} + +After consent, [create a container type](/sharepoint/dev/embedded/getting-started/containertypes) on the owning tenant. Once it exists, **remove** `FileStorageContainerType.Manage.All` from the manifest — it is needed only to create the container type, never on consuming tenants. + +```json +{ + "requiredResourceAccess": [ + { + "resourceAppId": "{graph-resource-app-id}", + "resourceAccess": [ + { "id": "2dcc6599-bd30-442b-8f11-90f88ad441dc", "type": "Role" } + ] + } + ] +} +``` + +**Expected response:** the manifest saves with `FileStorageContainerType.Manage.All` removed and `FileStorageContainerTypeReg.Selected` present. + +**On failure:** +- Container type creation returns `403` → consent from [step 2](#step-2) was not granted or not yet propagated. Re-grant and retry. + +> [!WARNING] +> Leaving `FileStorageContainerType.Manage.All` in the manifest exposes excessive permissions to your customers' consuming tenants. Remove it after the container type is created. + +### Step 4 — Request container-access permissions for consuming tenants {#step-4} + +Add the permissions the app needs on consuming tenants: registration plus container access (delegated, and app-only if required). + +```json +{ + "requiredResourceAccess": [ + { + "resourceAppId": "{graph-resource-app-id}", + "resourceAccess": [ + { "id": "2dcc6599-bd30-442b-8f11-90f88ad441dc", "type": "Role" }, + { "id": "085ca537-6565-41c2-aca7-db852babc212", "type": "Scope" }, + { "id": "40dc41bc-0f7e-42ff-89bd-d9516947e474", "type": "Role" } + ] + } + ] +} +``` + +**Expected response:** the manifest saves with the delegated `FileStorageContainer.Selected` scope and, optionally, the app-only role. + +**On failure:** +- Duplicate `id` validation error → a permission ID is listed twice; each `id` appears once per `resourceAppId` block. + +### Step 5 — Grant admin consent on the consuming tenant {#step-5} + +An administrator on the consuming tenant must consent to the requested permissions. Use the same app-role-assignment call against the consuming tenant's service principal. + +```http +POST https://graph.microsoft.com/v1.0/servicePrincipals/{service-principal-id}/appRoleAssignedTo +Authorization: Bearer {token} +Content-Type: application/json + +{ + "principalId": "{service-principal-id}", + "resourceId": "{graph-service-principal-id}", + "appRoleId": "{app-role-id}" +} +``` + +**Expected response:** `201 Created` per assigned app role. + +**On failure:** +- `403 Forbidden` → the consenting account is not an administrator on the consuming tenant. Use a Global Administrator or an account with consent rights. +- Delegated scopes (`Scope` type) are consented as OAuth2 permission grants, not app-role assignments; grant those via the consent flow rather than this call. + +### Step 6 — Register the container type on the consuming tenant {#step-6} + +Registration grants the app its container type application permissions on the consuming tenant. Follow [Register the container type](/sharepoint/dev/embedded/getting-started/register-api-documentation). + +```http +POST https://graph.microsoft.com/beta/storage/fileStorage/containerTypeRegistrations +Authorization: Bearer {token} +Content-Type: application/json + +{ "containerTypeId": "{container-type-id}" } +``` + +**Expected response:** `201 Created` with the container type registration. (Beta endpoint; see [stability note](#troubleshooting).) + +**On failure:** +- `403 Forbidden` → the app lacks `FileStorageContainerTypeReg.Selected` consent on this tenant. Complete [step 5](#step-5). + +## Verify {#verify} + +Confirm that the expected app-role assignments are in place for the application on the target tenant. + +```http +GET https://graph.microsoft.com/v1.0/servicePrincipals/{service-principal-id}?$expand=appRoleAssignedTo +Authorization: Bearer {token} +``` + +Returns `200 OK`. The `appRoleAssignedTo` collection contains the SPE permission roles you assigned for that tenant. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `401 Unauthorized` | Token missing, expired, or wrong scope | Re-acquire a token with the permission in **Inputs**. | +| `403 Forbidden` on container access | Container type not registered or not consented on this tenant | Complete [step 5](#step-5) and [step 6](#step-6). | +| `403 Forbidden` on List containers (delegated) | The signed-in user has no OneDrive | Known dependency; call app-only, or provision the user's OneDrive. | +| `FileStorageContainer.Manage.All` grants nothing | Signed-in user is not a SharePoint Embedded or Global Administrator | Sign in as an administrator; if both `Manage.All` and `Selected` are granted, `Manage.All` is ignored. | +| `containerTypeRegistrations` not found | Calling `v1.0`; the endpoint is **beta** | Use the `https://graph.microsoft.com/beta` host. Stability: beta. | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off. See [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling). | + +## Next steps + +- [Create a container type](/sharepoint/dev/embedded/getting-started/containertypes) +- [Register the container type](/sharepoint/dev/embedded/getting-started/register-api-documentation) +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) + +## Related + +- [Application architecture](/sharepoint/dev/embedded/development/app-architecture) +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) +- [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) +- [Microsoft Graph authentication and authorization](https://learn.microsoft.com/en-us/graph/auth/auth-concepts) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/development/content-experiences/office-experience.md b/docs/embedded/spe-docs-agent-ready/development/content-experiences/office-experience.md new file mode 100644 index 000000000..436f3ffe7 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/content-experiences/office-experience.md @@ -0,0 +1,211 @@ +--- +title: Open and edit Office documents stored in SharePoint Embedded +description: Launch, co-author, version, and share Office files held in SharePoint Embedded containers from your application. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: how-to + outcome: An end user opens an Office document stored in a SharePoint Embedded container for view or edit, co-authors in real time, restores a prior version, and shares it with the correct access level. + estimated_minutes: 20 + difficulty: intermediate + roles: [app-developer, end-user] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + - uri: /sharepoint/dev/embedded/development/content-experiences/user-experiences-overview + kind: concept + - uri: /sharepoint/dev/embedded/development/auth + kind: how-to + - capability: container-type-owner + api_surface: + - id: getContainerDrive + method: GET + path: /storage/fileStorage/containers/{container-id}/drive + permissions: [FileStorageContainer.Selected] + - id: listDriveItems + method: GET + path: /drives/{drive-id}/items/{item-id}/children + permissions: [FileStorageContainer.Selected] + - id: downloadFile + method: GET + path: /drives/{drive-id}/items/{item-id}/content + permissions: [FileStorageContainer.Selected] + inputs: + - name: container-id + type: string + source: prior-step + - name: drive-id + type: string + source: prior-step + - name: item-id + type: string + source: prior-step + outputs: + - name: web-url + type: uri + verify: The driveItem webUrl opens the document in Office for the web for view or edit. + next_steps: + - uri: /sharepoint/dev/embedded/development/tutorials/launch-experience + when: always + - uri: /sharepoint/dev/embedded/development/content-experiences/search-content + when: needs-search + related: + - uri: /sharepoint/dev/embedded/development/content-experiences/user-experiences-overview + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + - uri: /sharepoint/dev/embedded/development/auth + stability: ga + last_validated: proposed +--- + +# Open and edit Office documents stored in SharePoint Embedded + + +At the end of this how-to you can open a Word, Excel, or PowerPoint file stored in a SharePoint Embedded container from your application, hand the user to Office for the web or the desktop Office app for view or edit, let multiple users co-author in real time with AutoSave, restore a prior version, and share the file at a defined access level. Office file experiences on SharePoint Embedded behave the same as on the Microsoft 365 platform: AutoSave and versioning are enabled automatically for every Word, Excel, and PowerPoint file in a container. + +> [!NOTE] +> Documents in an **archived** container cannot be viewed or accessed. Your application must detect the archived container state, show an appropriate error, and guide the user to reactivate the container before retrying. + +## Prerequisites + +- [SharePoint Embedded overview](/sharepoint/dev/embedded/overview) — understand containers, container types, and `driveItem` content. +- [Content experiences overview](/sharepoint/dev/embedded/development/content-experiences/user-experiences-overview) — how launch, preview, download, and discoverability fit together. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — acquire a token with `FileStorageContainer.Selected`. Co-author and share require **delegated** (on-behalf-of-user) tokens. +- Capability: `container-type-owner` — the container type that holds the file is registered and consented in the consuming tenant. +- For [@mention](#step-3) to deliver, each mentioned user must [have a Microsoft 365 license assigned](/sharepoint/dev/embedded/development/auth#mention-users-in-office-documents). + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{container-id}` | string | A prior step (the container holding the document) | +| `{drive-id}` | string | [Step 1](#step-1) — `drive.id` from `getContainerDrive` | +| `{item-id}` | string | [Step 2](#step-2) — `id` of the `driveItem` to open | + +## Steps + +### Step 1 — Resolve the container's drive {#step-1} +Every file in a container lives under the container's single drive. Get the drive to obtain the `{drive-id}` used by the file operations. + +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containers/{container-id}/drive +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` with a `drive` resource whose `id` is your `{drive-id}`. + +**On failure:** +- `404 Not Found` → the container is archived or soft-deleted. Reactivate it, then retry. See the archived-container note above. +- `403 Forbidden` (`accessDenied`) → the token lacks `FileStorageContainer.Selected`, or the app is not permitted on this container type. + +### Step 2 — List items and select the Office document {#step-2} +List the children of the drive root (or a folder) to find the `driveItem` to open. The `webUrl` on the item is the Office launch URL. + +```http +GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/root/children +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` with a collection of `driveItem` objects. Each Office file carries a `webUrl` that opens it in Office for the web. + +**On failure:** +- `404 Not Found` → wrong `{drive-id}`; re-run [Step 1](#step-1). +- `403 Forbidden` → the signed-in user has no permission on the container. + +### Step 3 — Open, co-author, and @mention {#step-3} +Open the document by directing the user to the item's `webUrl`. Office for the web (or, when chosen, the desktop Office app) renders the file; AutoSave persists every change. To open in a specific mode (view for read-only, edit for editing), configure the launch URL as described in [Set up Office launch experience](/sharepoint/dev/embedded/development/tutorials/launch-experience). + +When two or more users open the same document, Office shows a presence indicator at each editor's location and streams changes live; use `@mention` in a comment to tag a peer for feedback. + +```manual: + description: Open the document for the signed-in user and co-author in Office for the web. + ui_path: Your application UI → open the driveItem.webUrl returned in Step 2 (append edit/view launch parameters per the Launch experience tutorial) + api_equivalent: none — Office co-authoring is a client experience reached via driveItem.webUrl; there is no Graph "co-author" operation. See /sharepoint/dev/embedded/development/tutorials/launch-experience + verify: + method: GET + path: /drives/{drive-id}/items/{item-id} +``` + +**Expected response:** The `webUrl` opens the file in Office for the web; presence indicators appear for concurrent editors and AutoSave is on. + +**On failure:** +- Document opens read-only when edit was intended → the delegated token or the user's container permission grants only `reader`; grant `writer` or higher. See [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm). +- `@mention` is not delivered → the mentioned user has no Microsoft 365 license, or is a guest/external user. Mentions are restricted to people inside the consuming tenant's organization and exclude guests and users from other tenants. + +### Step 4 — View or restore a previous version {#step-4} +Versioning is automatic for Word, Excel, and PowerPoint files. Users compare versions and restore a chosen version when a mistake was made, a previous version is preferred, or unwanted co-authoring changes need to be reverted. Version history is reached from the open document in Office. + +```manual: + description: View and restore a prior version of the Office document. + ui_path: Open the document via driveItem.webUrl → File → Info → Version history → select a version → Restore + api_equivalent: none — restore from Office version history is a client experience; no SPE Graph "restore version" operation is published in api-surface.json + verify: + method: GET + path: /drives/{drive-id}/items/{item-id} +``` + +**Expected response:** The selected version becomes the current version; `lastModifiedDateTime` on the `driveItem` updates. + +**On failure:** +- Version history unavailable → the container is archived (reactivate it) or the file is not a versioned Office file type. + +### Step 5 — Share the document at the correct access level {#step-5} +Users share a document by sending an email invite, by creating a shareable link, or by tagging a peer with `@mention`. Choose the sharing setting that matches the intended audience. + +| If you want to… | Sharing setting | +|---|---| +| Allow anyone who receives the link to access the file | **Anyone** — access for anyone who receives the link, directly or forwarded, including people outside your organization. | +| Allow anyone in your organization to access the file | **People in <Your Organization>** — anyone in your organization who has the link. | +| Limit access to named people and block forwarding | **Specific people** — only the people you specify; if the invitation is forwarded, only people who already have access can use the link. | +| Reshare with someone who already has access | **People with existing access** — sends a link without changing permissions. | + +```manual: + description: Share the document with the chosen access level. + ui_path: Open the document via driveItem.webUrl → Share → enter recipients or Copy link → set link permission to Anyone / People in / Specific people / People with existing access → Send + api_equivalent: POST /storage/fileStorage/containers/{container-id}/permissions (addContainerPermission) grants container-level access programmatically; see /sharepoint/dev/embedded/development/sharing-and-perm + verify: + method: GET + path: /storage/fileStorage/containers/{container-id}/permissions +``` + +**Expected response:** The recipient receives access at the chosen level; `listContainerPermissions` reflects any granted container permission. + +**On failure:** +- External recipient cannot open with **Specific people** → external sharing is not enabled for the consuming tenant, or the link audience excludes external users. +- Recipient sees access denied on a direct file link → a raw file URL lacks app authorization. Share the `webUrl` or generate a sharing link instead of a direct content URL. + +## Verify {#verify} +Confirm the document is reachable and editable for the signed-in user. + +```http +GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id} +Authorization: Bearer {token} +``` + +Returns `200 OK` with a `driveItem` that has a `file` facet and a `webUrl`. Opening `webUrl` renders the document in Office for the web for view or edit. + +## Troubleshooting {#troubleshooting} +| Symptom | Likely cause | Fix | +|---|---|---| +| Document cannot be opened or accessed | Container is archived (cold storage tier) | Reactivate the container, then retry. See [Content experiences overview](/sharepoint/dev/embedded/development/content-experiences/user-experiences-overview#archived-containers) | +| Opens read-only when edit expected | Delegated permission or container role grants only read | Grant `writer` or higher. See [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) | +| `@mention` not delivered | Mentioned user lacks a Microsoft 365 license, or is a guest/external user | Assign a license; mentions are limited to the consuming tenant's organization | +| Office breadcrumb missing or stale | Container properties not configured, or Office not on Current Channel | Configure container properties; specify **Current Channel** for [Office update channels](/deployoffice/updates/overview-update-channels) | +| `401 Unauthorized` | Token missing/expired or wrong scope | Re-acquire a delegated token with `FileStorageContainer.Selected` | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps +- [Set up the launch experience (Office client modes)](/sharepoint/dev/embedded/development/tutorials/launch-experience) +- [Offer file preview experiences](/sharepoint/dev/embedded/development/tutorials/using-file-preview) +- [Search content](/sharepoint/dev/embedded/development/content-experiences/search-content) + +## Related +- [Content experiences overview](/sharepoint/dev/embedded/development/content-experiences/user-experiences-overview) +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Office update channels](/deployoffice/updates/overview-update-channels) diff --git a/docs/embedded/spe-docs-agent-ready/development/content-experiences/search-content.md b/docs/embedded/spe-docs-agent-ready/development/content-experiences/search-content.md new file mode 100644 index 000000000..2d364c078 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/content-experiences/search-content.md @@ -0,0 +1,284 @@ +--- +title: Search SharePoint Embedded containers and content +description: Use the Microsoft Search API in Microsoft Graph to query SharePoint Embedded containers and content, scoped by container type. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: how-to + outcome: A search query returns SharePoint Embedded containers (drive) or content (driveItem) scoped to a specific container type, with hidden content included when the container type opted out of Microsoft 365 discoverability. + estimated_minutes: 20 + difficulty: intermediate + roles: [app-developer, end-user] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + - uri: /sharepoint/dev/embedded/development/content-experiences/user-experiences-overview + kind: concept + - uri: /sharepoint/dev/embedded/development/auth + kind: how-to + - capability: container-type-owner + api_surface: + - id: searchQuery + method: POST + path: /search/query + permissions: [Files.Read.All] + - id: listDriveItems + method: GET + path: /drives/{drive-id}/items?$filter={filter} + permissions: [FileStorageContainer.Selected] + inputs: + - name: container-type-id + type: uuid + source: app-registration + - name: container-id + type: string + source: prior-step + - name: query-string + type: string + source: user-supplied + - name: column-property + type: string + source: user-supplied + - name: property-value + type: string + source: user-supplied + outputs: + - name: hits + type: array + verify: POST /search/query returns 200 with a hitsContainers collection scoped to {container-type-id}. + next_steps: + - uri: /sharepoint/dev/embedded/development/content-experiences/office-experience + when: always + - uri: /sharepoint/dev/embedded/development/tutorials/metadata + when: always + related: + - uri: /sharepoint/dev/embedded/development/content-experiences/user-experiences-overview + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/development/limits-calling + stability: beta + last_validated: proposed +--- + +# Search SharePoint Embedded containers and content + + +At the end of this how-to you can query SharePoint Embedded containers and content with the [Microsoft Search](/microsoftsearch/overview-microsoft-search) API in Microsoft Graph, scope each query to a container type (and optionally a file type), include content hidden from Microsoft 365 when your application opted out of discoverability, and enumerate content by column property with `$filter`. + +> [!IMPORTANT] +> Searching SharePoint Embedded content is in **Preview** and is subject to change. The Search API for SharePoint Embedded supports **delegated permissions only** and runs in the context of the signed-in user. Review the [exceptional access pattern](/sharepoint/dev/embedded/development/auth#operations-involving-searching-sharepoint-embedded-content) for the current permission requirements before depending on this in production. + +> [!NOTE] +> The Search examples on this page run against the Microsoft Graph **beta** endpoint (`/search/query`); responses carry a `beta` `@odata.context`. The enumerate examples in [Step 5](#step-5) use the **v1.0** `driveItem` surface. The `/search/query` operation is not yet listed in [api-surface.json](/sharepoint/dev/embedded/api-surface.json); confirm the path, permissions, and stability against the live `$metadata` before stamping `last_validated`. + +## Prerequisites + +- [SharePoint Embedded overview](/sharepoint/dev/embedded/overview) — understand containers, container types, and `driveItem` content. +- [Content experiences overview](/sharepoint/dev/embedded/development/content-experiences/user-experiences-overview) — discoverability and the `includeHiddenContent` parameter. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — acquire a **delegated** token; Search does not support application (app-only) permissions. +- Capability: `container-type-owner` — your application has access permission to the container type whose content you query. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{container-type-id}` | uuid | Your app registration (the container type to scope to) | +| `{container-id}` | string | A prior step (a specific container's drive id) | +| `{query-string}` | string | User-supplied search terms | +| `{column-property}` | string | User-supplied column (field) name to filter on | +| `{property-value}` | string | User-supplied value to match | + +> [!NOTE] +> If your application **opted out** of content discoverability in Microsoft 365, every search request must set `sharePointOneDriveOptions.includeHiddenContent` to `true`, or hidden content is excluded. See [Content experiences overview](/sharepoint/dev/embedded/development/content-experiences/user-experiences-overview#content-discovery-in-microsoft-365). + +## Steps + +### Step 1 — Search containers by container type {#step-1} +Return every container (`drive`) of a container type in the tenant. Scope with `ContainerTypeId` in the `queryString`; the response lists each container instance. + +```http +POST https://graph.microsoft.com/beta/search/query +Authorization: Bearer {token} +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": ["drive"], + "query": { + "queryString": "ContainerTypeId:{container-type-id}" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + } + } + ] +} +``` + +**Expected response:** `200 OK` with `value[].hitsContainers[].hits[]`, each `resource` being a `#microsoft.graph.drive`. + +**On failure:** +- `403 Forbidden` → token uses application permissions, or the app lacks access to the container type. Use a delegated token and grant the app access to the container type. +- Empty `hits` while content exists → the app opted out of discoverability and `includeHiddenContent` was not set to `true`. + +### Step 2 — Search containers by title, description, or custom property {#step-2} +Narrow the container search by combining `ContainerTypeId` with `Title`, `Description`, or a custom property. For a custom property, append `OWSTEXT` to the property name in the `queryString`. + +```http +POST https://graph.microsoft.com/beta/search/query +Authorization: Bearer {token} +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": ["drive"], + "query": { + "queryString": "{column-property}OWSTEXT:{property-value} AND ContainerTypeId:{container-type-id}" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + } + } + ] +} +``` + +**Expected response:** `200 OK` with `hits` whose `drive` resources match the title, description, or custom-property criteria. + +**On failure:** +- No matches on a custom property → the property name was not suffixed with `OWSTEXT`, or the value does not match. +- `400 Bad Request` → malformed `queryString` (check `AND` syntax and quoting). + +### Step 3 — Search for content (driveItem) by title or words {#step-3} +Search content rather than containers by setting `entityTypes` to `driveItem`. Scope to all containers of a type with `ContainerTypeId`, or to one container with `ContainerId`. + +```http +POST https://graph.microsoft.com/beta/search/query +Authorization: Bearer {token} +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": ["driveItem"], + "query": { + "queryString": "'{query-string}' AND ContainerTypeId:{container-type-id}" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + } + } + ] +} +``` + +**Expected response:** `200 OK` with `hits` whose `resource` is `#microsoft.graph.driveItem`; the `summary` highlights matched terms. + +**On failure:** +- Results include items your app cannot access → search enforces the user's access, not the app's. Always include `ContainerTypeId` (or `ContainerId`) so results are scoped to your application's content. See [Known limitations](#known-limitations). +- `403 Forbidden` → application token used; switch to delegated. + +### Step 4 — Request specific fields and sort {#step-4} +Return chosen content properties in the response with `fields`, and order results by a [sortable property](/sharepoint/technical-reference/crawled-and-managed-properties-overview) with `sortProperties`. + +```http +POST https://graph.microsoft.com/beta/search/query +Authorization: Bearer {token} +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": ["driveItem"], + "query": { + "queryString": "{query-string}" + }, + "sharePointOneDriveOptions": { + "includeHiddenContent": true + }, + "fields": [ + "id", "name", "parentReference", "file", "folder", "webUrl", + "createdDateTime", "lastModifiedDateTime", "size", + "fileSystemInfo", "createdBy", "lastModifiedBy" + ], + "sortProperties": [ + { "name": "Created", "isDescending": false } + ] + } + ] +} +``` + +**Expected response:** `200 OK` with each hit's `resource.listItem.fields` populated for the requested fields, ordered by `Created` ascending. + +**On failure:** +- `sortProperties` ignored or rejected → the named property is not sortable. Choose a [sortable managed property](/sharepoint/technical-reference/crawled-and-managed-properties-overview). +- Requested field absent from response → the field name is not a valid managed property for the item. + +### Step 5 — Enumerate (filter) content without the Search API {#step-5} +To return content by an exact column-property value without search indexing, enumerate the drive's items with `$filter`. This uses the standard `driveItem` surface on **v1.0**. See the [filter query parameter](/graph/filter-query-parameter?tabs=http) reference. + +```http +GET https://graph.microsoft.com/v1.0/drives/{container-id}/items?$filter=listitem/fields/{column-property} eq '{property-value}'&$select=id,name,lastModifiedDateTime,size&$expand=listitem($expand=fields)&$orderby=createdDateTime desc +Authorization: Bearer {token} +Content-Type: application/json +Prefer: HonorNonIndexedQueriesWarningMayFailRandomly +``` + +**Expected response:** `200 OK` with a `value` array of `driveItem` objects, each expanded with its `listItem.fields`, ordered by `createdDateTime` descending. + +**On failure:** +- `400 Bad Request` or random failures on a container with more than 5,000 items using `$orderby` → add the header `Prefer: HonorNonIndexedQueriesWarningMayFailRandomly`. +- `404 Not Found` → wrong `{container-id}` (drive id); resolve the drive first. See [Office experiences, Step 1](/sharepoint/dev/embedded/development/content-experiences/office-experience#step-1). + +## Verify {#verify} +Confirm a scoped query returns hits for your container type. + +```http +POST https://graph.microsoft.com/beta/search/query +Authorization: Bearer {token} +Content-Type: application/json + +{ + "requests": [ + { + "entityTypes": ["drive"], + "query": { "queryString": "ContainerTypeId:{container-type-id}" }, + "sharePointOneDriveOptions": { "includeHiddenContent": true } + } + ] +} +``` + +Returns `200 OK` with at least one `hitsContainers[].hits[]` entry whose `resource` is a `drive`, confirming the query is correctly scoped and authorized. + +## Known limitations {#known-limitations} +- Search requests run in the context of the signed-in user; results are scoped to items that user can access. Results can include containers or content the user can reach but that your SharePoint Embedded application is not authorized to access. Always include `ContainerTypeId` (containers) or `ContainerId` (content) in the `queryString` to keep results within your application's scope. +- For your application to access containers or content returned in search results, it must have access permission to the corresponding container type. + +## Troubleshooting {#troubleshooting} +| Symptom | Likely cause | Fix | +|---|---|---| +| `403 Forbidden` | Application (app-only) token used; Search supports delegated only | Re-acquire a delegated token; see the [exceptional access pattern](/sharepoint/dev/embedded/development/auth#operations-involving-searching-sharepoint-embedded-content) | +| Hidden content missing from results | App opted out of discoverability and `includeHiddenContent` not set | Set `sharePointOneDriveOptions.includeHiddenContent` to `true` | +| Results leak items the app cannot access | Query not scoped to a container type | Add `ContainerTypeId` (or `ContainerId`) to the `queryString` | +| Random failures with `$orderby` on large containers | More than 5,000 items, non-indexed query | Add header `Prefer: HonorNonIndexedQueriesWarningMayFailRandomly` | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps +- [Open and edit Office documents](/sharepoint/dev/embedded/development/content-experiences/office-experience) +- [Using metadata on containers](/sharepoint/dev/embedded/development/tutorials/metadata) + +## Related +- [Content experiences overview](/sharepoint/dev/embedded/development/content-experiences/user-experiences-overview) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) +- [Microsoft Search API overview](/microsoftsearch/overview-microsoft-search) +- [Crawled and managed properties](/sharepoint/technical-reference/crawled-and-managed-properties-overview) diff --git a/docs/embedded/spe-docs-agent-ready/development/content-experiences/user-experiences-overview.md b/docs/embedded/spe-docs-agent-ready/development/content-experiences/user-experiences-overview.md new file mode 100644 index 000000000..4eca454cd --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/content-experiences/user-experiences-overview.md @@ -0,0 +1,92 @@ +--- +title: Content experiences overview for SharePoint Embedded +description: The user-experience capabilities SharePoint Embedded gives your app — Office editing, preview, download, search, discoverability, archive, and recycle bin. +ms.topic: concept-article +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: concept + difficulty: beginner + roles: [app-developer, end-user] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + api_surface: [] + next_steps: + - uri: /sharepoint/dev/embedded/development/content-experiences/office-experience + when: always + - uri: /sharepoint/dev/embedded/development/content-experiences/search-content + when: needs-search + - uri: /sharepoint/dev/embedded/development/tutorials/using-file-preview + when: always + related: + - uri: /sharepoint/dev/embedded/development/content-experiences/office-experience + - uri: /sharepoint/dev/embedded/development/content-experiences/search-content + - uri: /sharepoint/dev/embedded/development/tutorials/launch-experience + - uri: /sharepoint/dev/embedded/development/tutorials/using-file-preview + - uri: /sharepoint/dev/embedded/administration/developer-admin/dev-admin + stability: ga + last_validated: proposed +--- + +# Content experiences overview for SharePoint Embedded + + +## What it is + +SharePoint Embedded provides a set of user-experience capabilities you compose into your application: opening and editing Office files, file preview, file download, in-app search, content discoverability control in Microsoft 365, container archiving, and a recycle bin. Each capability is reached either by directing the user to a `driveItem` web URL (Office, preview) or by a Microsoft Graph call (download, search, archive, recycle bin), so you assemble the right end-user surface without rebuilding storage, collaboration, or compliance. + +| Capability | What it gives the user | Reached via | +|---|---|---| +| Open & edit using Office | View, edit, and co-author Word, Excel, and PowerPoint files in Office for the web or the desktop app | `driveItem.webUrl` + launch parameters | +| Preview content | File preview for many file types, embedded in an iFrame or a new page | SharePoint Embedded player plugin | +| Download | A short-lived, pre-authenticated URL to download a file | [Download driveItem](/graph/api/driveitem-get-content) | +| Search | Query containers and content scoped by container type and file type | [Microsoft Search API](/microsoftsearch/overview-microsoft-search) | +| Content discovery in Microsoft 365 | Opt content in or out of office.com, OneDrive.com, intelligent file discovery, and Copilot grounding | `Set-SPOContainerTypeConfiguration` cmdlet | +| Archived containers | Move container data to a cold storage tier to cut storage cost | Microsoft Graph | +| Recycle bin | Restore or permanently delete deleted items within 93 days | Microsoft Graph | + +## Why it matters / when to use + +Use these content experiences when your application needs first-class document behavior — co-authoring, versioning, previews, search, and Purview-backed governance — without building a file UI from scratch. Office editing and preview are client experiences you reach through item URLs; download, search, archive, and recycle bin are Graph operations you call from your back end. Together they cover the common file-management surface end users expect. + +For the step-by-step "open and edit" recipe, see [Office experiences](/sharepoint/dev/embedded/development/content-experiences/office-experience). To launch Office in a specific mode (view or edit), see [Set up the launch experience](/sharepoint/dev/embedded/development/tutorials/launch-experience). To embed previews, see [File preview](/sharepoint/dev/embedded/development/tutorials/using-file-preview). To search, see [Search content](/sharepoint/dev/embedded/development/content-experiences/search-content). + +> [!NOTE] +> A direct link to a file lacks authorization from your application. If used directly in a browser, a raw file URL yields access denied. Use the [Download driveItem](/graph/api/driveitem-get-content) API to generate a short-lived, pre-authenticated download URL, or share the item's `webUrl`. + +## When NOT to use + +- When content must remain invisible to Microsoft 365 surfaces and to Copilot grounding — leave discoverability at its default (disabled); do not opt in with `Set-SPOContainerTypeConfiguration`. +- When you need raw blob download semantics with no document model (no preview, co-authoring, or Purview) — SharePoint Embedded content experiences are not the fit; use Azure Blob Storage. +- When a container is archived — its data is in cold storage and cannot be opened, previewed, searched, or downloaded until reactivated. + +## Key terms + +| Term | Meaning | +|---|---| +| Content discoverability | Whether SharePoint Embedded content appears in Microsoft 365 surfaces (office.com, OneDrive.com, intelligent file discovery) and is available for Copilot for Microsoft 365 grounding. **Disabled by default.** | +| `includeHiddenContent` | Search request parameter your app must set when the container type opted out of Microsoft 365 discoverability, so search returns the hidden content. | +| Archived container | A container whose data is moved to the cold storage tier to reduce cost; inaccessible until reactivated; deletable without reactivation. | +| Recycle bin | The per-container holding area for deleted items, retained 93 days, after which items are permanently and irreversibly deleted. | +| Player plugin | The SharePoint Embedded file-preview component embedded in an iFrame or opened in a new page. | + +## How it fits together + +Content discoverability is a **control-plane** decision made on the container type. By default, SharePoint Embedded application content is hidden across Microsoft 365 — office.com, OneDrive.com, other intelligent file-discovery features — and is excluded from Copilot for Microsoft 365 grounding. To opt in, the developer admin changes the setting at (or after) container type creation with the `Set-SPOContainerTypeConfiguration` cmdlet (`-discoverabilityDisabled $False`). If you modify the setting after content already exists, changes can take up to 30 days to reach full consistency across all consuming tenants. To enable the Office.com sharing dialog for your content, add the required application permissions during container type registration. + +The other experiences operate on the **content plane**: Office editing and preview act on individual `driveItem` resources via their URLs; download, search, archive, and recycle bin are Graph operations against the container's drive and items. Search runs in the context of the signed-in user and enforces that user's access — always scope queries by `ContainerTypeId` so results stay within your application's content. See [Search content](/sharepoint/dev/embedded/development/content-experiences/search-content). + +## Related + +- [Office experiences](/sharepoint/dev/embedded/development/content-experiences/office-experience) +- [Search content](/sharepoint/dev/embedded/development/content-experiences/search-content) +- [Set up the launch experience](/sharepoint/dev/embedded/development/tutorials/launch-experience) +- [File preview in an iFrame](/sharepoint/dev/embedded/development/tutorials/using-file-preview) +- [Developer admin — container type configuration](/sharepoint/dev/embedded/administration/developer-admin/dev-admin) +- [Download a driveItem (Microsoft Graph)](/graph/api/driveitem-get-content) diff --git a/docs/embedded/spe-docs-agent-ready/development/declarative-agent/sharepoint-embedded-knowledge-source.md b/docs/embedded/spe-docs-agent-ready/development/declarative-agent/sharepoint-embedded-knowledge-source.md new file mode 100644 index 000000000..141edf3f3 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/declarative-agent/sharepoint-embedded-knowledge-source.md @@ -0,0 +1,154 @@ +--- +title: Set up SharePoint Embedded as a knowledge source in Microsoft Foundry +description: Configure a SharePoint knowledge source over SharePoint Embedded content and grant Microsoft Foundry access to your container type. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: how-to + outcome: A Microsoft Foundry Agent Service knowledge source is configured over a SharePoint Embedded container type, and Microsoft Foundry is granted delegated read access so an agent can retrieve over container content. + estimated_minutes: 25 + difficulty: advanced + roles: [app-developer, enterprise-developer] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + - uri: /sharepoint/dev/embedded/getting-started/containertypes + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: how-to + - capability: container-type-owner + - capability: m365-subscription + api_surface: + - id: createContainerTypeRegistration + method: POST + path: /storage/fileStorage/containerTypeRegistrations + permissions: [FileStorageContainerType.Manage.All] + inputs: + - name: container-type-id + type: uuid + source: app-registration + - name: foundry-app-id + type: uuid + source: generated + outputs: + - name: application-permission-grant + type: object + verify: GET the container type registration shows Foundry's application permission grant with delegated readContent. + next_steps: + - uri: /sharepoint/dev/embedded/development/content-experiences/search-content + when: needs-search + - uri: /sharepoint/dev/embedded/overview + when: always + related: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/api-surface.json + stability: preview + last_validated: proposed +--- + +# Set up SharePoint Embedded as a knowledge source in Microsoft Foundry + + +At the end of this how-to, a [Microsoft Foundry Agent Service](/azure/foundry/agents/overview) knowledge source is configured to retrieve over content in a SharePoint Embedded (SPE) container type, and Microsoft Foundry holds the delegated read permission it needs to access that container type in your consuming tenants. + +> [!IMPORTANT] +> The SharePoint Embedded AI knowledge source in Microsoft Foundry is in **Preview**. Its API surface, required permissions, and pricing may change before general availability. The Copilot-license prerequisite below applies to the preview period only; billing switches to metered once this capability leaves preview. Do not depend on this capability in production until it is generally available. + +## Prerequisites + +- [SharePoint Embedded overview](/sharepoint/dev/embedded/overview) — an SPE app with **at least one container** must already exist. +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — you know the `{container-type-id}` of the content to expose, and your app owns it. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — the container type's **owning application** can call Microsoft Graph against the consuming tenants. +- Capability: `container-type-owner` — only the owning application can grant Foundry access to the container type. +- Capability: `m365-subscription` — at least **one Copilot license** on the tenant. This is a preview-only requirement. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{container-type-id}` | uuid | Your app registration — the SPE container type whose content the agent retrieves over | +| `{foundry-app-id}` | uuid | The Microsoft Foundry first-party application ID, `880da380-985e-4198-81b9-e05b1cc53158` (fixed value per the live docs; verify before use) | + +## Steps + +### Step 1 — Configure the SharePoint knowledge source for SharePoint Embedded {#step-1} +Point the [SharePoint knowledge source (Preview)](/azure/search/agentic-knowledge-source-how-to-sharepoint-remote) at your container type so Foundry retrieves over SPE content. Set `remoteSharePointParameters.containerTypeId` to your `{container-type-id}`. + +```manual: + description: Create a SharePoint knowledge source configured for SharePoint Embedded in Microsoft Foundry. + ui_path: Microsoft Foundry → Agent Service → Knowledge sources → add a SharePoint knowledge source → set remoteSharePointParameters.containerTypeId to {container-type-id} + api_equivalent: Configured through the Foundry / Azure AI Search SharePoint knowledge source API; see /azure/search/agentic-knowledge-source-how-to-sharepoint-remote#source-specific-properties. No SPE Graph operation provisions this — out of api-surface.json scope. + verify: + method: GET + path: /storage/fileStorage/containerTypeRegistrations +``` + +**Expected response:** The knowledge source is created with `remoteSharePointParameters.containerTypeId` equal to `{container-type-id}`. + +**On failure:** +- Knowledge source creation rejects the container type → `{container-type-id}` is wrong, or the container type has no containers. Confirm at least one container exists. +- See the [SharePoint knowledge source properties](/azure/search/agentic-knowledge-source-how-to-sharepoint-remote#source-specific-properties) for the required `remoteSharePointParameters` shape. + +### Step 2 — Grant Microsoft Foundry access to the container type {#step-2} +Foundry needs delegated read permission on your container type. Grant it by updating the container type registration in each consuming tenant. The container type's **owning application** must make this call on the consuming tenants. Replace `{container-type-id}` with your container type ID; `{foundry-app-id}` is the fixed Foundry application ID `880da380-985e-4198-81b9-e05b1cc53158`. + +```http +PUT https://graph.microsoft.com/v1.0/storage/fileStorage/containerTypeRegistrations/{container-type-id}/applicationPermissionGrants/{foundry-app-id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "delegatedPermissions": ["readContent"], + "applicationPermissions": ["none"] +} +``` + +> [!NOTE] +> The `applicationPermissionGrants` sub-resource on `containerTypeRegistrations` is not yet listed in [api-surface.json](/sharepoint/dev/embedded/api-surface.json); the closest registered operation is `createContainerTypeRegistration` (POST `/storage/fileStorage/containerTypeRegistrations`, **beta**, `FileStorageContainerType.Manage.All`). Verify the method, host (v1.0 vs beta), and permissions of this PUT against the live `$metadata` before stamping `last_validated`. + +> [!TIP] +> You can grant this permission during initial registration instead, using the [Create container type registration](/graph/api/filestorage-post-containertyperegistrations) endpoint. + +**Expected response:** `200 OK` (or `201 Created`) with the application permission grant for `{foundry-app-id}` showing `delegatedPermissions` of `readContent`. + +**On failure:** +- `403 Forbidden` → the caller is not the container type's owning application, or lacks `FileStorageContainerType.Manage.All`. Call from the owning app with the required permission. +- `404 Not Found` → the container type is not registered in this consuming tenant. Register it first with [Create container type registration](/graph/api/filestorage-post-containertyperegistrations). +- `400 Bad Request` → `{foundry-app-id}` is not the expected Foundry application ID; confirm the current value. + +## Verify {#verify} +Confirm the Foundry application permission grant is present on the container type registration. + +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containerTypeRegistrations/{container-type-id}/applicationPermissionGrants +Authorization: Bearer {token} +``` + +Returns `200 OK` with a grant for `{foundry-app-id}` whose `delegatedPermissions` include `readContent`. A Foundry agent backed by the knowledge source can then retrieve over the container content. + +## Troubleshooting {#troubleshooting} +| Symptom | Likely cause | Fix | +|---|---|---| +| Agent returns no SPE results | Knowledge source `containerTypeId` mismatch, or grant missing | Re-check [Step 1](#step-1) `containerTypeId` and [Step 2](#step-2) grant | +| `403 Forbidden` on the grant | Caller is not the owning app or lacks `FileStorageContainerType.Manage.All` | Call from the owning application with the required permission | +| `404 Not Found` on the registration | Container type not registered in the consuming tenant | Register it with [Create container type registration](/graph/api/filestorage-post-containertyperegistrations) | +| Setup blocked by licensing | No Copilot license on the tenant (preview-only requirement) | Assign at least one Copilot license during the preview | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps +- [Search SharePoint Embedded containers and content](/sharepoint/dev/embedded/development/content-experiences/search-content) +- [SharePoint Embedded overview](/sharepoint/dev/embedded/overview) + +## Related +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Microsoft Foundry Agent Service](/azure/foundry/agents/overview) +- [SharePoint knowledge source (Preview)](/azure/search/agentic-knowledge-source-how-to-sharepoint-remote) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/development/fluid.md b/docs/embedded/spe-docs-agent-ready/development/fluid.md new file mode 100644 index 000000000..c14286204 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/fluid.md @@ -0,0 +1,214 @@ + +--- +title: Run a Fluid Framework app on SharePoint Embedded +description: Gather your client ID and container type ID, configure the Item Counter sample, and run a real-time collaborative Fluid app on SPE. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: The Item Counter Fluid sample runs locally against your SPE app and syncs state in real time across two signed-in clients on the tenant. + estimated_minutes: 25 + difficulty: intermediate + roles: [app-developer, enterprise-developer] + prerequisites: + - uri: /sharepoint/dev/embedded/getting-started/spembedded-for-vscode + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: how-to + - capability: m365-subscription + - capability: entra-app-admin + api_surface: [] + inputs: + - name: spe-client-id + type: uuid + source: app-registration + - name: spe-container-type-id + type: uuid + source: prior-step + outputs: + - name: running-fluid-app + type: string + verify: https://localhost:8080 loads, signs in, and syncs the Item Counter value across two clients + next_steps: + - uri: /sharepoint/dev/embedded/development/content-experiences/office-experience + when: always + - uri: /sharepoint/dev/embedded/development/limits-calling + when: always + related: + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/getting-started/spembedded-for-vscode + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/overview + stability: ga + last_validated: proposed +--- + +# Run a Fluid Framework app on SharePoint Embedded + + +By the end of this how-to, the Microsoft **Item Counter** Fluid sample runs locally against your SharePoint Embedded (SPE) application and syncs its counter value in real time across two clients signed in to the same tenant. [Fluid Framework](https://fluidframework.com/) is a set of client libraries for distributing, synchronizing, and saving shared data so multiple clients can operate on the same data structures in real time. + +## Prerequisites + +- [VS Code extension for SharePoint Embedded](/sharepoint/dev/embedded/getting-started/spembedded-for-vscode) — create an SPE application and a trial container type. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — the app must be registered in [Microsoft Entra ID](https://entra.microsoft.com/) with admin consent. +- Capability: administrative credentials for a Microsoft 365 tenant. +- Capability: at least one container created of the same container type linked to your SPE application. +- Capability: Node.js and `npm`, and `git` installed locally. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{spe-client-id}` | uuid | The application (client) ID. From the Microsoft Entra admin center under **Identity > Applications > App registrations**, or the exported Postman environment from the VS Code extension. | +| `{spe-container-type-id}` | uuid | The container type ID. From the exported Postman environment, or the `Get-SPOContainerType` PowerShell cmdlet. | + +## Steps + +### Step 1 — Get your client ID and container type ID {#step-1} + +The `{spe-client-id}` is required to acquire correct access tokens; the `{spe-container-type-id}` is required to reach containers of your app. Retrieve the container type ID with PowerShell. + +```pwsh +Get-SPOContainerType +``` + +**Expected response:** the cmdlet lists your container types, including the `ContainerTypeId` value for `{spe-container-type-id}`. + +**On failure:** +- Cmdlet not found → install the SharePoint Online Management Shell. +- Empty result → no container type exists yet. Create one with the [VS Code extension](/sharepoint/dev/embedded/getting-started/spembedded-for-vscode). + +> [!NOTE] +> If you used the [VS Code extension](/sharepoint/dev/embedded/getting-started/spembedded-for-vscode), export the Postman environment to read both `{spe-container-type-id}` and `{spe-client-id}` in one place. The `{spe-client-id}` is also visible in the Microsoft Entra admin center under **Identity > Applications > App registrations > All applications**. + +### Step 2 — Clone the Fluid Examples repository {#step-2} + +Get the sample source, which includes the Item Counter app wired for SPE. + +```bash +git clone https://github.com/microsoft/FluidExamples.git +``` + +**Expected response:** the repository clones and a `FluidExamples` directory is created. + +**On failure:** +- `git: command not found` → install Git. +- Network/proxy error → configure `git` to use your proxy, then retry. + +### Step 3 — Move into the Item Counter directory {#step-3} + +The SPE-specific sample lives in `item-counter-spe`. + +```bash +cd FluidExamples/item-counter-spe +``` + +**Expected response:** the working directory changes to `item-counter-spe`. + +**On failure:** +- `No such file or directory` → the clone in [Step 2](#step-2) did not complete. Re-clone. + +### Step 4 — Create the `.env` file with your IDs {#step-4} + +The app reads its client ID and container type ID from environment variables. Create an `.env` file with the two values, no spaces. + +```bash +cat > .env <<'EOF' +SPE_CLIENT_ID={spe-client-id} +SPE_CONTAINER_TYPE_ID={spe-container-type-id} +EOF +``` + +**Expected response:** an `.env` file exists in `item-counter-spe` with both variables set. + +**On failure:** +- App later reports a missing variable → a key name is misspelled. Use exactly `SPE_CLIENT_ID` and `SPE_CONTAINER_TYPE_ID`. + +### Step 5 — Install dependencies {#step-5} + +Install the sample's Node.js packages. + +```bash +npm install +``` + +**Expected response:** `npm` completes with `node_modules` populated and a non-zero number of packages added. + +**On failure:** +- Peer-dependency or engine errors → confirm a supported Node.js version is active, then retry. + +### Step 6 — Start the development server {#step-6} + +Build and serve the app locally with Webpack. + +```bash +npm run dev +``` + +**Expected response:** Webpack finishes compiling and serves the app at `https://localhost:8080`. + +**On failure:** +- Port in use → stop the process on port 8080 or change the configured port, then re-run. +- Build error referencing env vars → the `.env` from [Step 4](#step-4) is missing or malformed. + +### Step 7 — Sign in and grant admin consent {#step-7} + +The app authenticates against your tenant and requests consent on first run. This is a browser interaction. + +```yaml +manual: + description: Open the running app, sign in with tenant admin credentials, and grant admin consent in the pop-up. + ui_path: Browser → https://localhost:8080 → sign in (admin credentials) → Grant admin consent in the pop-up window + api_equivalent: Admin consent can be assigned via POST /servicePrincipals/{service-principal-id}/appRoleAssignedTo — see /sharepoint/dev/embedded/development/auth#step-5 + verify: + description: The Item Counter UI loads after consent without an access-denied error. +``` + +**Expected response:** after consent, the Item Counter UI loads at `https://localhost:8080`. + +**On failure:** +- Access-denied after sign-in → admin consent was declined or the signing-in account is not an admin. See [Grant admin consent](/sharepoint/dev/embedded/development/auth#step-5). +- No container available → create a container of the same container type first. + +## Verify {#verify} + +Confirm real-time sync across two clients on the same tenant. + +```yaml +manual: + description: Copy the full app URL to a second browser (or send it to another user on the same tenant), sign in, and change the counter. + ui_path: Copy https://localhost:8080 URL → open in a second browser/tab → sign in (same tenant) → increment the counter + verify: + description: The Item Counter value updates live in both browsers, confirming Fluid is syncing state between clients. +``` + +The counter changes appear in both clients simultaneously. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| App fails to start with an env error | `.env` missing or misspelled keys | Recreate `.env` per [Step 4](#step-4) with exact key names. | +| Sign-in succeeds but content is access-denied | Admin consent not granted, or app not registered/consented | Complete [Step 7](#step-7); see [Authentication and authorization](/sharepoint/dev/embedded/development/auth). | +| No container found at runtime | No container of the app's container type exists | Create a container first. See [Container types](/sharepoint/dev/embedded/getting-started/containertypes). | +| Changes do not sync between clients | Second client is on a different tenant | Use credentials on the **same** tenant for both clients. | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`. See [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling). | + +## Next steps + +- [Office experiences](/sharepoint/dev/embedded/development/content-experiences/office-experience) +- [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) + +## Related + +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [VS Code extension for SharePoint Embedded](/sharepoint/dev/embedded/getting-started/spembedded-for-vscode) +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [SharePoint Embedded overview](/sharepoint/dev/embedded/overview) +- [Fluid Examples — Item Counter (GitHub)](https://github.com/microsoft/FluidExamples/tree/main/item-counter-spe) diff --git a/docs/embedded/spe-docs-agent-ready/development/limits-calling.md b/docs/embedded/spe-docs-agent-ready/development/limits-calling.md new file mode 100644 index 000000000..c7f9b3b74 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/limits-calling.md @@ -0,0 +1,136 @@ + +--- +title: SharePoint Embedded limits and calling patterns +description: Size limits, throttling behavior, resource-unit costs, and API rate limits for SharePoint Embedded, plus how to handle 429 and 503. +ms.topic: reference +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: reference + difficulty: intermediate + roles: [app-developer, enterprise-developer, owning-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/development/app-architecture + kind: concept + api_surface: [] + next_steps: + - uri: /sharepoint/dev/embedded/development/auth + when: always + related: + - uri: /sharepoint/dev/embedded/development/app-architecture + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + stability: preview + last_validated: proposed +--- + +# SharePoint Embedded limits and calling patterns + + +This reference lists the size limits, throttling behavior, and API rate limits for SharePoint Embedded (SPE), and the calling patterns that keep an application within them. + +> [!IMPORTANT] +> These are preview limits and are subject to change. Values marked with `*` can be increased on request. + +## Size limits + +| Resource | Limit | +|---|---| +| Container types a partner (owning) tenant can create | 25* | +| Container types an app can own | 1 | +| Containers of a container type per consuming tenant | 100,000* | +| Storage per container type per consuming tenant | 100 TB* | +| Files and folders per container | 30,000,000 | +| Storage per container | 25 TB | +| Files and folders with additive permissions per container | 5,000 | +| File size | 250 GB | +| Version count per file | 500 (automatic version history default) | +| Users shared per folder or file | 5,000 | + +## Throttling responses + +| Status code | Meaning | Required action | +|---|---|---| +| `429 Too Many Requests` | A service limit was hit | Honor the `Retry-After` header before retrying. | +| `503 Server Too Busy` | The service is temporarily overloaded | Honor the `Retry-After` header before retrying. | + +Both responses include a `Retry-After` header indicating how long to wait before retrying or making a new request. Throttled requests count toward usage limits, so failing to honor `Retry-After` can result in more throttling. + +### Best practices + +| Practice | Why | +|---|---| +| Reduce the number of concurrent requests | Lowers the chance of hitting per-container and per-app limits. | +| Avoid request spikes | Smooths usage so short bursts do not trip throttling. | +| Honor the `Retry-After` header | Ignoring it increases throttling because throttled requests still count. | +| Minimize permission operations | Permission operations cost the most resource units (see below), so reducing them raises effective call rate. | + +## Resource-unit cost per request + +API cost is normalized and expressed in **resource units**. Different operations cost different amounts. + +| Resource units per request | Operations | +|---|---| +| 1 | Single-item query, such as get item. | +| 2 | Multi-item query, such as list children, create, update, delete, and upload. | +| 5 | All permission resource operations, including `$expand=permissions`. | + +> [!NOTE] +> Microsoft reserves the right to change the API resource-unit cost. + +## API rate limits + +Rate limits are defined in resource units per minute. + +| Resource | Limit | +|---|---| +| Requests per container | 3,000 resource units per minute | +| Requests per app per tenant | 12,000 resource units per minute* | +| Requests per user | 600 resource units per minute | + +To estimate the request rate from a resource-unit limit, average about two resource units per request and divide the limit by 2. Reducing permission operations notably improves the call rate, because those operations have the largest impact on resource consumption. + +### Container creation rate limit + +| Condition | Limit | +|---|---| +| Per consuming tenant, during the tenant's peak hours | 5 new containers per second | +| Per consuming tenant, outside peak hours | Faster than 5 per second (no fixed peak-hour cap) | + +Requests beyond the peak-hour limit are rate limited. + +## Examples + +### Honor `Retry-After` on a throttled response + +```http +HTTP/1.1 429 Too Many Requests +Retry-After: 12 +Content-Type: application/json + +{ "error": { "code": "activityLimitReached", "message": "The request has been throttled." } } +``` + +Wait the number of seconds in `Retry-After` (here, 12) before retrying, then apply exponential backoff if throttling persists. + +### Estimate sustainable request rate for an app + +With a per-app limit of 12,000 resource units per minute and an average of 2 resource units per request: + +```text +12,000 resource units/min ÷ 2 resource units/request ≈ 6,000 requests/min ≈ 100 requests/sec +``` + +Permission-heavy workloads (5 units each) reach the limit far sooner: 12,000 ÷ 5 = 2,400 permission requests per minute. + +## See also + +- [Application architecture](/sharepoint/dev/embedded/development/app-architecture) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) +- [Microsoft Graph throttling guidance](https://learn.microsoft.com/en-us/graph/throttling) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/development/sharing-and-perm.md b/docs/embedded/spe-docs-agent-ready/development/sharing-and-perm.md new file mode 100644 index 000000000..b3564989b --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/sharing-and-perm.md @@ -0,0 +1,229 @@ + +--- +title: Share files and manage permissions in a SharePoint Embedded container +description: Grant additive item-level permissions, retrieve and remove them, and configure role-based and external sharing for a container. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: A specific file or folder in a container is shared with a user at a chosen permission level, and the container's sharing model is configured. + estimated_minutes: 20 + difficulty: intermediate + roles: [app-developer, enterprise-developer, owning-admin, consuming-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/development/auth + kind: how-to + - capability: container-type-owner + api_surface: + - id: getContainerDrive + method: GET + path: /storage/fileStorage/containers/{container-id}/drive + permissions: [FileStorageContainer.Selected] + - id: addContainerPermission + method: POST + path: /storage/fileStorage/containers/{container-id}/permissions + permissions: [FileStorageContainer.Selected] + - id: listContainerPermissions + method: GET + path: /storage/fileStorage/containers/{container-id}/permissions + permissions: [FileStorageContainer.Selected] + inputs: + - name: container-id + type: string + source: prior-step + - name: drive-id + type: string + source: prior-step + - name: item-id + type: string + source: prior-step + - name: permission-id + type: string + source: prior-step + - name: user-email + type: string + source: user-supplied + - name: container-type-id + type: uuid + source: prior-step + outputs: + - name: item-permission + type: object + verify: GET /drives/{drive-id}/items/{item-id}/permissions returns 200 listing the new grant + next_steps: + - uri: /sharepoint/dev/embedded/development/limits-calling + when: always + - uri: /sharepoint/dev/embedded/development/content-experiences/office-experience + when: always + related: + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/development/app-architecture + - uri: /sharepoint/dev/embedded/development/limits-calling + stability: ga + last_validated: proposed +--- + +# Share files and manage permissions in a SharePoint Embedded container + + +By the end of this how-to, you can grant a single file or folder in a container an extra ("additive") permission for a specific user, read and remove that grant, and configure the container type's role-based and external sharing models. In SharePoint Embedded (SPE), content always inherits permissions from its parent hierarchy; you cannot alter that inheritance, but you can **extend** access to individual items. + +## Prerequisites + +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — the app must hold `FileStorageContainer.Selected` and be registered on the consuming tenant. +- Capability: an existing, active container and a delegated (on-behalf-of-user) token. Additive permissions cannot be granted with app-only permissions. +- Capability: container-type-owner rights to change the role-based sharing model (set by the owning application's developers). + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{container-id}` | string | A prior step (create/list containers). | +| `{drive-id}` | string | From [Step 1](#step-1) — the container's drive. | +| `{item-id}` | string | The file or folder `driveItem` ID being shared. | +| `{permission-id}` | string | Returned when a permission is created; used to read or delete it. | +| `{user-email}` | string | User-supplied recipient address. | +| `{container-type-id}` | uuid | The container type whose sharing model is being configured. | + +## Steps + +### Step 1 — Get the container's drive {#step-1} + +Additive permissions are applied to `driveItem` resources, so first resolve the container's drive to obtain `{drive-id}`. + +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containers/{container-id}/drive +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` with a `drive` whose `id` is `{drive-id}`. + +**On failure:** +- `403 Forbidden` → app not registered or not consented on this tenant. See [Authentication and authorization](/sharepoint/dev/embedded/development/auth). +- `404 Not Found` → `{container-id}` is wrong or the container is deleted. + +### Step 2 — Grant an additive permission on a file or folder {#step-2} + +Extend access to one item for a user beyond their container role. Use the `driveItem` invite endpoint; `sendInvitation` must be `false`. + +```http +POST https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/invite +Authorization: Bearer {token} +Content-Type: application/json + +{ + "recipients": [ { "email": "{user-email}" } ], + "roles": [ "write" ], + "sendInvitation": false, + "requireSignIn": true +} +``` + +**Expected response:** `200 OK` with the created `permission` whose `id` is `{permission-id}`. + +**On failure:** +- `400 Bad Request` → the target `{item-id}` is the container's root folder. Additive permissions cannot be applied to root (equivalent to adding a container role); grant a [container permission](/sharepoint/dev/embedded/development/auth#container-user-permission-roles) instead. +- `403 Forbidden` → an app-only token was used. Additive permissions require a delegated token. +- `403 Forbidden` → guest sharing is blocked by the consuming tenant configuration. See [Step 6](#step-6). + +### Step 3 — Retrieve item permissions {#step-3} + +Read the permissions on the item to confirm the grant and capture `{permission-id}` values. + +```http +GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/permissions +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` with a collection of `permission` objects including the grant from [Step 2](#step-2). + +**On failure:** +- `404 Not Found` → `{item-id}` or `{drive-id}` is wrong. + +### Step 4 — Delete an additive permission {#step-4} + +Remove the additive grant. You can delete it only on the `driveItem` where it was originally added. + +```http +DELETE https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/permissions/{permission-id} +Authorization: Bearer {token} +``` + +**Expected response:** `204 No Content`. + +**On failure:** +- `404 Not Found` → `{permission-id}` does not exist on this item, or you are targeting an item other than the one where the permission was added. + +### Step 5 — Set the role-based sharing model on the container type {#step-5} + +Choose who may add new permissions to files. The **open** model (default) lets any member or guest with edit permission add permissions; the **restrictive** model limits this to `owner` and `manager` roles. This is part of [container type configuration](/sharepoint/dev/embedded/getting-started/containertypes) and is set by the owning application's developers. + +```pwsh +Set-SPOContainerTypeConfiguration ` + -ContainerTypeId {container-type-id} ` + -SharingRestricted $false +``` + +**Expected response:** the cmdlet returns the updated container type configuration with `SharingRestricted` set as specified. + +**On failure:** +- `Access denied` → the account is not a developer/owner of the container type. Run as the owning application's developer admin. +- Cmdlet not found → install the latest SharePoint Online Management Shell. + +> [!NOTE] +> This is a control-plane action with no Microsoft Graph equivalent today. See `api-surface.json` gap `setUpContainerTypeBilling` for related control-plane gaps; container type sharing configuration is likewise PowerShell-only. + +### Step 6 — Override tenant sharing capability for the application {#step-6} + +A consuming-tenant SharePoint Embedded admin can let one application's containers use a sharing capability different from the tenant default (for example, allow guest sharing where the tenant blocks it). + +```pwsh +Set-SPOApplication ` + -OwningApplicationId {owning-application-id} ` + -OverrideTenantSharingCapability $true ` + -SharingCapability ExternalUserSharingOnly +``` + +**Expected response:** the cmdlet confirms the override is applied to the application's containers. + +**On failure:** +- `Access denied` → the account is not a consuming-tenant SharePoint Embedded admin. Use that role. + +## Verify {#verify} + +List the item's permissions and confirm the additive grant from [Step 2](#step-2) is present (or absent after [Step 4](#step-4)). + +```http +GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/permissions +Authorization: Bearer {token} +``` + +Returns `200 OK`. The collection contains the expected `permission` with the role you granted. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `401 Unauthorized` | Token missing/expired or wrong scope | Re-acquire a delegated token with `FileStorageContainer.Selected`. | +| `403 Forbidden` on invite | App-only token used, or guest sharing blocked | Use a delegated token; override sharing via [Step 6](#step-6) if guests are required. | +| `400 Bad Request` on invite | Targeting the container root folder | Apply additive permissions to a non-root item; use container roles for whole-container access. | +| Cannot delete a permission | Deleting from a different item than where it was added | Delete on the originating `driveItem` only. | +| `429 Too Many Requests` | Throttled; permission operations cost 5 resource units | Honor `Retry-After`; reduce permission calls. See [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling). | + +## Next steps + +- [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) +- [Office experiences](/sharepoint/dev/embedded/development/content-experiences/office-experience) + +## Related + +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Application architecture](/sharepoint/dev/embedded/development/app-architecture) +- [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) +- [driveItem: invite (Microsoft Graph)](https://learn.microsoft.com/en-us/graph/api/driveitem-invite) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/development/tutorials/doc-processing-acs.md b/docs/embedded/spe-docs-agent-ready/development/tutorials/doc-processing-acs.md new file mode 100644 index 000000000..953504bc0 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/tutorials/doc-processing-acs.md @@ -0,0 +1,354 @@ +--- +title: Process documents in a container with Azure AI Document Intelligence +description: Extract invoice fields from files added to a SharePoint Embedded container and write the results back as JSON, triggered by webhooks. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: how-to + outcome: When a supported file is added or updated in a container, the app reads the change via the drive delta feed, extracts invoice fields with Azure AI Document Intelligence, and writes a `-extracted-fields.json` file back to the same folder. + estimated_minutes: 40 + difficulty: intermediate + roles: [app-developer] + prerequisites: + - uri: /sharepoint/dev/embedded/development/tutorials/using-webhooks + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: concept + - capability: azure-subscription + api_surface: + - id: getContainerDrive + method: GET + path: /storage/fileStorage/containers/{container-id}/drive + permissions: [FileStorageContainer.Selected] + - id: listDriveItems + method: GET + path: /drives/{drive-id}/items/{item-id}/children + permissions: [FileStorageContainer.Selected] + - id: downloadFile + method: GET + path: /drives/{drive-id}/items/{item-id}/content + permissions: [FileStorageContainer.Selected] + - id: uploadFile + method: PUT + path: /drives/{drive-id}/items/{parent-id}:/{filename}:/content + permissions: [FileStorageContainer.Selected] + inputs: + - name: drive-id + type: string + source: prior-step + - name: item-id + type: string + source: prior-step + - name: parent-id + type: string + source: prior-step + - name: filename + type: string + source: generated + - name: delta-token + type: string + source: prior-step + - name: dac-resource-endpoint + type: string + source: azure-portal + - name: dac-resource-key + type: string + source: azure-portal + outputs: + - name: extracted-fields-json + type: string + verify: GET /drives/{drive-id}/items/{item-id}/children lists a new `-extracted-fields.json` item + next_steps: + - uri: /sharepoint/dev/embedded/development/tutorials/metadata + when: always + - uri: /sharepoint/dev/embedded/development/declarative-agent/sharepoint-embedded-knowledge-source + when: needs-search + related: + - uri: /sharepoint/dev/embedded/development/tutorials/using-webhooks + - uri: /sharepoint/dev/embedded/development/limits-calling + stability: ga + last_validated: proposed +--- + +# Process documents in a container with Azure AI Document Intelligence + + +At the end of this how-to, your SharePoint Embedded application reacts to a webhook notification by reading the container's drive delta feed, downloading each newly added or updated invoice (JPEG, JPG, PNG, BMP, TIFF, or PDF), extracting fields with the Azure AI Document Intelligence `prebuilt-invoice` model, and writing the extracted fields back to the same folder as a `-extracted-fields.json` file. + +> [!NOTE] +> Azure AI Document Intelligence was previously branded Azure Cognitive Services Form Recognizer. The `@azure/ai-form-recognizer` SDK client (`DocumentAnalysisClient`) is used here. + +## Prerequisites + +- [Using webhooks](/sharepoint/dev/embedded/development/tutorials/using-webhooks) — this how-to extends the webhook sample app; you need a working change-notification subscription on your container's drive before you start. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — the app must hold a Microsoft Graph token with `FileStorageContainer.Selected`. +- Capability: `azure-subscription` — required to create the Azure AI multi-service or Document Intelligence resource. +- An Azure AI Document Intelligence (or multi-service) resource. Create one with [Create a multi-service resource for Azure AI services](https://learn.microsoft.com/azure/ai-services/multi-service-resource?tabs=windows&pivots=azportal) or [Get started with Document Intelligence](https://learn.microsoft.com/azure/ai-services/document-intelligence/quickstarts/get-started-sdks-rest-api). After creation you have an endpoint and a key. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{drive-id}` | string | The container's drive `id` from [`getContainerDrive`](/sharepoint/dev/embedded/development/tutorials/using-webhooks) | +| `{item-id}` | string | The changed `driveItem` `id` from the delta feed | +| `{parent-id}` | string | `parentReference.id` of the changed item | +| `{filename}` | string | Generated as `-extracted-fields.json` | +| `{delta-token}` | string | The `token` query value carried forward from the previous delta response (`@odata.nextLink` / `@odata.deltaLink`) | +| `{dac-resource-endpoint}` | string | Azure portal → your Document Intelligence resource → Keys and Endpoint (`DAC_RESOURCE_ENDPOINT`) | +| `{dac-resource-key}` | string | Azure portal → your Document Intelligence resource → Keys and Endpoint (`DAC_RESOURCE_KEY`) | + +## Steps + +### Step 1 — Read drive changes from the delta feed {#step-1} + +When a webhook notification arrives, enumerate the items that changed since your last delta token so you process only new or updated files. In `GraphProvider.ts`, implement `getDriveChanges` to page through the delta feed and persist the latest token per drive. + +```typescript +public static async getDriveChanges(driveId: string): Promise { + let changedItems: any[] = []; + const driveDeltaBasePath: string = `/drives/${driveId}/items/root/delta`; + let driveDeltaTokenParams: string = ""; + let hasMoreChanges: boolean = true; + try { + do { + if (this.changeTokens.has(driveId)) { + driveDeltaTokenParams = `?token=${this.changeTokens.get(driveId)}`; + } + const response = await this.graphClient.api(driveDeltaBasePath + driveDeltaTokenParams).get(); + changedItems.push(...response.value); + if (response['@odata.nextLink']) { + const token = new URL(response['@odata.nextLink']).searchParams.get('token'); + this.changeTokens.set(driveId, token); + } else { + hasMoreChanges = false; + const token = new URL(response['@odata.deltaLink']).searchParams.get('token'); + this.changeTokens.set(driveId, token); + } + } while (hasMoreChanges); + } catch (err) { + console.log(err); + } + return changedItems; +} +``` + +The underlying call is `GET /drives/{drive-id}/items/root/delta?token={delta-token}`. + +**Expected response:** `200 OK`. Each page carries a `value` array of changed `driveItem` resources plus either an `@odata.nextLink` (more pages) or an `@odata.deltaLink` (caught up). Persist the `token` from whichever link is present. + +**On failure:** +- `404 Not Found` (`itemNotFound`) → `{drive-id}` is wrong, or the container was deleted. Re-fetch the drive id with `GET /storage/fileStorage/containers/{container-id}/drive`. +- `410 Gone` (`resyncRequired`) → the stored `{delta-token}` expired. Drop the token and re-run the loop from `.../root/delta` to do a full resync. + +### Step 2 — Fetch each changed item's metadata {#step-2} + +You need the item's name (to test the extension) and its `@microsoft.graph.downloadUrl` (to stream the content). In `GraphProvider.ts`, add `getDriveItem`. + +```typescript +public static async getDriveItem(driveId: string, itemId: string): Promise { + return await this.graphClient.api(`/drives/${driveId}/items/${itemId}`).get(); +} +``` + +The underlying call is `GET /drives/{drive-id}/items/{item-id}`. + +**Expected response:** `200 OK` with a `driveItem` that includes `name`, `parentReference.id`, and a short-lived `@microsoft.graph.downloadUrl`. + +**On failure:** +- `404 Not Found` → the item was deleted between the delta read and this fetch. Skip it and continue. +- `403 Forbidden` (`accessDenied`) → the app token lacks `FileStorageContainer.Selected` on this container. Re-acquire the token. See [Authentication and authorization](/sharepoint/dev/embedded/development/auth). + +### Step 3 — Configure the Document Intelligence client {#step-3} + +Store the Azure resource credentials so the analyzer can call Document Intelligence. Create `ReceiptProcessor.ts` and add the `dac` client, reading the endpoint and key from environment variables. + +```typescript +private static dac = new DocumentAnalysisClient( + `${process.env["DAC_RESOURCE_ENDPOINT"]}`, + new AzureKeyCredential(`${process.env["DAC_RESOURCE_KEY"]}`) +); +``` + +Set `DAC_RESOURCE_ENDPOINT` to `{dac-resource-endpoint}` and `DAC_RESOURCE_KEY` to `{dac-resource-key}`. + +> [!WARNING] +> `{dac-resource-key}` is a secret. Keep it in an environment variable or a secret store; do not commit it to source control. Rotate it in the Azure portal if it leaks. + +This step has no Graph call. Verify it by confirming both environment variables resolve at startup (the constructor throws if the endpoint is empty). + +**On failure:** +- Constructor throws `Endpoint URL is malformed` → `DAC_RESOURCE_ENDPOINT` is empty or not a valid URL. Re-copy the endpoint from the Azure portal Keys and Endpoint blade. + +### Step 4 — Download the file content as a stream {#step-4} + +Stream the file bytes from the container so you can pass them straight to the analyzer without buffering the whole file. In `ReceiptProcessor.ts`, add `getDriveItemStream`, authorizing the request with the Graph access token. + +```typescript +private static async getDriveItemStream(url: string): Promise { + const token = GraphProvider.graphAccessToken; + const config: AxiosRequestConfig = { + method: "get", + url: url, + headers: { + "Authorization": `Bearer ${token}` + }, + responseType: 'stream' + }; + const response = await axios.get(url, config); + return response.data; +} +``` + +The `url` is the item's `@microsoft.graph.downloadUrl`; this is equivalent to `GET /drives/{drive-id}/items/{item-id}/content`. + +**Expected response:** `200 OK` with the raw file bytes as a readable stream. + +**On failure:** +- `401 Unauthorized` → the `@microsoft.graph.downloadUrl` is pre-authorized and short-lived; if it expired, re-fetch the item ([#step-2](#step-2)) to get a fresh URL. +- `403 Forbidden` → token missing `FileStorageContainer.Selected`. Re-acquire it. + +### Step 5 — Extract invoice fields {#step-5} + +Run the `prebuilt-invoice` model over the stream and strip bulky positional fields you do not need to store. In `ReceiptProcessor.ts`, add `analyzeReceiptStream` and `removeUnwantedFields`. + +```typescript +private static async analyzeReceiptStream(stream: Readable): Promise { + const poller = await this.dac.beginAnalyzeDocument("prebuilt-invoice", stream, { + onProgress: ({ status }) => { + console.log(`status: ${status}`); + }, + }); + + const { + documents: [result] = [], + } = await poller.pollUntilDone(); + + const fields = result?.fields; + this.removeUnwantedFields(fields); + return fields; +} + +private static removeUnwantedFields(fields: any) { + for (const prop in fields) { + if (prop === 'boundingRegions' || prop === 'content' || prop === 'spans') { + delete fields[prop]; + } + if (typeof fields[prop] === 'object') { + this.removeUnwantedFields(fields[prop]); + } + } +} +``` + +> [!NOTE] +> `prebuilt-invoice` is one of several prebuilt models. Swap the first argument of `beginAnalyzeDocument` to use a different model (for example `prebuilt-receipt` or a custom model id). + +**Expected response:** the long-running analyze operation reaches `succeeded` and returns a `documents` array; `documents[0].fields` holds the extracted invoice fields. + +**On failure:** +- `InvalidRequest` / `InvalidContent` → the file is not a supported format or is corrupt. Confirm the extension is JPEG, JPG, PNG, BMP, TIFF, or PDF before calling. +- `401` / `403` from the Document Intelligence endpoint → `{dac-resource-key}` is wrong or revoked. Re-copy the key from the Azure portal. +- `429 Too Many Requests` → the Document Intelligence resource is throttling. Honor `Retry-After` and back off. + +### Step 6 — Write the extracted fields back to the container {#step-6} + +Persist the result as a JSON file in the same folder as the source file so it travels with the document. In `GraphProvider.ts`, add `addDriveItem`. + +```typescript +public static async addDriveItem(driveId: string, parentId: any, fileName: string, receiptString: string) { + await this.graphClient.api(`/drives/${driveId}/items/${parentId}:/${fileName}:/content`).put(receiptString); +} +``` + +The underlying call is `PUT /drives/{drive-id}/items/{parent-id}:/{filename}:/content`. + +```http +PUT https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{parent-id}:/{filename}:/content +Authorization: Bearer {token} +Content-Type: application/json + +{ "...extracted invoice fields..." } +``` + +**Expected response:** `201 Created` (or `200 OK` if the JSON file already existed) with the new `driveItem`. + +**On failure:** +- `403 Forbidden` (`accessDenied`) → token lacks write access (`FileStorageContainer.Selected`). Re-acquire the token. +- `423 Locked` → the container is locked read-only. Unlock it before writing. See [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling). +- `507 Insufficient Storage` → the container or container type quota is exhausted. + +### Step 7 — Drive the pipeline from a change notification {#step-7} + +Tie the steps together so each changed, supported file is downloaded, analyzed, and written back. In `ReceiptProcessor.ts`, add `processDrive`. + +```typescript +export abstract class ReceiptProcessor { + + public static async processDrive(driveId: string): Promise { + const changedItems = await GraphProvider.getDriveChanges(driveId); + for (const changedItem of changedItems) { + try { + const item = await GraphProvider.getDriveItem(driveId, changedItem.id); + const extension = this.getFileExtension(item.name); + if (this.SUPPORTED_FILE_EXTENSIONS.includes(extension.toLowerCase())) { + const url = item["@microsoft.graph.downloadUrl"]; + const receipt = await this.analyzeReceiptStream(await this.getDriveItemStream(url)); + const receiptString = JSON.stringify(receipt, null, 2); + const fileName = this.getFileDisplayName(item.name) + "-extracted-fields.json"; + const parentId = item.parentReference.id; + await GraphProvider.addDriveItem(driveId, parentId, fileName, receiptString); + } + } catch (error) { + console.log(error); + } + } + } +} +``` + +Restart the app, re-establish the ngrok tunnel, and recreate the delta-change subscription on the container (per [Using webhooks](/sharepoint/dev/embedded/development/tutorials/using-webhooks)). + +**Expected response:** the console logs each changed file name; for each supported file a `-extracted-fields.json` item appears in the same folder. + +**On failure:** +- No items logged after uploading a file → the webhook subscription expired or the tunnel is down. Recreate both, then upload again. + +## Verify {#verify} + +Upload a supported invoice file (JPEG, JPG, PNG, BMP, TIFF, or PDF) to the container, wait for the notification to process, then list the folder's children. + +```http +GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{parent-id}/children +Authorization: Bearer {token} +``` + +Returns `200 OK` and the `value` array contains a `-extracted-fields.json` item whose name matches the uploaded file. Download it to confirm it holds the extracted invoice fields. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `410 Gone` (`resyncRequired`) on delta | Stored `{delta-token}` expired | Discard the token and call `.../root/delta` with no token to resync | +| No JSON file produced for an uploaded file | Extension not in the supported set | Upload JPEG, JPG, PNG, BMP, TIFF, or PDF only | +| `401`/`403` from Document Intelligence | Wrong or revoked `{dac-resource-key}` or `{dac-resource-endpoint}` | Re-copy both from the Azure portal Keys and Endpoint blade | +| `401 Unauthorized` on download stream | Pre-authorized `@microsoft.graph.downloadUrl` expired | Re-fetch the item ([#step-2](#step-2)) for a fresh URL | +| `423 Locked` on write-back | Container is locked read-only | Unlock the container, then retry | +| `429 Too Many Requests` | Graph or Document Intelligence throttling | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps + +- [Using metadata on containers](/sharepoint/dev/embedded/development/tutorials/metadata) — promote extracted fields into queryable container columns. +- [AI knowledge source in Microsoft Foundry](/sharepoint/dev/embedded/development/declarative-agent/sharepoint-embedded-knowledge-source) — ground an agent on the processed content. + +## Related + +- [Using webhooks](/sharepoint/dev/embedded/development/tutorials/using-webhooks) +- [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) +- [Track changes for a drive (delta)](https://learn.microsoft.com/graph/api/driveitem-delta) +- [Upload or replace the contents of a driveItem](https://learn.microsoft.com/graph/api/driveitem-put-content) diff --git a/docs/embedded/spe-docs-agent-ready/development/tutorials/launch-experience.md b/docs/embedded/spe-docs-agent-ready/development/tutorials/launch-experience.md new file mode 100644 index 000000000..dba0cb357 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/tutorials/launch-experience.md @@ -0,0 +1,215 @@ +--- +title: Configure the launch mode for Office files in SharePoint Embedded +description: Force view or edit mode for Office files and open them directly in Office desktop clients from a SharePoint Embedded container. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: A reader-supplied Office file in a SharePoint Embedded container opens in a controlled launch mode — forced view, forced edit, or directly in an Office desktop client. + estimated_minutes: 20 + difficulty: intermediate + roles: [app-developer] + prerequisites: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: concept + - capability: container-type-owner + api_surface: + - id: getContainer + method: GET + path: /storage/fileStorage/containers/{containerId} + permissions: [FileStorageContainer.Selected] + - id: getContainerDrive + method: GET + path: /storage/fileStorage/containers/{containerId}/drive + permissions: [FileStorageContainer.Selected] + - id: listDriveItems + method: GET + path: /drives/{driveId}/items/{itemId}/children + permissions: [FileStorageContainer.Selected] + inputs: + - name: drive-id + type: string + source: prior-step + - name: item-id + type: string + source: prior-step + - name: token + type: string + source: prior-step + - name: launch-mode + type: enum + source: user-supplied + - name: file-name + type: string + source: prior-step + - name: folder-web-url + type: string + source: prior-step + outputs: + - name: modified-web-url + type: uri + verify: opening the URL renders the file in the requested action mode + next_steps: + - uri: /sharepoint/dev/embedded/development/tutorials/using-file-preview + when: always + - uri: /sharepoint/dev/embedded/development/content-experiences/office-experience + when: always + related: + - uri: /sharepoint/dev/embedded/development/content-experiences/office-experience + - uri: /sharepoint/dev/embedded/development/tutorials/using-file-preview + stability: ga + last_validated: proposed +--- + +# Configure the launch mode for Office files in SharePoint Embedded + + +By the end of this how-to, you have a launch URL that opens an Office file from a SharePoint Embedded container in the mode you choose: forced read-only view, forced edit, or directly in an Office desktop client. The web rendering uses the file's `webUrl` (a Web Application Open Platform Interface, or WOPI, link); the desktop launch uses an Office URI scheme. + +## Prerequisites + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — you have an active container holding at least one Office file. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — you can acquire a bearer token with `FileStorageContainer.Selected`. +- Capability: `container-type-owner` — your app owns the container type for the target container. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{token}` | string | A bearer token with `FileStorageContainer.Selected` ([auth](/sharepoint/dev/embedded/development/auth)) | +| `{container-id}` | string | The container holding the file (a prior step) | +| `{drive-id}` | string | The container's drive `id` (from [Step 1](#step-1)) | +| `{item-id}` | string | The `driveItem` id of the target file (from [Step 2](#step-2)) | +| `{launch-mode}` | enum | One of `view`, `edit`, or `desktop` (user-supplied) | +| `{file-name}` | string | The file name, for example `MyDocument.docx` (from [Step 2](#step-2)) | +| `{folder-web-url}` | string | The `webUrl` of the parent folder (from [Step 2](#step-2)) | + +## Steps + +### Step 1 — Resolve the container's drive id {#step-1} + +WOPI and drive-item operations are addressed by `driveId`. Read the container's drive to get it. + +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containers/{container-id}/drive +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` with a `drive` resource. Record its `id` as `{drive-id}`. + +**On failure:** +- `404 Not Found` (`itemNotFound`) → the container is inactive or `{container-id}` is wrong. Activate the container, then retry. +- `403 Forbidden` (`accessDenied`) → the token lacks `FileStorageContainer.Selected` or the app has no permission on this container. + +### Step 2 — Read the file's webUrl and parent folder {#step-2} + +You need the file's `webUrl` for web modes and the parent folder `webUrl` plus the file name for desktop mode. List the children of the target folder and select those fields. + +```http +GET https://graph.microsoft.com/v1.0/drives/{drive-id}/root/children?$select=id,name,webUrl,parentReference,folder,file +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` with a `value` array. For the target file, record `id` as `{item-id}`, `name` as `{file-name}`, and `webUrl`. Read the parent folder's `webUrl` as `{folder-web-url}` (the folder's own `driveItem`). + +**On failure:** +- `400 Bad Request` (`invalidRequest`) → malformed `$select`. Remove unsupported fields and retry. +- `404 Not Found` → `{drive-id}` is wrong. Re-run [Step 1](#step-1). + +> [!NOTE] +> For an Office document, the `webUrl` returned by Graph is a WOPI link of the form `https://host/:w:r/contentstorage/.../doc2.aspx?sourcedoc={guid}&file={file-name}&action=default&mobileredirect=true`. The `action=default` segment determines the launch mode. + +### Step 3 — Force a web launch mode (view or edit) {#step-3} + +The default WOPI link opens with `action=default`. To force read-only view or forced edit, rewrite the `action` query parameter on the `webUrl`. This C# example parses the existing query and sets `action` to `view` (use `edit` for the editor). + +```csharp +string webUrl = "{web-url}"; // the WOPI webUrl from Step 2 + +System.UriBuilder builder = new System.UriBuilder(webUrl); +var queryDictionary = System.Web.HttpUtility.ParseQueryString(builder.Query); +queryDictionary["action"] = "view"; // set to "edit" to force the editor +builder.Query = queryDictionary.ToString(); +string modifiedWebUrl = builder.ToString(); +``` + +**Expected response:** No service call. `modifiedWebUrl` is a string carrying `action=view` (or `action=edit`); opening it renders the file in that mode. + +**On failure:** +- Empty or unchanged `action` → the source `webUrl` was not a WOPI link (the file type is not WOPI-renderable). Fall back to download or [file preview](/sharepoint/dev/embedded/development/tutorials/using-file-preview). +- Malformed URL exception → `{web-url}` was truncated. Re-read it from [Step 2](#step-2). + +> [!TIP] +> For the full set of WOPI `action` values, see [WOPI Discovery — WOPI Actions](https://learn.microsoft.com/microsoft-365/cloud-storage-partner-program/online/discovery#wopi-actions). + +### Step 4 — Build a desktop-client launch URI {#step-4} + +To open the file directly in an Office desktop client, build an Office URI scheme instead of a WOPI link. The scheme format is `:||`. + +Choose the scheme and command for `{launch-mode}`: + +| Scheme name | App | Command name | Meaning | +|---|---|---|---| +| `ms-word` | Word | `ofv` | Open File View | +| `ms-excel` | Excel | `ofe` | Open File Edit | +| `ms-powerpoint` | PowerPoint | `nft` | New From Template | + +Because the document `webUrl` points to Office Online, build the file URL in two parts — the parent folder `webUrl`, then the file name — and assemble the scheme: + +```text +ms-word:ofe|u|{folder-web-url}/{file-name} +``` + +This resolves to a launch URI such as: + +```text +ms-word:ofe|u|https://contoso.sharepoint.com/contentstorage/CSP_1234765465/Document%20Library/MyDocument.docx +``` + +**Expected response:** No service call. The string is a valid Office URI; opening it in a blank window or new tab launches the desktop client at the requested file. + +**On failure:** +- Nothing launches → the URI was opened in the same tab. Open it in a blank window or new tab. +- Office prompts repeatedly for sign-in → the user lacks permission on the container. Grant the user a role with [Add container permission](/sharepoint/dev/embedded/development/sharing-and-perm). + +> [!NOTE] +> The `nft` (New From Template) command uses a `|s|{save-location}` descriptor and may not behave as expected, because the container permission schema differs from SharePoint sites. For the full grammar, see [Office URI Schemes](https://learn.microsoft.com/office/client-developer/office-uri-schemes). + +## Verify {#verify} + +Open `modifiedWebUrl` (from [Step 3](#step-3)) in a blank browser tab. The file renders, and the mode matches `{launch-mode}`: + +- `action=view` → read-only; no editing surface. +- `action=edit` → the editor toolbar is present and the document is writable. + +For the desktop URI (from [Step 4](#step-4)), open it in a new tab; the corresponding Office desktop app launches with the file loaded. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `401 Unauthorized` on Graph calls | Token missing/expired or wrong scope | Re-acquire a token with `FileStorageContainer.Selected` (see **Inputs**) | +| `403 Forbidden` | App or user has no permission on the container | Grant a role via [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) | +| `webUrl` has no `action` parameter | File type is not WOPI-renderable | Use [file preview](/sharepoint/dev/embedded/development/tutorials/using-file-preview) or download instead | +| Forced mode is ignored | The WOPI link was opened in the same tab/frame | Open the URI in a blank window or new tab | +| Desktop URI does nothing | Office desktop client not installed, or URI opened in same tab | Install the client; open the URI in a new tab | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps + +- [File preview in an iFrame](/sharepoint/dev/embedded/development/tutorials/using-file-preview) +- [Office experiences](/sharepoint/dev/embedded/development/content-experiences/office-experience) + +## Related + +- [Office experiences](/sharepoint/dev/embedded/development/content-experiences/office-experience) +- [WOPI Discovery — WOPI Actions](https://learn.microsoft.com/microsoft-365/cloud-storage-partner-program/online/discovery#wopi-actions) +- [Office URI Schemes](https://learn.microsoft.com/office/client-developer/office-uri-schemes) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/development/tutorials/metadata.md b/docs/embedded/spe-docs-agent-ready/development/tutorials/metadata.md new file mode 100644 index 000000000..dedd46250 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/tutorials/metadata.md @@ -0,0 +1,208 @@ +--- +title: Add queryable metadata to SharePoint Embedded containers and files +description: Define columns on a SharePoint Embedded container, set field values on files, and query drive items by their custom metadata. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: A SharePoint Embedded container carries a custom column, a file in its drive has values set for that column, and drive items can be filtered and ordered by the column value. + estimated_minutes: 15 + difficulty: intermediate + roles: [app-developer] + prerequisites: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: concept + - capability: container-type-owner + api_surface: + - id: createColumn + method: POST + path: /storage/fileStorage/containers/{containerId}/columns + permissions: [FileStorageContainer.Selected] + - id: listColumns + method: GET + path: /storage/fileStorage/containers/{containerId}/columns + permissions: [FileStorageContainer.Selected] + - id: getContainerDrive + method: GET + path: /storage/fileStorage/containers/{containerId}/drive + permissions: [FileStorageContainer.Selected] + inputs: + - name: container-id + type: string + source: prior-step + - name: drive-id + type: string + source: prior-step + - name: item-id + type: string + source: prior-step + - name: column-id + type: uuid + source: prior-step + - name: token + type: string + source: prior-step + outputs: + - name: column-id + type: uuid + verify: GET /beta/storage/fileStorage/containers/{container-id}/columns returns the column + - name: field-value + type: string + verify: GET /beta/drives/{drive-id}/items/{item-id}/listitem/fields returns the set value + next_steps: + - uri: /sharepoint/dev/embedded/development/content-experiences/search-content + when: needs-search + - uri: /sharepoint/dev/embedded/development/tutorials/using-webhooks + when: always + related: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/development/content-experiences/search-content + stability: beta + last_validated: proposed +--- + +# Add queryable metadata to SharePoint Embedded containers and files + + +By the end of this how-to, your container has a custom column (a `columnDefinition`), a file in the container's drive has a value set for that column, and you can filter and order drive items by the column value. Columns are defined per container instance — your app is responsible for defining and managing columns across all its containers. + +> [!IMPORTANT] +> The container `columns` operations and the `listitem/fields` query options shown here are on the Microsoft Graph **beta** endpoint (`https://graph.microsoft.com/beta`). The shape may change before general availability. Track promotion in [api-surface.json](/sharepoint/dev/embedded/api-surface.json). + +## Prerequisites + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — you have an active container and can read its drive. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — you can acquire a bearer token with `FileStorageContainer.Selected`. +- Capability: `container-type-owner` — column create/update/delete require a container **owner**; members can only read and list columns. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{token}` | string | A bearer token with `FileStorageContainer.Selected` ([auth](/sharepoint/dev/embedded/development/auth)) | +| `{container-id}` | string | The target container (a prior step) | +| `{drive-id}` | string | The container's drive `id` (from `GET /storage/fileStorage/containers/{container-id}/drive`) | +| `{item-id}` | string | The `driveItem` id of a file in the drive (user-supplied / prior step) | +| `{column-id}` | uuid | The created column `id` (from [Step 1](#step-1)) | + +## Steps + +### Step 1 — Create a text column on the container {#step-1} + +Define a `columnDefinition` so files in the container can carry queryable structured metadata. This example creates a single-line text column named `Title`. + +```http +POST https://graph.microsoft.com/beta/storage/fileStorage/containers/{container-id}/columns +Authorization: Bearer {token} +Content-Type: application/json + +{ + "description": "test", + "displayName": "Title", + "enforceUniqueValues": false, + "hidden": false, + "indexed": false, + "name": "Title", + "text": { + "allowMultipleLines": false, + "appendChangesToExistingText": false, + "linesForEditing": 0, + "maxLength": 255 + } +} +``` + +**Expected response:** `201 Created` with the `columnDefinition`. Record its `id` as `{column-id}`. + +**On failure:** +- `400 Bad Request` (`invalidRequest`) → the `name` breaks a column naming rule (see the note below), or `text.maxLength` exceeds 255. +- `403 Forbidden` (`accessDenied`) → the caller is a container member, not an owner. Only owners create columns. + +> [!NOTE] +> Column `name` must not contain `!`; must not start with a digit, period, minus, or `?`; must not contain spaces or non-alphanumeric characters except `_`; must not look like an `A1`/`R1C1` cell reference; must not be a localized form of "true"/"false"; and must not be a reserved name such as `Author`, `Created`, or `Description`. The `note` column type is not supported. + +### Step 2 — Set the column value on a file {#step-2} + +Files carry column values as `listItem` fields. Patch the `listitem/fields` of the file's `driveItem` to set values for your columns. + +```http +PATCH https://graph.microsoft.com/beta/drives/{drive-id}/items/{item-id}/listitem/fields +Authorization: Bearer {token} +Content-Type: application/json + +{ + "Color": "Fuchsia", + "Quantity": 934 +} +``` + +**Expected response:** `200 OK` with the updated field set, for example `{ "Name": "Widget", "Color": "Fuchsia", "Quantity": 934 }`. + +**On failure:** +- `400 Bad Request` → a field name has no matching column on the container. Create the column first via [Step 1](#step-1). +- `404 Not Found` → `{item-id}` or `{drive-id}` is wrong. Re-read the drive ([Step 4](#step-4)) and the item id. + +> [!NOTE] +> To clear a value, PATCH the field to `null` (for example `{ "Color": null }`). The response omits the cleared field. + +### Step 3 — Query drive items by the custom column {#step-3} + +Once values are set, filter and order drive items by their column values using OData query options on `listitem/fields`. This example orders by `TestField` and filters to values starting with `3`. + +```http +GET https://graph.microsoft.com/beta/drives/{drive-id}/items?$orderby=listitem/fields/TestField asc&$filter=startswith(listitem/fields/TestField,'3')&$expand=listitem($expand=fields) +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` with a `value` array of matching drive items, each carrying its `listitem/fields/TestField` value. + +**On failure:** +- `400 Bad Request` (`invalidRequest`) → the column is not `indexed`, or the field referenced in `$filter`/`$orderby` does not exist. Recreate the column with `"indexed": true` and confirm the field name. +- `501 Not Implemented` → the OData option is unsupported on this drive. Reduce to `$expand=listitem($expand=fields)` and filter client-side. + +## Verify {#verify} + +Confirm the column exists and the value is set. + +```http +GET https://graph.microsoft.com/beta/storage/fileStorage/containers/{container-id}/columns +Authorization: Bearer {token} +``` + +Returns `200 OK` with a `value` array that includes a column whose `id` equals `{column-id}`. Then read the file's fields: + +```http +GET https://graph.microsoft.com/beta/drives/{drive-id}/items/{item-id}/listitem/fields?$select=Color,Quantity +Authorization: Bearer {token} +``` + +Returns `200 OK` with the values set in [Step 2](#step-2). + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `401 Unauthorized` | Token missing/expired or wrong scope | Re-acquire a token with `FileStorageContainer.Selected` (see **Inputs**) | +| `403 Forbidden` on create/update/delete column | Caller is a container member, not owner | Use an owner identity; members can only read/list columns | +| `400 Bad Request` on column create | Invalid column `name` or `maxLength` > 255 | Apply the naming rules in [Step 1](#step-1); cap `maxLength` at 255 | +| `400 Bad Request` on field PATCH | No matching column for the field | Create the column first ([Step 1](#step-1)) | +| `$filter`/`$orderby` rejected | Column not `indexed` | Recreate the column with `"indexed": true` | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps + +- [Search content](/sharepoint/dev/embedded/development/content-experiences/search-content) +- [Using webhooks](/sharepoint/dev/embedded/development/tutorials/using-webhooks) + +## Related + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [Search content](/sharepoint/dev/embedded/development/content-experiences/search-content) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/development/tutorials/migrate-abs-to-spe.md b/docs/embedded/spe-docs-agent-ready/development/tutorials/migrate-abs-to-spe.md new file mode 100644 index 000000000..4df88fe87 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/tutorials/migrate-abs-to-spe.md @@ -0,0 +1,325 @@ +--- +title: Migrate content from Azure Blob Storage to a SharePoint Embedded container +description: Copy blobs from an Azure Blob Storage container into a SharePoint Embedded container with C#, rebuilding folder structure and uploading via Graph upload sessions. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: how-to + outcome: Every blob in a source Azure Blob Storage container is copied into a target SharePoint Embedded container, with the flat blob namespace rebuilt as a folder hierarchy under a top folder named after the source container; failures are written to a re-runnable output file. + estimated_minutes: 60 + difficulty: advanced + roles: [app-developer, migration-engineer] + prerequisites: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: concept + - capability: azure-subscription + - capability: spe-admin + api_surface: + - id: getContainer + method: GET + path: /storage/fileStorage/containers/{container-id} + permissions: [FileStorageContainer.Selected] + - id: listContainers + method: GET + path: /storage/fileStorage/containers?$filter=containerTypeId eq {container-type-id} + permissions: [FileStorageContainer.Selected] + - id: listDriveItems + method: GET + path: /drives/{drive-id}/items/{parent-folder-id}/children + permissions: [FileStorageContainer.Selected] + inputs: + - name: sas-url + type: string + source: user-supplied + - name: tenant-id + type: uuid + source: entra-portal + - name: client-id + type: uuid + source: app-registration + - name: container-id + type: string + source: prior-step + - name: blob-file + type: string + source: user-supplied + - name: output-file + type: string + source: user-supplied + outputs: + - name: migrated-items + type: string + verify: GET /drives/{drive-id}/items/{parent-folder-id}/children lists a top folder named after the source container with the migrated tree beneath it + next_steps: + - uri: /sharepoint/dev/embedded/development/tutorials/metadata + when: always + - uri: /sharepoint/dev/embedded/development/content-experiences/search-content + when: needs-search + related: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/development/limits-calling + stability: ga + last_validated: proposed +--- + +# Migrate content from Azure Blob Storage to a SharePoint Embedded container + + +At the end of this how-to, every blob in a source Azure Blob Storage (ABS) container has been copied into a target SharePoint Embedded (SPE) container. The sample app rebuilds the flat blob namespace into a folder hierarchy under a top folder named after the source container, uploads each file with a Microsoft Graph upload session, skips files that already exist at the destination, and writes any failures to an output file you can feed back in for an incremental re-run. The reference implementation is `MigrateABStoSPE` in the [SharePoint Embedded Samples repository](https://github.com/microsoft/SharePoint-Embedded-Samples/tree/main/Tools/migrate-from-blob-storage). + +> [!IMPORTANT] +> This sample copies content one file at a time through Graph upload sessions. SharePoint Embedded also exposes a server-side migration path (`createMigrationJob` / `provisionMigrationContainers`) for migrating from SharePoint-managed staging storage; that is a different mechanism and is not what this ABS-to-SPE sample uses. There is no documented rollback for a partial migration — see `api-surface.json` gap `migrationRollback`. Plan to re-run incrementally from the failed-blob output file rather than rolling back. + +## Prerequisites + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — you need an onboarded container type and a target container in the consuming tenant. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — the app registration must be granted `User.Read` and `FileStorageContainer.Selected`, with admin consent. +- Capability: `azure-subscription` — to host or read the source ABS container. +- Capability: `spe-admin` — the authenticating user needs at least the SharePoint Embedded Administrator or Global Administrator role. +- A Microsoft Entra app registration with a **Mobile and desktop applications** platform added and redirect URI `http://localhost` (required for the interactive browser sign-in used by the sample). See [Register an application](https://learn.microsoft.com/graph/auth-register-app-v2). +- .NET SDK 8.0.303 or later, on Windows, Linux, or macOS. +- A source ABS container and a **container-level Shared Access Signature (SAS) URL** with **Read** and **List** permission. See [Introduction to Azure Blob Storage](https://learn.microsoft.com/azure/storage/blobs/storage-blobs-introduction). + +> [!NOTE] +> The container type must be registered in the consuming tenant and the app installed there, even when the owning tenant and the consuming tenant are the same. See [Install your app in a customer tenant](/sharepoint/dev/embedded/development/tutorials/vendor-install-app-customer). + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{sas-url}` | string | Azure portal → source storage account → container → Shared access tokens; needs Read + List | +| `{tenant-id}` | uuid | The consuming SPE tenant's directory (tenant) ID from [Microsoft Entra admin center](https://entra.microsoft.com) | +| `{client-id}` | uuid | The app registration's Application (client) ID | +| `{container-id}` | string | The target SPE container ID from [`listContainers`](https://learn.microsoft.com/graph/api/filestorage-list-containers) | +| `{blob-file}` | string | Optional path to a file listing blobs to migrate (one blob name per line, no quotes) | +| `{output-file}` | string | Optional path where the failed-blob list is written for an incremental re-run | + +## Steps + +### Step 1 — Build the sample app {#step-1} + +Compile the sample so the migration binary is ready to run. From a terminal in the directory containing `Program.cs`, restore packages and build. The project references Microsoft Graph SDK 5.56.0, Azure.Identity 1.12.0, Azure.Storage.Blobs 12.21.0, CommandLineParser 2.9.1, and Newtonsoft.Json 13.0.3. + +```bash +dotnet --version +dotnet build +``` + +**Expected response:** `dotnet build` reports `Build succeeded` with 0 errors. + +**On failure:** +- `dotnet: command not found` → the .NET SDK is not installed or not on `PATH`. Install [.NET SDK 8.0.303](https://dotnet.microsoft.com/download/dotnet/8.0). +- Package restore errors → no network access to NuGet, or a pinned package version is unavailable. Restore connectivity, then re-run `dotnet build`. + +### Step 2 — Resolve the target container's drive {#step-2} + +Confirm the target `{container-id}` exists and is reachable before moving data. Read the container; the migration writes into its drive. + +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containers/{container-id} +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` with a `fileStorageContainer` whose `status` is `active`. + +**On failure:** +- `404 Not Found` → `{container-id}` is wrong, or the container type is not registered in this tenant. Verify with `GET /storage/fileStorage/containers?$filter=containerTypeId eq {container-type-id}`. +- `403 Forbidden` (`accessDenied`) → the app lacks `FileStorageContainer.Selected`, or admin consent was not granted. See [Install your app in a customer tenant](/sharepoint/dev/embedded/development/tutorials/vendor-install-app-customer). + +### Step 3 — Connect to the source and destination {#step-3} + +Open a read connection to the ABS container and an interactive Graph connection to SPE. The sample uses `InteractiveBrowserCredential`, which opens a browser for the consuming-tenant user to sign in; the redirect URI must match the `http://localhost` registered in [#step-1](#step-1) prerequisites. + +```csharp +// Source: Azure Blob Storage +_containerClient = new BlobContainerClient(new Uri(_containerLevelSASUrl)); + +// Destination: SharePoint Embedded via Microsoft Graph +string[] scopes = { "User.Read", "FileStorageContainer.Selected" }; +InteractiveBrowserCredentialOptions interactiveBrowserCredentialOptions = new InteractiveBrowserCredentialOptions() +{ + ClientId = clientId, + RedirectUri = new Uri("http://localhost"), +}; +InteractiveBrowserCredential interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveBrowserCredentialOptions); + +_graphClient = new GraphServiceClient(interactiveBrowserCredential, scopes, null); + +// Opens a browser to sign in with consuming-tenant credentials +var user = await _graphClient.Me.GetAsync(); +``` + +**Expected response:** the browser sign-in completes and `_graphClient.Me.GetAsync()` returns the signed-in user; the `BlobContainerClient` is constructed without error. + +**On failure:** +- `AuthenticationFailedException` / no browser opens → wrong `{client-id}`, or the redirect URI is not registered as a Mobile and desktop applications platform. Re-check the app registration. +- ABS `403 (AuthorizationFailure)` → the `{sas-url}` is expired or lacks Read/List. Regenerate the SAS with Read and List permission. + +### Step 4 — Enumerate the source blobs {#step-4} + +List the blobs to migrate. ABS stores blobs in a flat namespace, so the names carry any folder path as a prefix. If a `{blob-file}` was supplied, read it (one blob per line); otherwise enumerate the container. + +```csharp +var blobs = new List(); +await foreach (var blobItem in _containerClient.GetBlobsAsync()) +{ + blobs.Add(blobItem.Name); +} +return blobs; +``` + +**Expected response:** a non-empty list of blob names; the sample then sizes a `CountdownEvent` to `blobs.Count` so the thread pool knows how many files to migrate. + +**On failure:** +- Empty list when the container has data → the SAS lacks **List**, or you pointed at the wrong container. Regenerate the SAS with List. +- `{blob-file}` not found, or names wrapped in quotes → fix the path; the format is one blob name per line with no surrounding quotes. + +### Step 5 — Rebuild the folder hierarchy at the destination {#step-5} + +Recreate the implied folder tree in the container. The sample creates a top folder named after the source container, then parses each blob's path segments and creates one folder at a time, reusing folders that already exist. + +```csharp +// Create the top folder (named after the source container) under the drive root. +containerFolder = await _graphClient.CreateFolder(_containerName, "root"); + +foreach (var blobName in fileList) +{ + FileStructure fs = new FileStructure() { blobName = blobName }; + // Parse the flat blob name into folders; returns the parent folder id for the file. + fs.parentFolderId = TraverseBlobName(fs, containerFolder.Id); + // Queue the file for migration on the thread pool. + ThreadPool.QueueUserWorkItem(MigrateFile, fs); +} + +// Wait for all queued files to finish. +_countdown.Wait(); +``` + +`CreateFolder` issues `POST /drives/{drive-id}/items/{parent-folder-id}/children` with `@microsoft.graph.conflictBehavior: fail`, and `CheckIfItemExists` reads `GET /drives/{container-id}/items/{parent-folder-id}:/{item-path}` to skip folders that already exist. + +```csharp +var folder = new DriveItem +{ + Name = folderName, + Folder = new Folder(), + AdditionalData = new Dictionary() + { + { "@microsoft.graph.conflictBehavior", "fail" } + } +}; +var createdFolder = await _graphClient.Drives[_containerId].Items[parentFolderId].Children.PostAsync(folder); +``` + +**Expected response:** `201 Created` per new folder; an existing folder is detected by `CheckIfItemExists` and reused rather than recreated. + +**On failure:** +- `409 Conflict` (`nameAlreadyExists`) from `CreateFolder` → the folder already exists; the sample reuses it via `CheckIfItemExists`. No action needed. +- `403 Forbidden` → the signed-in user lacks write access on the container. Grant the user a writer/manager/owner role or re-consent `FileStorageContainer.Selected`. + +### Step 6 — Stream each file from ABS to SPE {#step-6} + +Migrate file bytes without staging them on disk: download the blob to a memory stream, then upload that stream to SPE through a Graph upload session in 320 KB chunks. `MigrateFile` runs on the thread pool and signals the countdown when done. + +```csharp +// Download the blob from ABS as a stream +BlobClient blobClient = _containerClient.GetBlobClient(blobName); +MemoryStream memoryStream = new MemoryStream(); +await blobClient.DownloadToAsync(memoryStream); +memoryStream.Position = 0; // rewind before upload + +// Upload the stream to SPE via an upload session +int _maxChunkSize = 320 * 1024; +var uploadSessionRequestBody = new CreateUploadSessionPostRequestBody() +{ + AdditionalData = new Dictionary + { + { "@microsoft.graph.conflictBehavior", "fail" } + } +}; +var uploadSession = await _graphClient.Drives[_containerId] + .Items[parentFolderId] + .ItemWithPath(fileName) + .CreateUploadSession + .PostAsync(uploadSessionRequestBody); + +var fileUploadTask = new LargeFileUploadTask(uploadSession, memoryStream, _maxChunkSize, _graphClient.RequestAdapter); +IProgress progress = new Progress(prog => Console.WriteLine($"Uploaded {fileName} {prog} bytes")); +var uploadResult = await fileUploadTask.UploadAsync(progress); + +_countdown.Signal(); +``` + +The upload session is created with `POST /drives/{drive-id}/items/{parent-folder-id}:/{filename}:/createUploadSession`; chunks are `PUT` to the returned `uploadUrl`. `conflictBehavior: fail` makes a file that already exists fail rather than overwrite, so re-runs are idempotent. + +**Expected response:** `uploadResult.UploadSucceeded` is `true`; the console logs `Uploaded {filename} {n} bytes`. + +**On failure:** +- `409 Conflict` (`nameAlreadyExists`) → the file already exists at the destination; this is expected on re-runs and the sample records it as "exists in destination", not a failure. +- `423 Locked` → the container is locked read-only. Unlock it, then re-run. +- `507 Insufficient Storage` → container or container-type quota exhausted. Increase quota or split the migration. +- `429 Too Many Requests` → throttling. Honor `Retry-After`; reduce thread-pool concurrency. See [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling). + +### Step 7 — Run the migration {#step-7} + +Run the built app with the source SAS URL and the SPE target coordinates. The two optional arguments let you migrate a specific blob list and capture failures for an incremental re-run. + +```bash +# line breaks added for readability +dotnet run Program.cs -- \ + --sasurl "{sas-url}" \ + --tenantid "{tenant-id}" \ + --clientid "{client-id}" \ + --containerid "{container-id}" \ + [ --blobfile "{blob-file}" --outputfile "{output-file}" ] +``` + +**Expected response:** the app prints each queued file, then a summary of total, success, exists-in-destination, and failed counts. If any files failed, it writes them to `{output-file}` and prints the re-run command. + +**On failure:** +- Process exits immediately with an auth error → re-check `{tenant-id}`, `{client-id}`, and that admin consent was granted for `FileStorageContainer.Selected`. +- Many files report `failed` with `403` → the signed-in user lacks write permission on the container, or the Mobile and desktop applications platform is missing from the app registration. + +## Verify {#verify} + +List the children of the target container's drive root and confirm the top folder (named after the source container) holds the migrated tree. + +```http +GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{parent-folder-id}/children +Authorization: Bearer {token} +``` + +Returns `200 OK` and the `value` array contains a folder named after the source container; descending into it reproduces the blob path hierarchy with the migrated files. Cross-check the run summary: `success + exists-in-destination` should equal the source blob count, with `failed` equal to 0. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| ABS `403 (AuthorizationFailure)` | `{sas-url}` expired or missing Read/List | Regenerate a container-level SAS with **Read** and **List** | +| File reported "already exists" and skipped | `conflictBehavior: fail` and the file is already at the destination | Expected; delete the destination file or switch to `replace` to overwrite | +| `{blob-file}` not found / not parsed | Wrong path, or blob names wrapped in quotes | One blob name per line, no quotes; fix the path | +| `403 Forbidden` from Graph | Missing `User.Read` + `FileStorageContainer.Selected`, no admin consent, or no console platform | Grant scopes and admin consent; add the Mobile and desktop applications platform | +| `423 Locked` on upload | Container locked read-only | Unlock the container, then re-run from `{output-file}` | +| `429 Too Many Requests` | Throttling under thread-pool concurrency | Honor `Retry-After`; lower concurrency. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | +| Partial migration, want to undo | No migration rollback exists (`api-surface.json` gap `migrationRollback`) | Re-run incrementally from `{output-file}`; do not expect server-side rollback | + +## Next steps + +- [Using metadata on containers](/sharepoint/dev/embedded/development/tutorials/metadata) — tag migrated files with queryable metadata. +- [Search content](/sharepoint/dev/embedded/development/content-experiences/search-content) — make migrated content discoverable. + +## Related + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) +- [Introduction to Azure Blob Storage](https://learn.microsoft.com/azure/storage/blobs/storage-blobs-introduction) +- [MigrateABStoSPE sample](https://github.com/microsoft/SharePoint-Embedded-Samples/tree/main/Tools/migrate-from-blob-storage) diff --git a/docs/embedded/spe-docs-agent-ready/development/tutorials/using-file-preview.md b/docs/embedded/spe-docs-agent-ready/development/tutorials/using-file-preview.md new file mode 100644 index 000000000..83f9ce7ab --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/tutorials/using-file-preview.md @@ -0,0 +1,229 @@ +--- +title: Embed a SharePoint Embedded file preview in an iFrame +description: Get a preview URL for a file in a SharePoint Embedded container with Microsoft Graph and render it in an iFrame, including PDF previewer options. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: A short-lived preview URL for a file in a SharePoint Embedded container is obtained from Microsoft Graph and rendered inside an iFrame in the reader's application. + estimated_minutes: 20 + difficulty: intermediate + roles: [app-developer] + prerequisites: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: concept + - capability: container-type-owner + api_surface: + # previewDriveItem is a standard Graph driveItem operation, not yet curated in api-surface.json. + # Validate against https://learn.microsoft.com/graph/api/driveitem-preview before publishing. + - id: previewDriveItem + method: POST + path: /drives/{driveId}/items/{itemId}/preview + permissions: [FileStorageContainer.Selected] + stability_note: not-in-api-surface.json — standard Graph driveItem:preview + - id: getContainerDrive + method: GET + path: /storage/fileStorage/containers/{containerId}/drive + permissions: [FileStorageContainer.Selected] + inputs: + - name: drive-id + type: string + source: prior-step + - name: item-id + type: string + source: prior-step + - name: token + type: string + source: prior-step + - name: file-name + type: string + source: prior-step + outputs: + - name: preview-url + type: uri + verify: the URL loads the file render inside an iFrame + next_steps: + - uri: /sharepoint/dev/embedded/development/tutorials/launch-experience + when: always + - uri: /sharepoint/dev/embedded/development/content-experiences/office-experience + when: always + related: + - uri: /sharepoint/dev/embedded/development/tutorials/launch-experience + - uri: /sharepoint/dev/embedded/development/content-experiences/office-experience + stability: ga + last_validated: proposed +--- + +# Embed a SharePoint Embedded file preview in an iFrame + + +By the end of this how-to, you have a short-lived preview URL for a file in a SharePoint Embedded container and render it inside an iFrame in your application — without the user needing a dedicated application. A wide range of file types is supported, including PDF, JPG, and MP4. The flow is two parts: call the Graph `driveItem` preview endpoint to obtain a `getUrl`, then point an iFrame at that URL. + +## Prerequisites + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — you have an active container holding the file to preview. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — you can acquire a bearer token with `FileStorageContainer.Selected`. +- Capability: `container-type-owner` — your app owns the container type for the target container. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{token}` | string | A bearer token with `FileStorageContainer.Selected` ([auth](/sharepoint/dev/embedded/development/auth)) | +| `{container-id}` | string | The container holding the file (a prior step) | +| `{drive-id}` | string | The container's drive `id` (from [Step 1](#step-1)); starts with `b!` | +| `{item-id}` | string | The `driveItem` id of the target file (user-supplied / prior step) | +| `{file-name}` | string | The file name shown in the preview page (a prior step) | + +## Steps + +### Step 1 — Resolve the container's drive id {#step-1} + +The preview endpoint is addressed by `driveId`. Read the container's drive to get it; the value starts with `b!`. + +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containers/{container-id}/drive +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` with a `drive` resource. Record its `id` as `{drive-id}`. + +**On failure:** +- `404 Not Found` (`itemNotFound`) → the container is inactive or `{container-id}` is wrong. Activate the container, then retry. +- `403 Forbidden` (`accessDenied`) → the token lacks `FileStorageContainer.Selected`. + +### Step 2 — Get the preview URL from Graph {#step-2} + +Call the `driveItem` preview endpoint to obtain an embeddable URL for the file. The response carries the URL in `getUrl`. + +```http +POST https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/preview +Authorization: Bearer {token} +Content-Type: application/json + +{} +``` + +**Expected response:** `200 OK` with a body like: + +```json +{ + "getUrl": "https://www.onedrive.com/embed?foo=bar&bar=baz", + "postParameters": "param1=value¶m2=another%20value", + "postUrl": "https://www.onedrive.com/embed_by_post" +} +``` + +Use the `getUrl` value as `{preview-url}`. + +**On failure:** +- `404 Not Found` → `{drive-id}` or `{item-id}` is wrong. Re-run [Step 1](#step-1) and confirm the item id. +- `403 Forbidden` → the app or user has no permission on the container. Grant access via [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm). + +> [!CAUTION] +> Today `getUrl` carries an encrypted token usable only with your application, so the iFrame loads without an extra auth header. This may change; you may later be required to add an `Authorization` header as with other Graph requests. + +If you use the Microsoft Graph C# SDK, the equivalent call is: + +```csharp +ItemPreviewInfo preview = await graphServiceClient + .Drives[driveId] + .Items[itemId] + .Preview() + .Request() + .PostAsync(); +``` + +> [!TIP] +> To remove the banner at the top of the preview, append `nb=true` to the URL, for example `https://contoso.sharepoint.com/restOfUrl/embed.aspx?param1=value&nb=true`. + +### Step 3 — Render the preview in an iFrame {#step-3} + +Serve a page in your application that embeds `{preview-url}` in an `iframe`. + +```html + + + +

Preview

+

Preview of {file-name}:

+ + + +``` + +**Expected response:** No service call. The browser loads the rendered file inside the iFrame. + +**On failure:** +- Blank iFrame or `X-Frame-Options` error → `{preview-url}` expired or was truncated. Re-run [Step 2](#step-2) to get a fresh URL. +- The page hangs → the file type is not previewable. See [supported file types](https://support.microsoft.com/office/file-types-supported-for-previewing-files-in-onedrive-sharepoint-and-teams-e054cd0f-8ef2-4ccb-937e-26e37419c5e4). + +### Step 4 — Load the preview dynamically without a CORS error {#step-4} + +Calling the Graph preview endpoint directly from browser script triggers a CORS error. Route it through a server endpoint in your application that returns the URL, then `fetch` it client-side. + +Server side (C#), obtain the preview URL and suppress the banner: + +```csharp +[HttpGet] +[AuthorizeForScopes(Scopes = new string[] { "FileStorageContainer.Selected" })] +public async Task> GetPreviewUrl(string driveId, string itemId) +{ + // Acquire a token, then call the preview endpoint (see Step 2). + return url + "&nb=true"; // nb=true suppresses the banner +} +``` + +Client side (JavaScript), fetch the URL and inject it into the iFrame: + +```javascript +async function preview(driveId, itemId) { + const url = `/GetPreviewUrl?driveId=${driveId}&itemId=${itemId}`; + const response = await fetch(url, { credentials: 'include' }) + .then(response => response.text()); + + document.getElementById('preview').src = response + "&nb=true"; // nb=true suppresses the banner +} +``` + +**Expected response:** The server returns `200 OK` with the preview URL string; the iFrame `src` updates and renders the file. + +**On failure:** +- `401 Unauthorized` from your endpoint → the server could not acquire a token. Confirm the app registration and consent for `FileStorageContainer.Selected`. +- CORS error persists → the browser is still calling Graph directly. Route all preview calls through your server endpoint. + +## Verify {#verify} + +Load the page from [Step 3](#step-3) (or trigger `preview(driveId, itemId)` from [Step 4](#step-4)) in a browser. The iFrame renders the file. For a PDF, the SharePoint Embedded PDF previewer loads. + +> [!NOTE] +> The PDF previewer accepts options through a JSON-encoded `embed` query string appended to the file's `webUrl` (from [driveItem GET](https://learn.microsoft.com/graph/api/driveitem-get), for example `GET /drives/{drive-id}/items/{item-id}?$select=webUrl`): `{web-url}?&embed={"mpp":true}` enables the print icon and Ctrl+P; `{web-url}?&embed={"mpsn":true}` shows sticky-note content when present. Combine options in one object. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `401 Unauthorized` | Token missing/expired or wrong scope | Re-acquire a token with `FileStorageContainer.Selected` (see **Inputs**) | +| `403 Forbidden` | App or user has no permission on the container | Grant a role via [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) | +| CORS error in browser console | Calling Graph preview directly from script | Route the call through a server endpoint ([Step 4](#step-4)) | +| iFrame blank / `X-Frame-Options` error | `getUrl` expired or truncated | Re-run [Step 2](#step-2) for a fresh `getUrl` | +| Banner still shown | `nb=true` not appended | Append `nb=true` to the preview URL | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps + +- [Configure the launch mode for Office files](/sharepoint/dev/embedded/development/tutorials/launch-experience) +- [Office experiences](/sharepoint/dev/embedded/development/content-experiences/office-experience) + +## Related + +- [Configure the launch mode for Office files](/sharepoint/dev/embedded/development/tutorials/launch-experience) +- [Microsoft Graph driveItem: preview](https://learn.microsoft.com/graph/api/driveitem-preview) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/development/tutorials/using-webhooks.md b/docs/embedded/spe-docs-agent-ready/development/tutorials/using-webhooks.md new file mode 100644 index 000000000..7e25c69d5 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/tutorials/using-webhooks.md @@ -0,0 +1,231 @@ +--- +title: Subscribe to container change notifications with webhooks in SharePoint Embedded +description: Register a webhook endpoint, create a Microsoft Graph subscription on a SharePoint Embedded container's drive, and receive change notifications. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: A Microsoft Graph subscription is active on a SharePoint Embedded container's drive, and the reader's webhook endpoint receives a notification whenever a file in the container is added or updated. + estimated_minutes: 25 + difficulty: intermediate + roles: [app-developer] + prerequisites: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: concept + - capability: container-type-owner + api_surface: + # createSubscription is a standard Graph operation, not yet curated in api-surface.json. + # Validate against https://learn.microsoft.com/graph/api/subscription-post-subscriptions before publishing. + - id: createSubscription + method: POST + path: /subscriptions + permissions: [FileStorageContainer.Selected] + stability_note: not-in-api-surface.json — standard Graph change-notification subscription + - id: getContainerDrive + method: GET + path: /storage/fileStorage/containers/{containerId}/drive + permissions: [FileStorageContainer.Selected] + inputs: + - name: container-id + type: string + source: prior-step + - name: notification-url + type: uri + source: generated + - name: token + type: string + source: prior-step + - name: expiration-date-time + type: string + source: generated + - name: client-state + type: string + source: user-supplied + outputs: + - name: subscription-id + type: string + verify: GET /subscriptions/{subscription-id} returns 200 with the active subscription + next_steps: + - uri: /sharepoint/dev/embedded/development/tutorials/doc-processing-acs + when: always + - uri: /sharepoint/dev/embedded/development/tutorials/metadata + when: always + related: + - uri: /sharepoint/dev/embedded/development/tutorials/doc-processing-acs + - uri: /sharepoint/dev/embedded/getting-started/containertypes + stability: ga + last_validated: proposed +--- + +# Subscribe to container change notifications with webhooks in SharePoint Embedded + + +By the end of this how-to, you have a webhook endpoint that Microsoft Graph validates, an active subscription on a SharePoint Embedded container's drive, and a notification arriving at your endpoint whenever a file in the container is added or updated. A common follow-on is to trigger downstream processing — for example, invoking Azure AI services on each new or updated file. + +## Prerequisites + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — you have an active container whose changes you want to track. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — you can acquire a bearer token with `FileStorageContainer.Selected`. +- Capability: `container-type-owner` — your app owns the container type for the target container. +- A running SharePoint Embedded application (for example, the [create-app training module](https://learn.microsoft.com/training/modules/sharepoint-embedded-create-app/)) and a tunneling tool such as [ngrok](https://ngrok.com/docs/getting-started/) to expose it publicly. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{token}` | string | A bearer token with `FileStorageContainer.Selected` ([auth](/sharepoint/dev/embedded/development/auth)) | +| `{container-id}` | string | The container drive id to subscribe to (a prior step); used as `driveId` | +| `{notification-url}` | uri | Your public webhook URL with `driveId` appended (from [Step 2](#step-2)) | +| `{expiration-date-time}` | string | An ISO 8601 UTC timestamp ≤ 4230 minutes ahead (generated, see [Step 3](#step-3)) | +| `{client-state}` | string | An opaque value echoed in each notification for validation (user-supplied; may be empty) | + +## Steps + +### Step 1 — Add a webhook endpoint to your app {#step-1} + +Microsoft Graph delivers notifications by POST to a public HTTPS endpoint. Add an `onReceiptAdded` route to your server's `index.ts` and register the query-parser plugin so query parameters are parsed at startup. + +```typescript +server.use(restify.plugins.bodyParser(), restify.plugins.queryParser()); + +server.post('/api/onReceiptAdded', async (req, res, next) => { + try { + const response = await onReceiptAdded(req, res); + res.send(200, response); + } catch (error: any) { + res.send(500, { message: `Error in API server: ${error.message}` }); + } + next(); +}); +``` + +Implement `onReceiptAdded` in `onReceiptAdded.ts`. Graph makes a one-time validation call carrying a `validationToken`, which you must echo back as `text/plain`. Subsequent calls carry the `driveId` of the changed container. + +```typescript +require('isomorphic-fetch'); + +export const onReceiptAdded = async (req: Request, res: Response) => { + const validationToken = req.query['validationToken']; + if (validationToken) { + res.send(200, validationToken, { "Content-Type": "text/plain" }); + return; + } + + const driveId = req.query['driveId']; + if (!driveId) { + res.send(200, "Notification received without driveId, ignoring", { "Content-Type": "text/plain" }); + return; + } + + console.log(`Received driveId: ${driveId}`); + res.send(200, ""); + return; +}; +``` + +**Expected response:** No service call yet. Your app exposes `POST /api/onReceiptAdded`, which returns `200 OK` and echoes the `validationToken` when present. + +**On failure:** +- Endpoint returns non-200 on validation → the `validationToken` is not echoed as `text/plain`. Return it verbatim with that content type. +- Query parameters are `undefined` → the query-parser plugin is not registered. Add `restify.plugins.queryParser()` before the route. + +### Step 2 — Expose the endpoint publicly {#step-2} + +Graph must reach your endpoint over the public internet. Start your app, then open a tunnel with ngrok on the app's port. + +```console +ngrok http 3001 +``` + +**Expected response:** ngrok prints a public HTTPS forwarding URL (for example `https://5ac2-...ngrok-free.app`). Form `{notification-url}` by appending your route and the container's `driveId` as a query parameter: `https:///api/onReceiptAdded?driveId={container-id}`. + +**On failure:** +- ngrok exits with `address already in use` → the tunnel port is wrong. Use the port your app listens on. +- Validation call never arrives → the forwarding URL is HTTP, not HTTPS, or the app is not running. Use the HTTPS URL and confirm the app is up. + +### Step 3 — Compute the subscription expiration {#step-3} + +A drive-item subscription lives at most 4230 minutes. Compute an ISO 8601 UTC timestamp no further ahead than that. This snippet (for example, in a Postman pre-request script) sets `{expiration-date-time}` into an environment variable. + +```javascript +var now = new Date(); +var duration = 1000 * 60 * 4230; // max lifespan of a driveItem subscription is 4230 minutes +var expiry = new Date(now.getTime() + duration); +var expiryDateTime = expiry.toISOString(); + +pm.environment.set("ContainerSubscriptionExpiry", expiryDateTime); +``` + +**Expected response:** No service call. `{expiration-date-time}` holds a valid future ISO 8601 UTC timestamp within the 4230-minute limit. + +**On failure:** +- Subscription create later returns `400` for `expirationDateTime` → the value is more than 4230 minutes ahead or is in the past. Recompute within the limit. + +### Step 4 — Create the Graph subscription {#step-4} + +Subscribe to changes on the container's drive root. Graph immediately POSTs the validation handshake to `{notification-url}` ([Step 1](#step-1)); the subscription is created only if your endpoint echoes the token. + +```http +POST https://graph.microsoft.com/v1.0/subscriptions +Authorization: Bearer {token} +Content-Type: application/json + +{ + "changeType": "updated", + "notificationUrl": "{notification-url}", + "resource": "drives/{container-id}/root", + "expirationDateTime": "{expiration-date-time}", + "clientState": "{client-state}" +} +``` + +**Expected response:** `201 Created` with a `subscription` resource. Record its `id` as `{subscription-id}`. + +**On failure:** +- `400 Bad Request` (`InvalidRequest`, "endpoint did not respond") → the validation handshake failed. Confirm the endpoint echoes `validationToken` ([Step 1](#step-1)) and is reachable ([Step 2](#step-2)). +- `403 Forbidden` (`accessDenied`) → the token lacks `FileStorageContainer.Selected` or the app has no permission on the container. +- `400 Bad Request` on `expirationDateTime` → the value exceeds 4230 minutes ahead. Recompute ([Step 3](#step-3)). + +> [!NOTE] +> Append the `driveId` to `notificationUrl` as a query parameter (as in [Step 2](#step-2)) so each notification identifies the source container. Set `clientState` to an opaque secret and compare it on every notification to reject spoofed calls. + +## Verify {#verify} + +Confirm the subscription is active. + +```http +GET https://graph.microsoft.com/v1.0/subscriptions/{subscription-id} +Authorization: Bearer {token} +``` + +Returns `200 OK` with `expirationDateTime` in the future. Then add or update a file in the container: your endpoint logs `Received driveId: {container-id}`, confirming end-to-end delivery. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `400 Bad Request` ("endpoint did not respond") on create | Validation handshake failed | Echo `validationToken` as `text/plain` ([Step 1](#step-1)); confirm the endpoint is public ([Step 2](#step-2)) | +| `401 Unauthorized` | Token missing/expired or wrong scope | Re-acquire a token with `FileStorageContainer.Selected` (see **Inputs**) | +| `403 Forbidden` | App has no permission on the container | Grant access via [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) | +| `400 Bad Request` on `expirationDateTime` | Beyond the 4230-minute limit or in the past | Recompute within the limit ([Step 3](#step-3)) | +| No notifications arrive | Tunnel down or wrong `resource` path | Restart the tunnel; confirm `resource` is `drives/{container-id}/root` | +| Subscription expires silently | Not renewed before `expirationDateTime` | PATCH `/subscriptions/{subscription-id}` with a new `expirationDateTime` before it lapses | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps + +- [Document processing with Azure AI](/sharepoint/dev/embedded/development/tutorials/doc-processing-acs) +- [Add queryable metadata to containers and files](/sharepoint/dev/embedded/development/tutorials/metadata) + +## Related + +- [Document processing with Azure AI](/sharepoint/dev/embedded/development/tutorials/doc-processing-acs) +- [Microsoft Graph: Create subscription](https://learn.microsoft.com/graph/api/subscription-post-subscriptions) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/development/tutorials/vendor-install-app-customer.md b/docs/embedded/spe-docs-agent-ready/development/tutorials/vendor-install-app-customer.md new file mode 100644 index 000000000..10b845773 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/development/tutorials/vendor-install-app-customer.md @@ -0,0 +1,256 @@ +--- +title: Install your SharePoint Embedded app in a customer tenant +description: Get admin consent, register your container type, and confirm billing so your SharePoint Embedded app is installed and usable on a consuming Microsoft 365 tenant. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: how-to + outcome: Your app's container type is registered on the consuming tenant with admin consent granted for the required Graph permissions, and a billable test call (such as creating a container) succeeds, proving the app is installed and usable there. + estimated_minutes: 30 + difficulty: intermediate + roles: [app-developer, owning-admin, consuming-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: concept + - capability: entra-app-admin + api_surface: + - id: createContainerTypeRegistration + method: POST + path: /storage/fileStorage/containerTypeRegistrations + permissions: [FileStorageContainerTypeReg.Selected] + - id: grantAdminConsentEquivalent + method: POST + path: /servicePrincipals/{service-principal-id}/appRoleAssignedTo + permissions: [AppRoleAssignment.ReadWrite.All, Application.Read.All] + - id: verifyAdminConsent + method: GET + path: /servicePrincipals/{service-principal-id}?$expand=appRoleAssignedTo + permissions: [Application.Read.All] + - id: createContainer + method: POST + path: /storage/fileStorage/containers + permissions: [FileStorageContainer.Selected] + inputs: + - name: tenant-id + type: uuid + source: user-supplied + - name: client-id + type: uuid + source: app-registration + - name: redirect-uri + type: string + source: app-registration + - name: container-type-id + type: uuid + source: prior-step + - name: service-principal-id + type: uuid + source: entra-portal + - name: display-name + type: string + source: user-supplied + outputs: + - name: container-type-registration-id + type: uuid + verify: GET /storage/fileStorage/containerTypeRegistrations/{container-type-id} returns 200 on the consuming tenant + next_steps: + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + when: migrating-from-azure-blob + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + when: always + related: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/administration/billing/billing + stability: beta + last_validated: proposed +--- + +# Install your SharePoint Embedded app in a customer tenant + + +At the end of this how-to, your SharePoint Embedded (SPE) app is installed on a consuming Microsoft 365 tenant: admin consent is granted for the required Microsoft Graph permissions, your container type is registered on that tenant, and a billable test call (such as creating a container) succeeds. The recommended path runs entirely inside your app using the Microsoft Authentication Library (MSAL) and on-behalf-of-user access. + +> [!IMPORTANT] +> Using SharePoint Embedded on behalf of a user (delegated access) is the recommended approach. It strengthens your app's security and improves the auditability of actions your app performs. + +## Prerequisites + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — you must have already created a container type and built your app. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — for the SPE permission and consent model. +- Capability: `entra-app-admin` — the consuming-tenant user who grants consent must hold Privileged Role Administrator or Global Administrator; container type registration via delegated permission requires SharePoint Embedded Administrator or Global Administrator. +- The consuming tenant can be any Microsoft 365 tenant (including your own) but must have at least one SharePoint license. + +> [!NOTE] +> Container type registration uses the `/beta` Microsoft Graph endpoint today (`api-surface.json` operation `createContainerTypeRegistration`, gap `promoteContainerTypeCrudToGa`). The shape may change before general availability; this page is marked `stability: beta`. + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{tenant-id}` | uuid | The consuming tenant's directory (tenant) ID, or the tenant domain | +| `{client-id}` | uuid | Your app registration's Application (client) ID | +| `{redirect-uri}` | string | A redirect URI on your app registration that handles the admin-consent response | +| `{container-type-id}` | uuid | Your container type's ID from [Container types](/sharepoint/dev/embedded/getting-started/containertypes) | +| `{service-principal-id}` | uuid | The object ID of your app's service principal in the consuming tenant ([Microsoft Entra admin center](https://entra.microsoft.com) → Enterprise applications) | +| `{display-name}` | string | A display name for the test container created during verification | + +## Steps + +### Step 1 — Identify the permissions your app must request {#step-1} + +Confirm your app requests the minimum permissions needed to install on a consuming tenant, so consent and registration can succeed. SPE requires two Graph permissions for installation. + +| Permission | Type | Purpose | Consent | +|---|---|---|---| +| `FileStorageContainerTypeReg.Selected` | delegated or application | Register the container type in the consuming tenant | Application: requires admin consent. Delegated: no admin consent required | +| `FileStorageContainer.Selected` | delegated or application | Interact with SPE content for the container type in the consuming tenant | Requires admin consent | + +This is a configuration check on your app registration; it has no Graph call. Verify the two permissions appear under **API permissions** for your app in the [Microsoft Entra admin center](https://entra.microsoft.com). + +**On failure:** +- Permissions missing from the app registration → add `FileStorageContainerTypeReg.Selected` and `FileStorageContainer.Selected` under API permissions, then continue. + +### Step 2 — Check whether the app is already installed {#step-2} + +Avoid duplicate work: if your container type is already registered on the consuming tenant, installation is complete. Acquire a Graph token with `FileStorageContainerTypeReg.Selected` and read the registration. + +```http +GET https://graph.microsoft.com/beta/storage/fileStorage/containerTypeRegistrations/{container-type-id} +Authorization: Bearer {token} +``` + +**Expected response:** `200 OK` means the container type is already registered on this tenant — installation is done, skip to [Verify](#verify). `404 Not Found` means it is not registered yet — continue to [#step-3](#step-3). + +**On failure:** +- `403 Forbidden` (`accessDenied`) → the token lacks `FileStorageContainerTypeReg.Selected`, or admin consent for the application permission is missing. Continue with consent in [#step-3](#step-3). +- `401 Unauthorized` → token missing or expired. Re-acquire a token with `FileStorageContainerTypeReg.Selected`. + +### Step 3 — Confirm the signing-in user can grant consent {#step-3} + +Before sending the user to the consent screen, check that they can actually approve it. After the user signs in to your app (use [MSAL](https://learn.microsoft.com/entra/identity-platform/msal-overview) to obtain and [validate an ID token](https://learn.microsoft.com/entra/identity-platform/claims-validation)), inspect the `wids` claim for Privileged Role Administrator or Global Administrator role template IDs. + +```typescript +// wids contains directory role template IDs from the validated ID token +const PRIVILEGED_ROLE_ADMIN = "e8611ab8-c189-46e8-94e1-60213ab1f814"; +const GLOBAL_ADMIN = "62e90394-69f5-4237-9190-012177145e10"; +const canConsent = (idTokenClaims.wids ?? []).some( + (wid: string) => wid === PRIVILEGED_ROLE_ADMIN || wid === GLOBAL_ADMIN +); +``` + +**Expected response:** `canConsent` is `true` for an admin who can grant consent in [#step-4](#step-4). + +**On failure:** +- `canConsent` is `false` → the user is unlikely to be able to grant admin consent. Surface a message asking them to involve a Privileged Role Administrator or Global Administrator, then resume at [#step-4](#step-4) once an admin signs in. + +### Step 4 — Get admin consent for your app {#step-4} + +Grant the consuming tenant's admin consent for your app's permissions. For an interactive admin, build the admin-consent URL and send the user to it; the redirect URI must handle the [successful response](https://learn.microsoft.com/entra/identity-platform/v2-admin-consent#successful-response). + +```http +GET https://login.microsoftonline.com/{tenant-id}/v2.0/adminconsent?client_id={client-id}&redirect_uri={redirect-uri} +``` + +For unattended automation, an agent can use the API equivalent of the portal consent action instead — assign the app role to the app's service principal. + +```yaml +manual: + description: Grant the consuming tenant's admin consent for the app's SPE Graph permissions. + ui_path: Microsoft Entra admin center → Enterprise applications → {your app} → Permissions → Grant admin consent + api_equivalent: POST /servicePrincipals/{service-principal-id}/appRoleAssignedTo # api-surface.json operation grantAdminConsentEquivalent + verify: + method: GET + path: /servicePrincipals/{service-principal-id}?$expand=appRoleAssignedTo +``` + +**Expected response:** the admin-consent flow redirects to `{redirect-uri}` with a success indication; the API-equivalent `POST .../appRoleAssignedTo` returns `201 Created`. + +**On failure:** +- `403 Forbidden` on the consent redirect → the signing-in user is not an admin who can consent. Return to [#step-3](#step-3) and route to a qualified admin. +- `AADSTS650056` (misconfigured app) → the app or its permissions are not correctly registered. Re-check API permissions from [#step-1](#step-1). + +### Step 5 — Register your container type on the consuming tenant {#step-5} + +Register the container type so the app can create and use containers on this tenant. Acquire a Graph token with `FileStorageContainerTypeReg.Selected` (the user must be a SharePoint Embedded Administrator or Global Administrator when using delegated permission), then create the registration. + +```http +POST https://graph.microsoft.com/beta/storage/fileStorage/containerTypeRegistrations +Authorization: Bearer {token} +Content-Type: application/json + +{ "containerTypeId": "{container-type-id}" } +``` + +**Expected response:** `201 Created` with a `fileStorageContainerTypeRegistration` resource for `{container-type-id}`. + +**On failure:** +- `403 Forbidden` (`accessDenied`) → admin consent from [#step-4](#step-4) has not propagated, or the user lacks the SharePoint Embedded Administrator / Global Administrator role. Re-acquire the token after consent completes. +- `409 Conflict` → the container type is already registered on this tenant. Treat as installed and proceed to [Verify](#verify). + +### Step 6 — Confirm pass-through billing if applicable {#step-6} + +If your container type uses pass-through (direct-to-customer) billing, the consuming tenant must complete pay-as-you-go billing setup before any billable call succeeds. Make a billable test call — create a container — to confirm billing is active. + +```http +POST https://graph.microsoft.com/v1.0/storage/fileStorage/containers +Authorization: Bearer {token} +Content-Type: application/json + +{ "displayName": "{display-name}", "containerTypeId": "{container-type-id}" } +``` + +**Expected response:** `201 Created` with a `fileStorageContainer` whose `status` is `inactive` — billing is set up correctly. + +**On failure:** +- `402`/`403` with a billing error → the consuming tenant has not activated SPE pay-as-you-go billing. There is no Graph API for this activation (`api-surface.json` gap `activateConsumingTenantPayg`); direct the consuming-tenant admin to [set up billing for a pass-through container type](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta). +- `403 Forbidden` (non-billing) → token lacks `FileStorageContainer.Selected`. Re-acquire it. + +## Verify {#verify} + +Confirm the container type registration exists on the consuming tenant. + +```http +GET https://graph.microsoft.com/beta/storage/fileStorage/containerTypeRegistrations/{container-type-id} +Authorization: Bearer {token} +``` + +Returns `200 OK` with the registration for `{container-type-id}`. If you ran [#step-6](#step-6), the test container also created successfully (`201 Created`), confirming consent, registration, and billing are all in place. Optionally confirm consent independently: + +```http +GET https://graph.microsoft.com/v1.0/servicePrincipals/{service-principal-id}?$expand=appRoleAssignedTo +Authorization: Bearer {token} +``` + +Returns `200 OK` with `appRoleAssignedTo` listing the SPE permissions granted to your app. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `403 Forbidden` registering the container type | Admin consent not yet granted or not propagated | Complete [#step-4](#step-4); re-acquire the token after consent settles | +| Consent redirect returns `403`/`AADSTS50105` | Signing-in user cannot grant admin consent | Route to a Privileged Role Administrator or Global Administrator ([#step-3](#step-3)) | +| `402`/`403` billing error on first billable call | Consuming tenant has not activated SPE pay-as-you-go billing | Admin completes [pay-as-you-go billing setup](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) (no Graph API — gap `activateConsumingTenantPayg`) | +| `409 Conflict` on registration | Container type already registered on the tenant | Treat as installed; proceed to [Verify](#verify) | +| `401 Unauthorized` | Token missing, expired, or wrong scope | Re-acquire a token with `FileStorageContainerTypeReg.Selected` / `FileStorageContainer.Selected` | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps + +- [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) — what the customer's admin must do, including billing setup. +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) — grant users access to containers once the app is installed. + +## Related + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Billing overview](/sharepoint/dev/embedded/administration/billing/billing) +- [Create a container type registration (Graph beta)](https://learn.microsoft.com/graph/api/filestorage-post-containertyperegistrations) diff --git a/docs/embedded/spe-docs-agent-ready/getting-started/containertypes.md b/docs/embedded/spe-docs-agent-ready/getting-started/containertypes.md new file mode 100644 index 000000000..d3b4126d5 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/getting-started/containertypes.md @@ -0,0 +1,259 @@ +--- +title: Create a SharePoint Embedded container type +description: Create a trial, standard, or passthrough container type, attach a billing profile, and register it for use. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: A container type exists on the owning tenant with the chosen billing classification and, for standard types, an attached billing profile. + estimated_minutes: 20 + difficulty: intermediate + roles: [app-developer, owning-admin] + prerequisites: + - capability: entra-app-admin + - capability: spe-admin + - uri: /sharepoint/dev/embedded/development/auth + kind: concept + api_surface: + - id: createContainerType + method: POST + path: /storage/fileStorage/containerTypes + permissions: [FileStorageContainerType.Manage.All] + - id: listContainerTypes + method: GET + path: /storage/fileStorage/containerTypes + permissions: [FileStorageContainerType.Manage.All] + - id: updateContainerType + method: PATCH + path: /storage/fileStorage/containerTypes/{container-type-id} + permissions: [FileStorageContainerType.Manage.All] + - id: deleteContainerType + method: DELETE + path: /storage/fileStorage/containerTypes/{container-type-id} + permissions: [FileStorageContainerType.Manage.All] + - id: createContainerTypeRegistration + method: POST + path: /storage/fileStorage/containerTypeRegistrations + permissions: [FileStorageContainerType.Manage.All] + inputs: + - name: container-type-name + type: string + source: user-supplied + - name: owning-app-id + type: uuid + source: app-registration + - name: billing-classification + type: string + source: user-supplied + - name: container-type-id + type: uuid + source: prior-step + - name: azure-subscription-id + type: uuid + source: user-supplied + - name: resource-group + type: string + source: user-supplied + - name: region + type: string + source: user-supplied + outputs: + - name: container-type-id + type: uuid + verify: GET /storage/fileStorage/containerTypes returns the new container type + next_steps: + - uri: /sharepoint/dev/embedded/getting-started/register-api-documentation + when: always + - uri: /sharepoint/dev/embedded/administration/billing/billingmanagement + when: always + related: + - uri: /sharepoint/dev/embedded/getting-started/spembedded-for-vscode + - uri: /sharepoint/dev/embedded/getting-started/register-api-documentation + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/administration/billing/meters + stability: beta + last_validated: proposed +--- + +# Create a SharePoint Embedded container type + + +At the end of this how-to a container type exists on your owning tenant with the billing classification you chose (`trial`, `standard`, or `directToCustomer`), and — for `standard` types — a billing profile attached through the SharePoint Online Management Shell. A container type is the 1:1-with-app resource that governs access, billing, and behavior for a set of containers. + +> [!IMPORTANT] +> Container type create/list/update/delete and registration are on the Microsoft Graph **beta** endpoint today (`stability: beta`). Shapes may change before general availability. See api-surface.json gap `promoteContainerTypeCrudToGa`. + +> [!NOTE] +> The billing classification is fixed at creation. A `trial` type cannot become production, and `standard` and `directToCustomer` cannot be converted to each other — delete and re-create to change. + +## Prerequisites + +- Capability: a Microsoft Entra ID app with the `FileStorageContainerType.Manage.All` application permission on the owning tenant. +- Capability: a [SharePoint Embedded Administrator](https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#sharepoint-embedded-administrator) account on whose behalf the create call is made. +- An active instance of SharePoint in the tenant. Users who authenticate into container types and containers must exist in Microsoft Entra ID (members or guests). +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — how the owning app acquires a token. +- For `standard` billing only: an Azure subscription and a resource group, plus owner or contributor permission on that subscription. See [Create an Azure subscription](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/initial-subscriptions) and [Create a resource group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal). + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{container-type-name}` | string | User-supplied, user-friendly name | +| `{owning-app-id}` | uuid | The owning Entra app's application (client) ID | +| `{billing-classification}` | string | One of `trial`, `standard`, `directToCustomer` | +| `{container-type-id}` | uuid | Returned by the create call (Step 1) | +| `{azure-subscription-id}` | uuid | User-supplied; standard billing only | +| `{resource-group}` | string | User-supplied; standard billing only | +| `{region}` | string | User-supplied; standard billing only | + +## Steps + +### Step 1 — Create the container type {#step-1} + +Call the create endpoint on behalf of a SharePoint Embedded Administrator. Set `{billing-classification}` to `trial` for free exploration, `standard` to bill the owning tenant, or `directToCustomer` to pass charges to the consuming tenant. + +```http +POST https://graph.microsoft.com/beta/storage/fileStorage/containerTypes +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "{container-type-name}", + "owningAppId": "{owning-app-id}", + "billingClassification": "{billing-classification}", + "settings": {} +} +``` + +**Expected response:** `201 Created` with a `fileStorageContainerType` carrying the generated `container-type-id`. + +**On failure:** +- `403 Forbidden` (`accessDenied`) → the app lacks `FileStorageContainerType.Manage.All`, or the user is not a SharePoint Embedded Administrator. Grant the permission and consent. +- `400 Bad Request` (existing trial) → a `trial` container type already exists; each tenant may hold only one at a time. Permanently delete the existing one first. +- `400 Bad Request` (`owningAppId` already owns a type) → a single owning app may own only one container type. Use a different app. + +> [!NOTE] +> A `trial` container type is limited to 5 containers (active plus recycled), 1 GB each, expires after 30 days, and is restricted to the developer tenant. A `standard` tenant may hold up to 25 container types. See [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling). + +### Step 2 — (Standard billing only) Attach a billing profile {#step-2} + +`standard` container types need a billing profile that points charges at your Azure subscription. There is no Graph API for this today; use the SharePoint Online Management Shell. Skip this step for `trial` and `directToCustomer` types. + +```manual +manual: + description: Attach an Azure billing profile to a standard container type. + ui_path: SharePoint Online Management Shell → Connect-SPOService with tenant admin credentials → Add-SPOContainerTypeBilling + api_equivalent: none — no Graph API today; see api-surface.json gap "setUpContainerTypeBilling" + verify: + method: GET + path: /storage/fileStorage/containerTypes +``` + +Install the [latest SharePoint Online Management Shell](https://www.microsoft.com/download/details.aspx?id=35588), connect, then attach billing: + +```pwsh +Connect-SPOService -Url https://{tenant}-admin.sharepoint.com + +Add-SPOContainerTypeBilling ` + -ContainerTypeId {container-type-id} ` + -AzureSubscriptionId {azure-subscription-id} ` + -ResourceGroup {resource-group} ` + -Region {region} +``` + +To update an existing billing profile: + +```pwsh +Set-SPOContainerType ` + -ContainerTypeId {container-type-id} ` + -AzureSubscriptionId {azure-subscription-id} ` + -ResourceGroup {resource-group} +``` + +**Expected response:** the cmdlet completes without error and the container type reports a valid billing profile. + +**On failure:** +- `SubscriptionNotRegistered` → `Microsoft.Syntex` is not yet registered as a resource provider; the cmdlet registers it asynchronously. Wait 5–10 minutes and retry until it succeeds. +- `Access denied` running the cmdlet → the account lacks owner/contributor on the Azure subscription, or the SharePoint Embedded Administrator / Global Administrator role. + +> [!NOTE] +> For `directToCustomer` (passthrough) types, the consuming tenant admin activates pay-as-you-go billing in their own tenant after [registration](/sharepoint/dev/embedded/getting-started/register-api-documentation) — there is no API for that activation either (see api-surface.json gap `activateConsumingTenantPayg`). + +### Step 3 — (Optional) Reconfigure container type settings {#step-3} + +Adjust behaviors (storage size, discoverability, versioning, and others) by patching the container type. Settings can also be supplied in the `settings` object during [Step 1](#step-1). + +```http +PATCH https://graph.microsoft.com/beta/storage/fileStorage/containerTypes/{container-type-id} +Authorization: Bearer {token} +Content-Type: application/json + +{ "settings": { "isDiscoverabilityEnabled": true } } +``` + +**Expected response:** `200 OK` with the updated `fileStorageContainerType`. + +**On failure:** +- `403 Forbidden` → missing `FileStorageContainerType.Manage.All`. Grant and consent. +- `404 Not Found` → wrong `{container-type-id}`. Confirm it with [Verify](#verify). + +> [!IMPORTANT] +> Setting changes can take up to **24 hours** to replicate to all consuming tenants. Where a consuming tenant has overridden a setting, the new value is not applied. Some settings (for example, storage size and discoverability) apply only to new content. See [fileStorageContainerTypeSettings](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainertypesettings). + +### Step 4 — Register the container type to enable containers {#step-4} + +Before any container can be created, register the container type in the consuming tenant (for `trial`, that is the developer tenant). Registration defines the owning app's permissions. Full request and permission details are in [Register container type permissions](/sharepoint/dev/embedded/getting-started/register-api-documentation). + +```http +POST https://graph.microsoft.com/beta/storage/fileStorage/containerTypeRegistrations +Authorization: Bearer {token} +Content-Type: application/json + +{ "containerTypeId": "{container-type-id}" } +``` + +**Expected response:** `201 Created` with a `fileStorageContainerTypeRegistration`. Containers of this type can now be created. + +**On failure:** +- `403 Forbidden` (`accessDenied`) → admin consent for the owning app has not been granted in the consuming tenant. Grant consent, then retry. See [Register container type permissions](/sharepoint/dev/embedded/getting-started/register-api-documentation). +- `404 Not Found` → the container type does not exist on the owning tenant; complete [Step 1](#step-1). + +## Verify {#verify} + +List the container types on the owning tenant and confirm the new one is present with the expected billing classification: + +```http +GET https://graph.microsoft.com/beta/storage/fileStorage/containerTypes +Authorization: Bearer {token} +``` + +Returns `200 OK` with a collection that includes a `fileStorageContainerType` whose `id` equals `{container-type-id}` and whose `billingClassification` matches your input. For `standard` types, the billing profile reports as valid. + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `401 Unauthorized` | Token missing/expired or wrong scope | Re-acquire a token with `FileStorageContainerType.Manage.All` | +| `403 Forbidden` | App permission not granted, or caller not SharePoint Embedded Administrator | Grant the permission and admin consent, then re-acquire the token | +| Cannot create a second trial type | Limit is one `trial` container type per tenant | Permanently delete the existing trial type and its deleted containers | +| `SubscriptionNotRegistered` on billing cmdlet | `Microsoft.Syntex` resource provider not yet registered | Wait 5–10 minutes for async registration, then retry | +| Cannot delete a standard container type | Deletion of `standard` types is not yet supported | Only `trial` types can be deleted today, after removing all containers including deleted ones | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps + +- [Register container type permissions](/sharepoint/dev/embedded/getting-started/register-api-documentation) — define owning and guest app permissions in a consuming tenant. +- [Billing management](/sharepoint/dev/embedded/administration/billing/billingmanagement) — manage standard billing profiles. + +## Related + +- [Set up a trial environment with the VS Code extension](/sharepoint/dev/embedded/getting-started/spembedded-for-vscode) +- [Register container type permissions](/sharepoint/dev/embedded/getting-started/register-api-documentation) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Billing meters](/sharepoint/dev/embedded/administration/billing/meters) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/getting-started/register-api-documentation.md b/docs/embedded/spe-docs-agent-ready/getting-started/register-api-documentation.md new file mode 100644 index 000000000..9fa1058df --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/getting-started/register-api-documentation.md @@ -0,0 +1,234 @@ +--- +title: Register a container type in a consuming tenant +description: Grant admin consent and call the registration API to define owning- and guest-app permissions on a container type. +ms.topic: how-to +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: how-to + outcome: A container type is registered in the consuming tenant with explicit owning-app (and optional guest-app) permissions, so containers can be created there. + estimated_minutes: 15 + difficulty: intermediate + roles: [app-developer, owning-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + kind: how-to + - uri: /sharepoint/dev/embedded/development/auth + kind: concept + - capability: entra-app-admin + - capability: spe-admin + api_surface: + - id: createContainerTypeRegistration + method: POST + path: /storage/fileStorage/containerTypeRegistrations + permissions: [FileStorageContainerType.Manage.All] + - id: grantAdminConsentEquivalent + method: POST + path: /servicePrincipals/{service-principal-id}/appRoleAssignedTo + permissions: [AppRoleAssignment.ReadWrite.All, Application.Read.All] + - id: verifyAdminConsent + method: GET + path: /servicePrincipals/{service-principal-id}?$expand=appRoleAssignedTo + permissions: [Application.Read.All] + - id: listContainers + method: GET + path: /storage/fileStorage/containers?$filter=containerTypeId eq {container-type-id} + permissions: [FileStorageContainer.Selected] + inputs: + - name: container-type-id + type: uuid + source: prior-step + - name: owning-app-id + type: uuid + source: app-registration + - name: guest-app-id + type: uuid + source: app-registration + - name: consuming-tenant-id + type: uuid + source: user-supplied + outputs: + - name: container-type-id + type: uuid + verify: GET /storage/fileStorage/containers?$filter=containerTypeId eq {container-type-id} returns 200 + next_steps: + - uri: /sharepoint/dev/embedded/getting-started/spembedded-for-vscode + when: always + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + when: always + related: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + stability: preview + last_validated: proposed +--- + +# Register a container type in a consuming tenant + + +At the end of this how-to, a container type is registered in a consuming tenant with explicit permissions for its owning application — and optionally for one or more guest applications. Registration is the first endpoint a SharePoint Embedded application must call on a consuming tenant; without it, all other container and content calls return access-denied errors. The last successful registration call wins: it determines the settings and permissions in effect on that tenant. + +> [!IMPORTANT] +> The container type registration API is in **preview** (`stability: preview`) and on the Microsoft Graph **beta** endpoint. The shape may change. See api-surface.json operation `createContainerTypeRegistration` and gap `promoteContainerTypeCrudToGa`. + +## Prerequisites + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — the container type must already exist on the owning tenant. +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) — how the owning app acquires a delegated or app-only token. +- Capability: the owning app has a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals) installed on the consuming tenant **and** admin consent granted there. +- Capability: the registration call carries the `FileStorageContainerTypeReg.Selected` permission (delegated or app-only). For a delegated call, the user must hold the [SharePoint Embedded Administrator](https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#sharepoint-embedded-administrator) or [Global Administrator](https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#global-administrator) role. For an app-only call, use the [client credentials grant flow](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow). + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{container-type-id}` | uuid | The container type created on the owning tenant | +| `{owning-app-id}` | uuid | Application (client) ID of the owning app | +| `{guest-app-id}` | uuid | Application (client) ID of an optional guest app | +| `{consuming-tenant-id}` | uuid | Tenant ID of the consuming tenant | + +## Permission values + +The registration grant uses these container-type permission values (set them per app in `delegatedPermissions` and `applicationPermissions`): + +| Permission | Description | +|---|---| +| `none` | No permissions to any containers or content of this container type. | +| `readContent` | Can read the content of containers of this container type. | +| `writeContent` | Can write content. Cannot be granted without `readContent`. | +| `create` | Can create containers of this container type. | +| `delete` | Can delete containers of this container type. | +| `read` | Can read the metadata of containers. | +| `write` | Can update the metadata of containers. | +| `enumeratePermissions` | Can enumerate container members and their roles. | +| `addPermissions` | Can add members to the container. | +| `updatePermissions` | Can change roles of existing members. | +| `deletePermissions` | Can delete other members (not self). | +| `deleteOwnPermissions` | Can remove own membership. | +| `managePermissions` | Can add, remove (including self), or update members' roles. | +| `manageContent` | Can manage the content of the container. | +| `full` | All permissions for containers of this container type. | + +## Steps + +### Step 1 — Grant admin consent in the consuming tenant {#step-1} + +The owning app must have a service principal and admin consent in the consuming tenant before registration. Direct the consuming tenant's Global Administrator to the admin consent endpoint (substitute the right host for national clouds — see [endpoints on national clouds](https://learn.microsoft.com/en-us/entra/identity-platform/authentication-national-cloud#microsoft-entra-authentication-endpoints)): + +```manual +manual: + description: Grant admin consent to the owning app in the consuming tenant. + ui_path: Send the consuming-tenant Global Administrator to https://login.microsoftonline.com/{consuming-tenant-id}/v2.0/adminconsent?client_id={owning-app-id}&scope=https://graph.microsoft.com/.default → review → consent + api_equivalent: POST https://graph.microsoft.com/v1.0/servicePrincipals/{service-principal-id}/appRoleAssignedTo (operation grantAdminConsentEquivalent) + verify: + method: GET + path: /servicePrincipals/{service-principal-id}?$expand=appRoleAssignedTo +``` + +**Expected response:** the admin consent flow completes and a service principal for `{owning-app-id}` exists on the consuming tenant. + +**On failure:** +- `AADSTS650051` / consent error → the directed account is not a Global Administrator in the consuming tenant. Use an eligible admin. +- Consent succeeds but registration later returns `403` → consent has not propagated yet; wait and retry [Step 2](#step-2). + +### Step 2 — Register the container type {#step-2} + +Call the registration API for the container type. This example registers `{container-type-id}` and grants the owning app `full` permissions for both delegated and app-only calls. + +```http +PUT https://graph.microsoft.com/beta/storage/fileStorage/containerTypeRegistrations/{container-type-id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "applicationPermissionGrants": [ + { + "appId": "{owning-app-id}", + "delegatedPermissions": ["full"], + "applicationPermissions": ["full"] + } + ] +} +``` + +**Expected response:** `201 Created` with a `fileStorageContainerTypeRegistration` whose `applicationPermissionGrants` echo the grant and whose `billingStatus` is `valid`. + +**On failure:** +- `403 Forbidden` (`accessDenied`) → admin consent not completed in the consuming tenant ([Step 1](#step-1)), or the call lacks `FileStorageContainerTypeReg.Selected`. +- `400 Bad Request` (`writeContent` without `readContent`) → `writeContent` requires `readContent` in the same grant. Add `readContent`. +- `404 Not Found` → the container type does not exist on the owning tenant. + +> [!NOTE] +> The api-surface index lists this operation as `createContainerTypeRegistration` with method `POST /storage/fileStorage/containerTypeRegistrations`; the live preview reference uses `PUT .../containerTypeRegistrations/{container-type-id}`. Validate the exact method and path against `$metadata` before publishing. + +### Step 3 — (Optional) Grant a guest app permissions {#step-3} + +Add a guest app to the same registration to let another application act on the owning app's containers (for example, a backup tool). Guest apps receive only the permissions you list. This example grants the owning app `full` and a guest app `read` and `write` for delegated calls only. + +```http +PUT https://graph.microsoft.com/beta/storage/fileStorage/containerTypeRegistrations/{container-type-id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "applicationPermissionGrants": [ + { + "appId": "{owning-app-id}", + "delegatedPermissions": ["full"], + "applicationPermissions": ["full"] + }, + { + "appId": "{guest-app-id}", + "delegatedPermissions": ["read", "write"], + "applicationPermissions": ["none"] + } + ] +} +``` + +**Expected response:** `201 Created` with a registration whose `applicationPermissionGrants` includes both the owning app and `{guest-app-id}`. + +**On failure:** +- `403 Forbidden` → the guest app has no service principal / consent in the consuming tenant. Have its app consented there first. +- `400 Bad Request` → an invalid permission value; use only the values in **Permission values**. + +> [!IMPORTANT] +> Each registration call replaces the prior grant set — the last successful call determines the effective permissions. Always include the owning app's grant in every call, or you will remove its access. + +## Verify {#verify} + +Confirm the owning app can now act on containers of this type in the consuming tenant: + +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containers?$filter=containerTypeId eq {container-type-id} +Authorization: Bearer {token} +``` + +Returns `200 OK` (an empty collection is valid before any container exists). A `403 Forbidden` here means registration or consent is incomplete — re-check [Step 1](#step-1) and [Step 2](#step-2). + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `401 Unauthorized` | Token missing/expired or wrong scope | Re-acquire a token with `FileStorageContainerTypeReg.Selected` | +| `403 Forbidden` on registration | Admin consent not granted in the consuming tenant | Complete [Step 1](#step-1), wait for propagation, retry | +| `403 Forbidden` on container calls after registering | Owning app grant omitted from the last registration call | Re-register including the owning app's `full` grant | +| `400 Bad Request` | `writeContent` granted without `readContent`, or invalid permission value | Add `readContent`; use only values in **Permission values** | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps + +- [Set up a trial environment with the VS Code extension](/sharepoint/dev/embedded/getting-started/spembedded-for-vscode) — create your first container against the registered type. +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) — manage per-user access on containers. + +## Related + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/getting-started/spembedded-for-vscode.md b/docs/embedded/spe-docs-agent-ready/getting-started/spembedded-for-vscode.md new file mode 100644 index 000000000..3d4c6950f --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/getting-started/spembedded-for-vscode.md @@ -0,0 +1,253 @@ +--- +title: Set up a SharePoint Embedded trial environment with the VS Code extension +description: Install the SharePoint Embedded VS Code extension, create a trial container type, register it, and create your first container. +ms.topic: quickstart +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: quickstart + outcome: A trial container type owned by a Microsoft Entra app is registered on the developer tenant and at least one active container exists. + estimated_minutes: 15 + difficulty: beginner + roles: [app-developer] + prerequisites: + - capability: m365-subscription + - capability: entra-app-admin + - uri: /sharepoint/dev/embedded/getting-started/containertypes + kind: how-to + api_surface: + - id: createContainerType + method: POST + path: /storage/fileStorage/containerTypes + permissions: [FileStorageContainerType.Manage.All] + - id: createContainerTypeRegistration + method: POST + path: /storage/fileStorage/containerTypeRegistrations + permissions: [FileStorageContainerType.Manage.All] + - id: createContainer + method: POST + path: /storage/fileStorage/containers + permissions: [FileStorageContainer.Selected] + - id: getContainer + method: GET + path: /storage/fileStorage/containers/{container-id} + permissions: [FileStorageContainer.Selected] + inputs: + - name: container-type-name + type: string + source: user-supplied + - name: owning-app-name + type: string + source: user-supplied + - name: container-name + type: string + source: user-supplied + - name: container-id + type: uuid + source: prior-step + outputs: + - name: container-type-id + type: uuid + verify: GET /storage/fileStorage/containerTypes returns the trial container type + - name: container-id + type: uuid + verify: GET /storage/fileStorage/containers/{container-id} returns 200 with status active + next_steps: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + when: always + - uri: /sharepoint/dev/embedded/getting-started/register-api-documentation + when: multi-tenant-app + - uri: /sharepoint/dev/embedded/development/app-architecture + when: always + related: + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/development/app-architecture + - uri: /sharepoint/dev/embedded/development/auth + stability: ga + last_validated: proposed +--- + +# Set up a SharePoint Embedded trial environment with the VS Code extension + + +At the end of this quickstart you have the SharePoint Embedded Visual Studio Code extension installed, a **trial** container type owned by a Microsoft Entra ID app, that container type registered on your developer tenant, and at least one active container you can upload files to. This is the fastest free path to calling SharePoint Embedded APIs for a proof of concept. + +> [!NOTE] +> The VS Code extension creates only **trial** container types. Standard (`standard`) and passthrough (`directToCustomer`) container types must be created with Microsoft Graph or the SharePoint Online Management Shell. See [Container types](/sharepoint/dev/embedded/getting-started/containertypes). + +## Prerequisites + +- Capability: administrative access to a Microsoft 365 tenant. If you do not have one, get a tenant through the [Microsoft 365 Developer Program](https://developer.microsoft.com/microsoft-365/dev-program), [Microsoft Customer Digital Experience](https://cdx.transform.microsoft.com/), or a [Microsoft 365 E3 trial](https://www.microsoft.com/microsoft-365/enterprise/microsoft365-plans-and-pricing). +- Capability: an account that can grant Microsoft Entra admin consent on the tenant (Global Administrator or SharePoint Embedded Administrator). +- An active instance of SharePoint in the tenant. +- [Visual Studio Code](https://code.visualstudio.com/) installed. +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — read first to understand trial limits (5 containers, 1 GB each, 30 days). + +## Inputs + +| Placeholder | Type | Where it comes from | +|---|---|---| +| `{container-type-name}` | string | User-supplied; rename later if needed | +| `{owning-app-name}` | string | User-supplied; name of the new owning Entra app, or pick an existing app | +| `{container-name}` | string | User-supplied | +| `{container-id}` | uuid | Returned when the container is created (Step 5) | + +## Steps + +### Step 1 — Install the extension and sign in {#step-1} + +Install the extension and authenticate to your tenant so the extension can create resources on your behalf. + +```manual +manual: + description: Install the SharePoint Embedded extension in VS Code and sign in with a tenant administrator account. + ui_path: Visual Studio Code → Extensions (activity bar) → search "SharePoint Embedded" → Install → select the SharePoint Embedded icon → sign in → review requested permissions → Accept + api_equivalent: none — the extension wraps app registration and consent; the underlying control-plane equivalents are createContainerType + grantAdminConsentEquivalent (see api-surface.json) + verify: + method: GET + path: /storage/fileStorage/containerTypes +``` + +You can also install from the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=SharepointEmbedded.ms-sharepoint-embedded-vscode-extension). Authentication opens an external browser tab; review the requested permissions, then accept the admin consent prompt. + +**Expected response:** the SharePoint Embedded view loads and shows your tenant signed in, ready to create a container type. + +**On failure:** +- `Consent declined` → the signed-in account lacks Global Administrator or SharePoint Embedded Administrator role. Re-run with an eligible account. +- `AADSTS errors in the browser tab` → admin consent was not completed; restart sign-in from the SharePoint Embedded icon. + +### Step 2 — Create a trial container type and its owning app {#step-2} + +Create the trial container type. Every container type is owned 1:1 by a Microsoft Entra ID app, so the extension creates a new app (or configures an existing one) as the owning application. + +```manual +manual: + description: Create a trial container type named {container-type-name} owned by a new or existing Entra app {owning-app-name}. + ui_path: SharePoint Embedded view → Create Trial Container Type → enter {container-type-name} → enter {owning-app-name} for a new app, or select an existing application ID + api_equivalent: POST https://graph.microsoft.com/beta/storage/fileStorage/containerTypes with billingClassification "trial" (operation createContainerType, beta-only — see api-surface.json gap promoteContainerTypeCrudToGa) + verify: + method: GET + path: /storage/fileStorage/containerTypes +``` + +> [!WARNING] +> If you select an existing application, the extension updates that app's configuration to work with SharePoint Embedded. Do not do this on a production application. + +**Expected response:** the new container type and its owning app appear as a tree node in the left navigation bar. + +**On failure:** +- `A trial container type already exists` → each tenant may hold only one `trial` container type at a time. Permanently delete the existing one (including its deleted containers) first. +- `App configuration failed` → the selected existing app could not be reconfigured; create a new owning app instead. + +### Step 3 — Register the container type on your tenant {#step-3} + +Register the container type on your local (developer) tenant. Registration defines the owning app's permissions and is required before any container can be created. See [Register container type permissions](/sharepoint/dev/embedded/getting-started/register-api-documentation). + +```manual +manual: + description: Register the trial container type on the local developer tenant. + ui_path: SharePoint Embedded view → select "Register on local tenant" prompt (lower-right), or right-click {container-type-name} → Register + api_equivalent: POST https://graph.microsoft.com/beta/storage/fileStorage/containerTypeRegistrations (operation createContainerTypeRegistration, beta-only — see api-surface.json gap promoteContainerTypeCrudToGa) + verify: + method: GET + path: /storage/fileStorage/containers?$filter=containerTypeId eq {container-type-id} +``` + +**Expected response:** the container type shows as registered, and a **Containers** node becomes available in the tree. + +**On failure:** +- `Access denied / consent required` → grant admin consent in the browser window that opens, then retry registration. +- `403 Forbidden` on the API equivalent → the owning app lacks `FileStorageContainerType.Manage.All` or the user lacks the SharePoint Embedded Administrator role. + +### Step 4 — Grant permissions {#step-4} + +Grant admin consent for the registered container type's permissions so the app can act on containers. + +```manual +manual: + description: Grant admin consent for the container type's permissions. + ui_path: SharePoint Embedded view → follow the "Grant admin consent" prompt → sign in and consent in the external browser window + api_equivalent: POST https://graph.microsoft.com/v1.0/servicePrincipals/{service-principal-id}/appRoleAssignedTo (operation grantAdminConsentEquivalent) + verify: + method: GET + path: /servicePrincipals/{service-principal-id}?$expand=appRoleAssignedTo +``` + +**Expected response:** consent completes in the browser and control returns to VS Code with the container type ready for use. + +**On failure:** +- `Consent window closes without granting` → re-open the grant prompt; the signed-in account must hold a tenant admin role. + +### Step 5 — Create your first container {#step-5} + +Create a container of your trial container type. A trial container type allows up to five containers (active plus recycled). + +```manual +manual: + description: Create a container named {container-name} under the registered trial container type. + ui_path: SharePoint Embedded view → right-click the Containers node → Create container → enter {container-name} + api_equivalent: POST https://graph.microsoft.com/v1.0/storage/fileStorage/containers (operation createContainer) + verify: + method: GET + path: /storage/fileStorage/containers/{container-id} +``` + +The Graph equivalent of this action is: + +```http +POST https://graph.microsoft.com/v1.0/storage/fileStorage/containers +Authorization: Bearer {token} +Content-Type: application/json + +{ "displayName": "{container-name}", "containerTypeId": "{container-type-id}" } +``` + +**Expected response:** `201 Created` with a `fileStorageContainer`; the new container appears under the **Containers** node. Containers created through Graph are inactive until activated. + +**On failure:** +- `Container limit reached` → a trial container type allows only 5 containers including recycled ones; recycle or permanently delete one. +- `400 Bad Request` (`containerTypeId not registered`) → complete [Step 3](#step-3) registration first. + +## Verify {#verify} + +Confirm the container exists and is usable: + +```http +GET https://graph.microsoft.com/v1.0/storage/fileStorage/containers/{container-id} +Authorization: Bearer {token} +``` + +Returns `200 OK` with a `fileStorageContainer` whose `status` is `active`. In the extension, the container appears under the **Containers** node and you can recycle or recover it from there. + +To load a working sample app wired to this container type, use the extension's **Load Sample App** action; it writes the runtime configuration (owning app ID and container type ID) for you. + +> [!IMPORTANT] +> The sample app stores authentication secrets in plain text for local development only. Never use this configuration in production. See [Register an application for production](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app). + +## Troubleshooting {#troubleshooting} + +| Symptom | Likely cause | Fix | +|---|---|---| +| `401 Unauthorized` | Token missing/expired or wrong scope | Re-acquire a token with the permission in **Inputs**; re-sign-in from the SharePoint Embedded icon | +| `403 Forbidden` | Admin consent not granted, or missing `FileStorageContainerType.Manage.All` | Grant consent ([Step 4](#step-4)), then re-acquire the token | +| Trial container type creation blocked | A `trial` container type already exists on the tenant (limit 1) | Permanently delete the existing trial container type and its deleted containers, then retry [Step 2](#step-2) | +| Cannot create a 6th container | Trial limit is 5 containers including recycled | Recycle or permanently delete a container, then retry [Step 5](#step-5) | +| Sample app port conflict | Port 8080 already in use | The sample app falls back to the next available port; or free port 8080 | +| `429 Too Many Requests` | Throttled | Honor `Retry-After`; back off exponentially. See [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) | + +## Next steps + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) — create standard/passthrough container types for production. +- [Register container type permissions](/sharepoint/dev/embedded/getting-started/register-api-documentation) — register in other consuming tenants. +- [Application architecture](/sharepoint/dev/embedded/development/app-architecture) + +## Related + +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [Application architecture](/sharepoint/dev/embedded/development/app-architecture) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/index.md b/docs/embedded/spe-docs-agent-ready/index.md new file mode 100644 index 000000000..5576df4a2 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/index.md @@ -0,0 +1,357 @@ +--- +title: SharePoint Embedded — documentation index +description: Persona-tagged index of every public SharePoint Embedded (SPE) Learn doc. Route to the right page by role, task, and outcome. +ms.topic: landing-page +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/09/2026 +ms.service: sharepoint-online +ms.localizationpriority: high +search.appverid: MET150 +agent: + schema_version: 1 + task_type: concept + outcome: The reader (human or agent) is routed to the smallest set of SPE pages required to accomplish their stated task, by role and outcome. + difficulty: beginner + roles: + - new-user + - app-developer + - developer-admin + - consuming-tenant-admin + - compliance-officer + prerequisites: [] + api_surface: [] + inputs: + - name: user_intent + type: enum + source: user-supplied + values: [evaluate, set-up-dev-env, build-app, build-content-experience, follow-tutorial, configure-billing, admin-consuming-tenant, govern-content] + outputs: + - name: target_section_id + type: string + verify: target section anchor resolves on this page + - name: target_page_uri + type: uri + verify: returns 200 from learn.microsoft.com + next_steps: + - uri: /sharepoint/dev/embedded/overview + when: user_intent == "evaluate" + - uri: /sharepoint/dev/embedded/getting-started/spembedded-for-vscode + when: user_intent == "set-up-dev-env" + - uri: /sharepoint/dev/embedded/development/auth + when: user_intent == "build-app" + - uri: /sharepoint/dev/embedded/administration/billing/billing + when: user_intent == "configure-billing" + - uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta + when: user_intent == "admin-consuming-tenant" + - uri: /sharepoint/dev/embedded/compliance/security-and-compliance + when: user_intent == "govern-content" + related: + - uri: /sharepoint/dev/embedded/scenarios-and-use-cases + - uri: /sharepoint/dev/embedded/whats-new + stability: ga + last_validated: proposed +--- + +# SharePoint Embedded — documentation index + + +SharePoint Embedded (SPE) is a cloud-based, API-only file and document management platform built on Microsoft 365 infrastructure. Developers embed Office collaboration, Microsoft Purview compliance, and Copilot capabilities directly into their own applications while keeping documents securely within each customer's Microsoft 365 tenant. + +This page is a routing index. It does not teach SPE; it points you to the smallest set of pages required to accomplish a specific task, organized by role. + +> [!TIP] +> If you already know what you need: jump to the [/llms.txt](/sharepoint/dev/embedded/llms.txt) index for the machine-readable form of this page, or the [Microsoft Graph API reference](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainer) for endpoints. + +## When to use this page {#when-to-use} + +Use this index if any of the following apply: + +- You are evaluating SPE for a new application. +- You are a developer about to set up your environment for the first time. +- You are an administrator (developer admin, consuming-tenant admin, or compliance officer) and need the right starting page for your role. +- You are an AI agent routing a user request to the correct SPE doc. + +## When NOT to use this page {#when-not-to-use} + +- You already know which page you need. Go there directly; do not pass through here. +- You need the raw Microsoft Graph API surface. Use the [Graph API reference](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainer). +- You are an agent crawling the corpus. Use [/llms.txt](/sharepoint/dev/embedded/llms.txt) and [/api-surface.json](/sharepoint/dev/embedded/api-surface.json) instead of scraping this page. + +## Section index {#section-index} + +| # | Section | Role | Anchor | +|---|---|---|---| +| 1 | New to SharePoint Embedded | new-user | [#new-to-spe](#new-to-spe) | +| 2 | Developer — Set up your environment | app-developer | [#dev-setup](#dev-setup) | +| 3 | Developer — Build your app | app-developer | [#dev-build](#dev-build) | +| 4 | Developer — Content experiences | app-developer | [#dev-content-experiences](#dev-content-experiences) | +| 5 | Tutorials | app-developer | [#tutorials](#tutorials) | +| 6 | Developer Admin / ISV — Billing & tenant management | developer-admin | [#dev-admin-billing](#dev-admin-billing) | +| 7 | Consuming Tenant Admin | consuming-tenant-admin | [#consuming-tenant-admin](#consuming-tenant-admin) | +| 8 | Compliance & Security Officer | compliance-officer | [#compliance-security](#compliance-security) | + +--- + +## 1. New to SharePoint Embedded {#new-to-spe} + +**Use this section if:** you have not built on SPE before and need orientation, scenarios, or guided training. + +| Page | Type | Estimated time | +|---|---|---| +| [Overview](/sharepoint/dev/embedded/overview) | concept | 10 min | +| [Scenarios and use cases](/sharepoint/dev/embedded/scenarios-and-use-cases) | concept | 10 min | +| [What's new](/sharepoint/dev/embedded/whats-new) | reference | 5 min | +| [Learning module — Overview & configuration](https://learn.microsoft.com/en-us/training/modules/sharepoint-embedded-setup) | quickstart | 45 min | +| [Learning module — Building applications](https://learn.microsoft.com/en-us/training/modules/sharepoint-embedded-create-app) | quickstart | 60 min | + +**Next step:** when you finish orientation, proceed to [Developer — Set up your environment](#dev-setup). + +--- + +## 2. Developer — Set up your environment {#dev-setup} + +**Use this section if:** you are an app developer creating container types and registering your app for the first time. + +| Page | Type | Estimated time | +|---|---|---| +| [VS Code extension](/sharepoint/dev/embedded/getting-started/spembedded-for-vscode) | quickstart | 15 min | +| [Container types](/sharepoint/dev/embedded/getting-started/containertypes) | how-to | 20 min | +| [Register container type API](/sharepoint/dev/embedded/getting-started/register-api-documentation) | how-to | 15 min | +| [Application architecture](/sharepoint/dev/embedded/development/app-architecture) | concept | 15 min | + +**Next step:** after environment setup, proceed to [Developer — Build your app](#dev-build). + +--- + +## 3. Developer — Build your app {#dev-build} + +**Use this section if:** you are wiring authentication, permissions, scale, or AI capabilities into a working SPE application. + +| Page | Type | Estimated time | +|---|---|---| +| [Authentication and authorization](/sharepoint/dev/embedded/development/auth) | concept + how-to | 30 min | +| [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) | how-to | 20 min | +| [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) | reference | 10 min | +| [Fluid Framework](/sharepoint/dev/embedded/development/fluid) | how-to | 25 min | +| [AI knowledge source in Microsoft Foundry](/sharepoint/dev/embedded/development/declarative-agent/sharepoint-embedded-knowledge-source) | how-to | 25 min | + +> [!IMPORTANT] +> AI knowledge source in Microsoft Foundry is in **Preview**. API surface, permissions, and pricing may change before general availability. + +**Next step:** for end-user-facing capabilities, proceed to [Developer — Content experiences](#dev-content-experiences). + +--- + +## 4. Developer — Content experiences {#dev-content-experiences} + +**Use this section if:** you are adding Office editing, file browsing, or search inside your application's user interface. + +| Page | Type | Estimated time | +|---|---|---| +| [Office experiences](/sharepoint/dev/embedded/development/content-experiences/office-experience) | how-to | 20 min | +| [User experiences overview](/sharepoint/dev/embedded/development/content-experiences/user-experiences-overview) | concept | 10 min | +| [Search content](/sharepoint/dev/embedded/development/content-experiences/search-content) | how-to | 20 min | + +**Next step:** for step-by-step recipes on specific scenarios, proceed to [Tutorials](#tutorials). + +--- + +## 5. Tutorials {#tutorials} + +**Use this section if:** you have a specific scenario (preview, webhook, migration, etc.) and want a step-by-step recipe. + +| Page | Type | Estimated time | +|---|---|---| +| [Launch experience (Office client modes)](/sharepoint/dev/embedded/development/tutorials/launch-experience) | how-to | 20 min | +| [Using metadata on containers](/sharepoint/dev/embedded/development/tutorials/metadata) | how-to | 15 min | +| [File preview in iFrame](/sharepoint/dev/embedded/development/tutorials/using-file-preview) | how-to | 20 min | +| [Document processing with Azure AI](/sharepoint/dev/embedded/development/tutorials/doc-processing-acs) | how-to | 40 min | +| [Using webhooks](/sharepoint/dev/embedded/development/tutorials/using-webhooks) | how-to | 25 min | +| [Migrate Azure Blob Storage to SPE](/sharepoint/dev/embedded/development/tutorials/migrate-abs-to-spe) | how-to | 60 min | +| [Install app in a customer tenant](/sharepoint/dev/embedded/development/tutorials/vendor-install-app-customer) | how-to | 30 min | + +--- + +## 6. Developer Admin / ISV — Billing & tenant management {#dev-admin-billing} + +**Use this section if:** you are an ISV or developer admin configuring pay-as-you-go billing or managing your partner tenant's SPE applications. + +| Page | Type | Estimated time | +|---|---|---| +| [Billing overview](/sharepoint/dev/embedded/administration/billing/billing) | concept | 10 min | +| [Billing management](/sharepoint/dev/embedded/administration/billing/billingmanagement) | how-to | 20 min | +| [Billing meters](/sharepoint/dev/embedded/administration/billing/meters) | reference | 10 min | +| [Developer admin role](/sharepoint/dev/embedded/administration/developer-admin/dev-admin) | how-to | 15 min | +| [SharePoint Embedded admin overview](/sharepoint/dev/embedded/administration/adminrole) | concept | 10 min | + +--- + +## 7. Consuming Tenant Admin {#consuming-tenant-admin} + +**Use this section if:** you are an administrator in a Microsoft 365 tenant that has installed one or more SPE-based applications. + +| Page | Type | Estimated time | +|---|---|---| +| [Consuming tenant admin overview](/sharepoint/dev/embedded/administration/consuming-tenant-admin/cta) | concept | 15 min | +| [Container management in PowerShell](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell) | reference | 15 min | +| [Admin UX (SharePoint Admin Center)](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaux) | how-to | 15 min | + +--- + +## 8. Compliance & Security Officer {#compliance-security} + +**Use this section if:** you are responsible for applying Microsoft Purview policies and governing content stored in SPE containers. + +| Page | Type | Estimated time | +|---|---|---| +| [Security and compliance (Microsoft Purview)](/sharepoint/dev/embedded/compliance/security-and-compliance) | concept | 25 min | + +### Reference (cross-cutting) + +| Page | Type | +|---|---| +| [Microsoft Graph API](https://learn.microsoft.com/en-us/graph/api/overview) | reference | +| [PowerShell cmdlets for SharePoint Embedded](/sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell) | reference | + +--- + +## Navigation manifest (for agents) {#navigation-manifest} + +The block below is the machine-readable form of this page. Agents SHOULD parse it instead of scraping the human tables above; the two are kept in sync. + +```yaml +manifest_version: 1 +generated: 2026-06-09 +sections: + - id: new-to-spe + title: New to SharePoint Embedded + role: new-user + intent: orient + pages: + - { uri: /sharepoint/dev/embedded/overview, task_type: concept } + - { uri: /sharepoint/dev/embedded/scenarios-and-use-cases, task_type: concept } + - { uri: /sharepoint/dev/embedded/whats-new, task_type: reference } + - { uri: /training/modules/sharepoint-embedded-setup, task_type: quickstart } + - { uri: /training/modules/sharepoint-embedded-create-app, task_type: quickstart } + - id: dev-setup + title: Developer — Set up your environment + role: app-developer + intent: set-up-dev-env + pages: + - { uri: /sharepoint/dev/embedded/getting-started/spembedded-for-vscode, task_type: quickstart } + - { uri: /sharepoint/dev/embedded/getting-started/containertypes, task_type: how-to } + - { uri: /sharepoint/dev/embedded/getting-started/register-api-documentation, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/app-architecture, task_type: concept } + - id: dev-build + title: Developer — Build your app + role: app-developer + intent: build-app + pages: + - { uri: /sharepoint/dev/embedded/development/auth, task_type: concept-and-how-to } + - { uri: /sharepoint/dev/embedded/development/sharing-and-perm, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/limits-calling, task_type: reference } + - { uri: /sharepoint/dev/embedded/development/fluid, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/declarative-agent/sharepoint-embedded-knowledge-source, task_type: how-to, stability: preview } + - id: dev-content-experiences + title: Developer — Content experiences + role: app-developer + intent: build-content-experience + pages: + - { uri: /sharepoint/dev/embedded/development/content-experiences/office-experience, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/content-experiences/user-experiences-overview, task_type: concept } + - { uri: /sharepoint/dev/embedded/development/content-experiences/search-content, task_type: how-to } + - id: tutorials + title: Tutorials + role: app-developer + intent: follow-tutorial + pages: + - { uri: /sharepoint/dev/embedded/development/tutorials/launch-experience, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/tutorials/metadata, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/tutorials/using-file-preview, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/tutorials/doc-processing-acs, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/tutorials/using-webhooks, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/tutorials/migrate-abs-to-spe, task_type: how-to } + - { uri: /sharepoint/dev/embedded/development/tutorials/vendor-install-app-customer, task_type: how-to } + - id: dev-admin-billing + title: Developer Admin / ISV — Billing & tenant management + role: developer-admin + intent: configure-billing + pages: + - { uri: /sharepoint/dev/embedded/administration/billing/billing, task_type: concept } + - { uri: /sharepoint/dev/embedded/administration/billing/billingmanagement, task_type: how-to } + - { uri: /sharepoint/dev/embedded/administration/billing/meters, task_type: reference } + - { uri: /sharepoint/dev/embedded/administration/developer-admin/dev-admin, task_type: how-to } + - { uri: /sharepoint/dev/embedded/administration/adminrole, task_type: concept } + - id: consuming-tenant-admin + title: Consuming Tenant Admin + role: consuming-tenant-admin + intent: admin-consuming-tenant + pages: + - { uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/cta, task_type: concept } + - { uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell, task_type: reference } + - { uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctaux, task_type: how-to } + - id: compliance-security + title: Compliance & Security Officer + role: compliance-officer + intent: govern-content + pages: + - { uri: /sharepoint/dev/embedded/compliance/security-and-compliance, task_type: concept } + reference: + - { uri: /graph/api/overview, task_type: reference, owner: graph-docs } + - { uri: /sharepoint/dev/embedded/administration/consuming-tenant-admin/ctapowershell, task_type: reference } +routing_rules: + - if: user_intent in ["evaluate", "orient", "what-is-spe"] + then_section: new-to-spe + - if: user_intent in ["first-time-setup", "set-up-dev-env", "create-app-registration", "create-container-type"] + then_section: dev-setup + - if: user_intent in ["auth", "permissions", "scale", "fluid", "ai-knowledge-source"] + then_section: dev-build + - if: user_intent in ["office-editing", "file-browser", "search-ui"] + then_section: dev-content-experiences + - if: user_intent in ["webhook", "metadata", "file-preview", "migration", "install-tenant", "doc-processing"] + then_section: tutorials + - if: user_intent in ["billing", "payg", "meters", "developer-admin"] + then_section: dev-admin-billing + - if: user_intent in ["consuming-tenant", "tenant-admin-installed-apps", "powershell"] + then_section: consuming-tenant-admin + - if: user_intent in ["compliance", "purview", "ediscovery", "retention"] + then_section: compliance-security +ambiguity_fallback: new-to-spe +``` + +## Related + +- [/llms.txt](/sharepoint/dev/embedded/llms.txt) — corpus-wide agent index +- [/api-surface.json](/sharepoint/dev/embedded/api-surface.json) — every Microsoft Graph operation referenced by SPE docs +- [Microsoft Graph SPE API reference](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainer) + +## Structured data {#structured-data} + +```html + +``` diff --git a/docs/embedded/spe-docs-agent-ready/overview.md b/docs/embedded/spe-docs-agent-ready/overview.md new file mode 100644 index 000000000..5d33fcee2 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/overview.md @@ -0,0 +1,107 @@ +--- +title: SharePoint Embedded overview +description: API-only file and document storage on Microsoft 365, with containers, container types, and Purview-backed compliance. +ms.topic: concept-article +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: concept + difficulty: beginner + roles: [app-developer, enterprise-developer, consuming-admin, owning-admin, m365-admin, compliance-officer, end-user, migration-engineer] + prerequisites: [] + next_steps: + - uri: /sharepoint/dev/embedded/scenarios-and-use-cases + when: always + - uri: /sharepoint/dev/embedded/getting-started/spembedded-for-vscode + when: always + - uri: /sharepoint/dev/embedded/development/app-architecture + when: always + related: + - uri: /sharepoint/dev/embedded/scenarios-and-use-cases + - uri: /sharepoint/dev/embedded/development/app-architecture + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/getting-started/containertypes + - uri: /sharepoint/dev/embedded/compliance/security-and-compliance + - uri: /sharepoint/dev/embedded/administration/billing/billing + - uri: /sharepoint/dev/embedded/whats-new + stability: ga + last_validated: proposed +--- + +# SharePoint Embedded overview + + +## What it is + +SharePoint Embedded is a cloud-based, API-only file and document management system that any application can use. It lets app developers harness the Microsoft 365 file and document storage platform without surfacing the SharePoint user interface. Every operation is a Microsoft Graph call; the full operation index is published at [`/sharepoint/dev/embedded/api-surface.json`](/sharepoint/dev/embedded/api-surface.json). + +Content lives in **File Storage Containers** (`fileStorageContainer`), often called containers for short. A container is similar to an API-only document library: it holds a single drive whose files and folders are standard `driveItem` resources, supports any file type and folder structure, and can store multiple terabytes of content. Each container belongs to exactly one **container type**, which is owned 1:1 by a single application — the container type is the unit of ownership, billing, and permission scope. + +When an application is used in a Microsoft 365 tenant, SharePoint Embedded creates a separate storage partition within that tenant. The partition has no user experience of its own; its documents are accessible only through APIs and only to the owning application. Containers in that partition are dedicated to and accessible by just that app, so the app's content is isolated within the tenant boundary. + +> [!NOTE] +> SharePoint Embedded content inherits Microsoft Purview compliance from the tenant where it is stored (the consuming tenant): eDiscovery, auditing, data loss prevention (DLP), retention policies, sensitivity labels, and conditional access apply to that content because it resides in the consumer's Microsoft 365 tenant. + +SharePoint Embedded lets developers integrate advanced Microsoft 365 features into their apps, including collaborative Office capabilities, Microsoft Purview security and compliance tools, and Copilot capabilities. + +## Why it matters / when to use + +Use SharePoint Embedded when an application needs first-class document storage and collaboration — view, edit, and co-authoring of Word, Excel, and PowerPoint in Office Web and Desktop, plus search, sharing, automatic versioning, and a recycle bin — while the storage belongs to the app rather than to an end user's personal OneDrive or SharePoint site. + +It serves two primary audiences: + +- **Enterprises** building line-of-business applications that store and manage content within their own Microsoft 365 tenant, outside of regular Microsoft 365 entitlements. +- **ISVs** building multitenant applications that manage content within each customer's Microsoft 365 tenant. + +Certain Microsoft products, such as Loop and Designer, also use SharePoint Embedded to manage customer content. + +The application supplies the entire user experience layer; SharePoint Embedded supplies the API-driven storage, collaboration, and compliance underneath. For worked examples by persona, see [Scenarios and use cases](/sharepoint/dev/embedded/scenarios-and-use-cases). + +Billing is **pay-as-you-go (PAYG)**. The storage partition does not count toward a tenant's other Microsoft 365 entitlements, including total SharePoint storage. Instead it is billed separately through an Azure subscription on a metered consumption model based on storage in active and archived state and the number of API calls. See [Billing overview](/sharepoint/dev/embedded/administration/billing/billing). + +## When NOT to use + +- When end users need to own and manage their own files in their personal OneDrive or a standard SharePoint site — use SharePoint or OneDrive directly. +- When you need raw object/blob storage with no document semantics (no co-authoring, previews, search, or Purview) — use Azure Blob Storage. +- When users need the full, flexible SharePoint site experience and direct site navigation — SharePoint Embedded is headless and exposes no UI other than your application's. +- When the app has no Microsoft 365 / Microsoft Entra identity context to authenticate Graph calls. + +## Key terms + +| Term | Meaning | +|---|---| +| Container | A `fileStorageContainer`; the storage boundary holding one drive of `driveItem` content. Each can store multiple terabytes and is permissioned independently. | +| Container type | The definition bound 1:1 to an application that governs ownership, billing classification, and the permissions the app may hold. | +| Owning tenant | The tenant of the application/ISV that creates and owns the container type. | +| Consuming tenant | The tenant where the app is registered and containers are created and stored. For an enterprise building for itself, the owning and consuming tenant are the same. | +| Storage partition | The separate, API-only partition SharePoint Embedded creates inside a consuming tenant; it holds the app's containers and has no user experience. | +| Content plane | Operations on containers and their `driveItem` content. | +| Control plane | Operations on container types, registrations, billing, and consent. | + +## How it fits together + +In the **owning tenant**, an ISV or enterprise developer registers a Microsoft Entra application and creates a container type bound 1:1 to that app (a **control plane** operation). The container type carries a billing classification and the set of permissions the app may hold. For the full conceptual model, see [Application architecture](/sharepoint/dev/embedded/development/app-architecture). + +In each **consuming tenant**, the same app is registered, the container type is registered on that tenant, and admin consent is granted. Containers are then created and their `driveItem` content managed there (the **content plane**). The storage partition — the actual files, and the Microsoft Purview compliance that governs them — lives in the consuming tenant and is subject to that tenant's Microsoft 365 settings. For an ISV, this is the customer's tenant; for an enterprise building for itself, it is the enterprise's own tenant. + +Because the consuming tenant's Microsoft 365 settings apply, app documents are automatically in scope for that tenant's Purview compliance, risk, and security controls. See [Security and compliance](/sharepoint/dev/embedded/compliance/security-and-compliance). + +To get started, you can create a container in 15 minutes or less with the [SharePoint Embedded extension for Visual Studio Code](/sharepoint/dev/embedded/getting-started/spembedded-for-vscode), or follow the guided training: + +- [Microsoft Learning: SharePoint Embedded — overview & configuration](https://learn.microsoft.com/en-us/training/modules/sharepoint-embedded-setup) +- [Microsoft Learning: SharePoint Embedded — building applications](https://learn.microsoft.com/en-us/training/modules/sharepoint-embedded-create-app) + +## Related + +- [Scenarios and use cases](/sharepoint/dev/embedded/scenarios-and-use-cases) +- [Application architecture](/sharepoint/dev/embedded/development/app-architecture) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Container types](/sharepoint/dev/embedded/getting-started/containertypes) +- [Security and compliance](/sharepoint/dev/embedded/compliance/security-and-compliance) +- [Billing overview](/sharepoint/dev/embedded/administration/billing/billing) +- [What's new](/sharepoint/dev/embedded/whats-new) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) diff --git a/docs/embedded/spe-docs-agent-ready/scenarios-and-use-cases.md b/docs/embedded/spe-docs-agent-ready/scenarios-and-use-cases.md new file mode 100644 index 000000000..5cf612beb --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/scenarios-and-use-cases.md @@ -0,0 +1,123 @@ +--- +title: SharePoint Embedded scenarios and use cases +description: When to choose SharePoint Embedded over SharePoint — structured UX, controlled collaboration, and customer document upload. +ms.topic: concept-article +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: concept + difficulty: beginner + roles: [app-developer, enterprise-developer, owning-admin] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + next_steps: + - uri: /sharepoint/dev/embedded/getting-started/spembedded-for-vscode + when: always + - uri: /sharepoint/dev/embedded/development/app-architecture + when: always + related: + - uri: /sharepoint/dev/embedded/overview + - uri: /sharepoint/dev/embedded/development/app-architecture + - uri: /sharepoint/dev/embedded/development/sharing-and-perm + - uri: /sharepoint/dev/embedded/compliance/security-and-compliance + stability: ga + last_validated: proposed +--- + +# SharePoint Embedded scenarios and use cases + + +## What it is + +This page presents example scenarios that show how a custom application can use SharePoint Embedded. The scenarios are contextualized examples of how combinations of SharePoint Embedded features fit common application patterns; they are not an exhaustive list of every feature or scenario. + +Each scenario describes the situation it addresses, gives concrete example applications, and explains why SharePoint Embedded is a better fit than building directly on SharePoint. + +> [!NOTE] +> A common thread across these scenarios: your application is the only user interface, and content is logically separated from the rest of a tenant's Microsoft 365 storage while remaining in scope for Microsoft Purview compliance tools. + +## Why it matters / when to use + +Use the scenarios below to match your application pattern to SharePoint Embedded and to articulate why it is preferable to SharePoint for that pattern. + +### Scenario: Structured user experience + +The application requires a guided experience that makes users work in a structured way, rather than the flexible, open-ended experience of SharePoint. Where the application drives a business-critical or time-sensitive process, the dedicated resource allocation of SharePoint Embedded simplifies management of throttling. + +**Example applications:** + +- Extended Relationship Management (XRM) applications +- Engagement-based applications +- Workflow-based collaboration, with a defined state + +**Why SharePoint Embedded instead of SharePoint:** + +- Your application is the only user interface, allowing you to create a prescriptive user experience. +- Resources are separate from your Microsoft 365 entitlements, allowing for simpler resource management. + +### Scenario: Highly controlled collaboration + +When you build on top of SharePoint, a user with permissions can still navigate to the underlying site and, depending on their permission level, take actions the application did not intend — such as changing site settings — with unintended consequences for the application or its content. + +Because SharePoint Embedded is headless, there is no user interface other than the one the custom application provides. If the application does not supply a way to change content or settings, a user cannot circumvent the application through SharePoint. You choose which collaborative features, such as sharing, are available in your application. + +**Example applications:** + +- Deal room applications +- Shared research environments + +**Why SharePoint Embedded instead of SharePoint:** + +- You need the collaborative capabilities of SharePoint, but only through a highly customized user interface. +- You are handling high-value content and want to manage risk by removing a user's ability to discover or alter the content repository. +- All containers for the application can share default sharing settings that are separate from your OneDrive and SharePoint settings. +- Content is logically separated from other Microsoft 365 content. + +### Scenario: Customer-facing document upload + +The application is aimed at an end customer — inside or outside your organization — who needs to upload a file as part of their interaction. You want a simplified end-user experience in your custom application together with the Microsoft 365 capabilities of document storage and compliance. SharePoint Embedded supports this without requiring the application's users to have access or entitlement to your Microsoft 365 tenant. + +**Example applications:** + +- Applying evidence to a mortgage application +- Identity document verification + +**Why SharePoint Embedded instead of SharePoint:** + +- It is critical to segregate this data from the rest of your Microsoft 365 storage, while keeping it in scope for compliance tools like eDiscovery. +- No Microsoft 365 licensing is required for users, and there is no need to use external users in SharePoint. +- Containers offer a simple, flexible unit of data storage. + +## When NOT to use + +- When users need the full, flexible SharePoint site experience and direct site navigation — SharePoint Embedded deliberately removes that surface. +- When end users should own and manage their own files in their personal OneDrive or a standard SharePoint site. +- When the content has no document semantics and you only need raw object storage — use Azure Blob Storage instead. +- When users must have direct, licensed access to your Microsoft 365 tenant for reasons unrelated to the application's content. + +## Key terms + +| Term | Meaning | +|---|---| +| Headless | SharePoint Embedded exposes no end-user UI of its own; the application provides the entire experience. | +| Container | A `fileStorageContainer`; the unit of storage the application creates and permissions independently. | +| Dedicated resource allocation | Resources separate from a tenant's Microsoft 365 entitlements, which simplifies throttling and resource management for business-critical flows. | +| Logical separation | App content is segregated from other Microsoft 365 content while remaining in scope for Purview compliance tools. | + +## How it fits together + +Each scenario relies on the same model: the application owns a container type, creates containers in the relevant tenant, and exposes only the collaboration features it chooses. Content stays in the consuming tenant and inherits that tenant's Microsoft Purview compliance, while users interact solely through the application. + +For the underlying architecture, see [Application architecture](/sharepoint/dev/embedded/development/app-architecture). For the foundational concepts behind these scenarios, see the [SharePoint Embedded overview](/sharepoint/dev/embedded/overview). + +## Related + +- [SharePoint Embedded overview](/sharepoint/dev/embedded/overview) +- [Application architecture](/sharepoint/dev/embedded/development/app-architecture) +- [Sharing and permissions](/sharepoint/dev/embedded/development/sharing-and-perm) +- [Security and compliance](/sharepoint/dev/embedded/compliance/security-and-compliance) diff --git a/docs/embedded/spe-docs-agent-ready/toc.yml b/docs/embedded/spe-docs-agent-ready/toc.yml new file mode 100644 index 000000000..6244e7932 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/toc.yml @@ -0,0 +1,81 @@ +- name: SharePoint Embedded + href: index.md + items: + - name: New to SharePoint Embedded + items: + - name: Overview + href: overview.md + - name: Scenarios and use cases + href: scenarios-and-use-cases.md + - name: What's new + href: whats-new.md + - name: Set up your environment + items: + - name: VS Code extension + href: getting-started/spembedded-for-vscode.md + - name: Container types + href: getting-started/containertypes.md + - name: Register container type API + href: getting-started/register-api-documentation.md + - name: Build your app + items: + - name: Application architecture + href: development/app-architecture.md + - name: Authentication and authorization + href: development/auth.md + - name: Sharing and permissions + href: development/sharing-and-perm.md + - name: Limits and calling patterns + href: development/limits-calling.md + - name: Fluid Framework + href: development/fluid.md + - name: AI knowledge source in Microsoft Foundry + href: development/declarative-agent/sharepoint-embedded-knowledge-source.md + - name: Content experiences + items: + - name: Office experiences + href: development/content-experiences/office-experience.md + - name: User experiences overview + href: development/content-experiences/user-experiences-overview.md + - name: Search content + href: development/content-experiences/search-content.md + - name: Tutorials + items: + - name: Launch experience + href: development/tutorials/launch-experience.md + - name: Using metadata on containers + href: development/tutorials/metadata.md + - name: File preview in iFrame + href: development/tutorials/using-file-preview.md + - name: Document processing with Azure AI + href: development/tutorials/doc-processing-acs.md + - name: Using webhooks + href: development/tutorials/using-webhooks.md + - name: Migrate Azure Blob Storage to SPE + href: development/tutorials/migrate-abs-to-spe.md + - name: Install app in a customer tenant + href: development/tutorials/vendor-install-app-customer.md + - name: Billing & tenant management + items: + - name: Billing overview + href: administration/billing/billing.md + - name: Billing management + href: administration/billing/billingmanagement.md + - name: Billing meters + href: administration/billing/meters.md + - name: Developer admin role + href: administration/developer-admin/dev-admin.md + - name: SharePoint Embedded admin overview + href: administration/adminrole.md + - name: Consuming Tenant Admin + items: + - name: Consuming tenant admin overview + href: administration/consuming-tenant-admin/cta.md + - name: Container management in PowerShell + href: administration/consuming-tenant-admin/ctapowershell.md + - name: Admin UX (SharePoint Admin Center) + href: administration/consuming-tenant-admin/ctaux.md + - name: Compliance & Security + items: + - name: Security and compliance + href: compliance/security-and-compliance.md diff --git a/docs/embedded/spe-docs-agent-ready/whats-new.md b/docs/embedded/spe-docs-agent-ready/whats-new.md new file mode 100644 index 000000000..dc8d6c089 --- /dev/null +++ b/docs/embedded/spe-docs-agent-ready/whats-new.md @@ -0,0 +1,136 @@ +--- +title: What's new in SharePoint Embedded +description: Dated log of SharePoint Embedded releases — new Graph APIs, GA and preview milestones, cloud availability, and tooling. +ms.topic: reference +ms.service: sharepoint-online +ms.author: ShreyasSar26 +author: ShreyasSaravanan +ms.date: 06/16/2026 +ms.localizationpriority: high +agent: + schema_version: 1 + task_type: reference + difficulty: beginner + roles: [app-developer, enterprise-developer, consuming-admin, owning-admin, m365-admin, migration-engineer] + prerequisites: + - uri: /sharepoint/dev/embedded/overview + kind: concept + api_surface: [] + next_steps: + - uri: /sharepoint/dev/embedded/overview + when: always + related: + - uri: /sharepoint/dev/embedded/overview + - uri: /sharepoint/dev/embedded/development/auth + - uri: /sharepoint/dev/embedded/development/limits-calling + - uri: /sharepoint/dev/embedded/api-surface.json + stability: ga + last_validated: proposed +--- + +# What's new in SharePoint Embedded + + +This page is a dated log of SharePoint Embedded releases. Entries are listed newest first. Endpoint availability (beta versus v1.0) is recorded per entry; confirm any operation's method, path, and permissions against [`/sharepoint/dev/embedded/api-surface.json`](/sharepoint/dev/embedded/api-surface.json) before relying on it. + +> [!NOTE] +> Some links below point to Microsoft Graph reference, Microsoft Purview, PowerShell, or training pages outside the SharePoint Embedded doc set; those keep their full `https://learn.microsoft.com` URLs. + +## Release log + +### March 2026 + +| Change | Status / endpoint | Details | +|---|---|---| +| SharePoint Embedded agent SDK deprecated | Deprecated | Replaced by the [SharePoint Embedded knowledge source in Microsoft Foundry](/sharepoint/dev/embedded/development/declarative-agent/sharepoint-embedded-knowledge-source). | +| `fileStorageContainerType` **permissions** relationship | beta | Manages the container type's owners. See [Managing SharePoint Embedded applications created in the owning tenant](/sharepoint/dev/embedded/development/auth#managing-sharepoint-embedded-applications-created-in-the-owning-tenant) and the [`fileStorageContainerType` resource](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainertype). | +| `fileStorageContainer` **informationBarrier** property | beta | Manages the container's information barrier. See [Information barriers for SharePoint](https://learn.microsoft.com/en-us/purview/information-barriers-sharepoint) and the [`fileStorageContainer` resource](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainer). | +| Native PDF viewing — search, comments and sticky notes, printing | beta + v1.0 | Delivered via the [`driveItem: preview`](https://learn.microsoft.com/en-us/graph/api/driveitem-preview) API. | + +### February 2026 + +| Change | Status / endpoint | Details | +|---|---|---| +| SharePoint Embedded connector for Power Platform | GA | The [SharePoint Embedded connector](https://learn.microsoft.com/en-us/connectors/sharepointembedded/) for [Power Platform](https://learn.microsoft.com/en-us/power-platform/) is now generally available. | +| Availability in Microsoft 365 operated by 21Vianet (China) | GA | See [Microsoft Graph national cloud deployments](https://learn.microsoft.com/en-us/graph/deployments). | +| Migration APIs support file version history | — | [SharePoint Embedded migration](https://learn.microsoft.com/en-us/graph/api/resources/sharepointmigration-api-overview) APIs now support migrating file version history. | + +### January 2026 + +| Change | Status / endpoint | Details | +|---|---|---| +| Container column APIs | v1.0 | [List columns](https://learn.microsoft.com/en-us/graph/api/filestoragecontainer-list-columns), [create column](https://learn.microsoft.com/en-us/graph/api/filestoragecontainer-post-columns), [update column](https://learn.microsoft.com/en-us/graph/api/filestoragecontainer-update-column), and [delete column](https://learn.microsoft.com/en-us/graph/api/filestoragecontainer-delete-column) are now available on v1.0. | + +### December 2025 + +| Change | Status / endpoint | Details | +|---|---|---| +| `fileStorageContainerType` APIs | v1.0 | See the [`fileStorageContainerType` resource](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainertype). | +| `fileStorageContainerTypeRegistration` APIs | v1.0 | See the [`fileStorageContainerTypeRegistration` resource](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainertyperegistration). | + +### November 2025 + +| Change | Status / endpoint | Details | +|---|---|---| +| Availability in Microsoft 365 GCC | GA (not GCC High or DoD) | For US Government customers. See [Microsoft Graph national cloud deployments](https://learn.microsoft.com/en-us/graph/deployments). | +| Migration APIs | v1.0 | [SharePoint Embedded migration](https://learn.microsoft.com/en-us/graph/api/resources/sharepointmigration-api-overview) APIs are now available on v1.0. | + +### October 2025 + +| Change | Status / endpoint | Details | +|---|---|---| +| `recycleBinItem: restore` accepts `driveItemId` | — | [recycleBinItem: restore](https://learn.microsoft.com/en-us/graph/api/filestoragecontainer-restore-recyclebinitem) supports `driveItemId` as an alternate key, enabling restore when the original `driveItem` ID is known. | +| Microsoft 365 Archive support | Private preview | [Microsoft 365 Archive](https://learn.microsoft.com/en-us/microsoft-365/archive/archive-overview) is previewing SharePoint Embedded support for a limited number of customers. [Sign up for the private preview](https://forms.office.com/r/98Z4iqSKya). | + +### September 2025 + +| Change | Status / endpoint | Details | +|---|---|---| +| Migration APIs | beta | [SharePoint Embedded migration](https://learn.microsoft.com/en-us/graph/api/resources/sharepointmigration-api-overview) APIs available on beta. | +| `driveItem: invite` documentation | Docs update | Clarified restrictions for the root item of OneDrive for home drives and inviting *new* guests via app-only access. See [driveItem: invite](https://learn.microsoft.com/en-us/graph/api/driveitem-invite). | +| `driveItem: copy` documentation | Docs update | Clarified behaviors for metadata, versions, cross-geo operations, and known issues. See [driveItem: copy](https://learn.microsoft.com/en-us/graph/api/driveitem-copy). | +| Container membership cmdlets | PowerShell | New cmdlets for consuming tenant administrators: [add](https://learn.microsoft.com/en-us/powershell/module/microsoft.online.sharepoint.powershell/add-spocontaineruser), [remove](https://learn.microsoft.com/en-us/powershell/module/microsoft.online.sharepoint.powershell/remove-spocontaineruser), and [change](https://learn.microsoft.com/en-us/powershell/module/microsoft.online.sharepoint.powershell/set-spocontaineruser) container membership, in the [SharePoint Online Management Shell](https://learn.microsoft.com/en-us/powershell/sharepoint/sharepoint-online/introduction-sharepoint-online-management-shell). | + +### August 2025 + +| Change | Status / endpoint | Details | +|---|---|---| +| `fileStorageContainerType` APIs | beta | See the [`fileStorageContainerType` resource](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainertype). | +| `fileStorageContainerTypeRegistration` APIs | beta | See the [`fileStorageContainerTypeRegistration` resource](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainertyperegistration). | + +### July 2025 + +| Change | Status / endpoint | Details | +|---|---|---| +| `driveItem: copy` request parameters | v1.0 | Now supports `childrenOnly` and `includeAllVersionHistory`. See [driveItem: copy](https://learn.microsoft.com/en-us/graph/api/driveitem-copy). | + +### June 2025 + +| Change | Status / endpoint | Details | +|---|---|---| +| `CopilotEmbeddedChatHosts` container type setting now required for SharePoint Embedded agent | Config change | Set by the application owner via [`Set-SPOContainerTypeConfiguration`](https://learn.microsoft.com/en-us/powershell/module/sharepoint-online/set-spocontainertypeconfiguration); optionally overridden by consuming tenant administrators via [`Set-SPOApplication`](https://learn.microsoft.com/en-us/powershell/module/sharepoint-online/set-spoapplication). See [CSP policies](/sharepoint/dev/embedded/development/declarative-agent/spe-da-adv#csp-policies). | + +### May 2025 + +| Change | Status / endpoint | Details | +|---|---|---| +| Default container type limit raised to 25 per partner tenant | Limit change | See [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling#size-limits). | +| SharePoint Embedded agent moved to consumption-based model | Billing change | Applies to all users regardless of Copilot license. See [SharePoint Embedded agent](/sharepoint/dev/embedded/development/declarative-agent/spe-da). | +| Admin-consent guidance updated to URL-based admin consent | Docs update | See [Authentication and authorization](/sharepoint/dev/embedded/development/auth#whats-next). | +| Documented access pattern for operations requiring a user license | Docs update | See [Operations that require a user license](/sharepoint/dev/embedded/development/auth#operations-that-require-a-user-license). | + +## Examples + +The release log drives a few common reader decisions: + +- **Choosing an endpoint version.** Operations such as `fileStorageContainerType` and `fileStorageContainerTypeRegistration` graduated from beta (August 2025) to v1.0 (December 2025). Prefer v1.0 for production. Container type create/list/update/delete in [`/sharepoint/dev/embedded/api-surface.json`](/sharepoint/dev/embedded/api-surface.json) are still tracked as `beta` there; reconcile against the live `$metadata` before publishing. +- **Migrating with version history.** Migration APIs reached v1.0 in November 2025, and file version history migration was added in February 2026. Plan migrations against v1.0. +- **Checking cloud availability.** SharePoint Embedded reached GCC in November 2025 (not GCC High or DoD) and Microsoft 365 operated by 21Vianet in February 2026. Confirm your target cloud via [Microsoft Graph national cloud deployments](https://learn.microsoft.com/en-us/graph/deployments). + +## See also + +- [SharePoint Embedded overview](/sharepoint/dev/embedded/overview) +- [Authentication and authorization](/sharepoint/dev/embedded/development/auth) +- [Limits and calling patterns](/sharepoint/dev/embedded/development/limits-calling) +- [API surface index](/sharepoint/dev/embedded/api-surface.json) +- [Microsoft Graph SharePoint Embedded API reference](https://learn.microsoft.com/en-us/graph/api/resources/filestoragecontainer)