# SharePoint REST API - Working with Site Collections

`SP.Site` represents a SharePoint site collection — the top-level container with its own security boundary, storage quota, and administration settings. It is accessible at `/_api/site` from any site within the collection. This post covers reading and updating site collection properties, managing activated features, and accessing the site recycle bin.

* * *

## Introduction

SharePoint distinguishes between a *site collection* (`SP.Site`, accessible at `/_api/site`) and a *site* within that collection (`SP.Web`, accessible at `/_api/web`). Every site collection has a single `SP.Site` instance. Regardless of which URL you use as the prefix, `/_api/site` always resolves to the site collection containing that URL:

```plaintext
https://contoso.sharepoint.com/sites/marketing/_api/site
https://contoso.sharepoint.com/sites/marketing/team/_api/site
```

Both URLs above refer to the same `SP.Site` object — the marketing site collection. The second URL targets a subsite, but `/_api/site` still walks up to the site collection root. This contrasts with `/_api/web`, which resolves to the specific site at the URL prefix. See the Working with Sites post for `SP.Web`.

`SP.Site` exposes a narrower surface than `SP.Web`. Most of the entity's properties are read-only; write operations are limited to a small set of site-level settings, and they require Full Control-tier permissions — among the highest minimum permission requirements in this series.

> **Authentication note:** The raw HTTP examples use a SharePoint Bearer token. With delegated authentication, the token represents a signed-in user and the operation must be permitted by both the delegated scope and that user's SharePoint permissions. With application (app-only) authentication, the token represents the Entra application and SharePoint evaluates its application permissions. For Entra app-only access to SharePoint REST, Microsoft documents certificate-based authentication; client-secret app-only tokens are not accepted by SharePoint REST. The legacy SharePoint ACS app-only model was retired on November 27, 2023 and stopped working on April 2, 2026. In SPFx, use `SPHttpClient` instead — it supplies the current user's SharePoint authentication context and manages request digests for write operations.

* * *

## Before You Start: Headers and JSON Format

SharePoint's REST API defaults to **OData v3 in most cases** when the `OData-Version` header is not supplied. To use OData v4 — which is what SPFx's `SPHttpClient` uses by default — include the `OData-Version: 4.0` header:

```http
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Content-Type: application/json;odata.metadata=none  (JSON-body requests only)
```

For a full explanation of OData versions, JSON format options, and how these headers interact, see [Understanding SharePoint REST JSON Formats](https://robwindsor.hashnode.dev/understanding-sharepoint-rest-json-formats).

* * *

## The SP.Site Entity

A plain `GET /_api/site` returns the core properties of the site collection. The properties you'll use most often:

| Property | Type | Description |
| --- | --- | --- |
| `Id` | `Guid` | The site collection's GUID. Stable across URL changes. |
| `Url` | `string` | The full absolute URL of the site collection, e.g. `https://contoso.sharepoint.com/sites/marketing`. |
| `ServerRelativeUrl` | `string` | The server-relative URL, e.g. `/sites/marketing`. |
| `PrimaryUri` | `string` | The canonical URL of the site collection. Typically the same as `Url`. |
| `GeoLocation` | `string` | The multi-geo data center code for the site collection, e.g. `NAM`, `EUR`. |
| `ReadOnly` | `bool` | Whether the site collection is in a read-only state. |
| `WriteLocked` | `bool` | Whether the site collection is write-locked. |
| `LockIssue` | `string` | The reason for the lock if the site collection is locked. `null` when unlocked. |
| `CompatibilityLevel` | `int` | Always `15` in SharePoint Online. A holdover from on-premises version tracking. |
| `MaxItemsPerThrottledOperation` | `int` | The list view threshold. Always `5000` in SharePoint Online. |
| `CurrentChangeToken` | `SP.ChangeToken` | The current change token for this site collection. Used with `GetChanges` for incremental change detection. |
| `ShareByEmailEnabled` | `bool` | Whether sharing by email invitation is enabled. |
| `ShareByLinkEnabled` | `bool` | Whether sharing by anonymous link is enabled. |
| `DisableCompanyWideSharingLinks` | `bool` | Whether company-wide sharing links are disabled. |
| `DisableAppViews` | `bool` | Whether app views are disabled. |
| `DisableFlows` | `bool` | Whether Power Automate flows are disabled for the site collection. |
| `AllowDesigner` | `bool` | Whether SharePoint Designer access is allowed. |
| `AllowMasterPageEditing` | `bool` | Whether master page editing is allowed. |
| `GroupId` | `Guid` | The GUID of the connected Microsoft 365 group. All zeros if the site collection is not group-connected. This is a preview property but is returned in the default response. |
| `HubSiteId` | `Guid` | The GUID of the hub site this site collection is associated with. All zeros if not a hub site member. Preview property. |
| `IsHubSite` | `bool` | Whether this site collection is registered as a hub site. Preview property. |
| `Classification` | `string` | The site's SharePoint classification value, if configured. Site classification is distinct from Microsoft Purview sensitivity labels. Preview property. |
| `SensitivityLabelId` | `string` | The GUID of the sensitivity label. Preview property. |

Navigation properties (accessible via `$expand` or as sub-resource paths):

| Property | Type | Description |
| --- | --- | --- |
| `Owner` | `SP.User` | The site collection owner. In Microsoft 365 Group-connected sites this is the Owners group (PrincipalType=4), not an individual user. |
| `RootWeb` | `SP.Web` | The top-level web of the site collection. Equivalent to `/_api/web` when the request is made against the site collection's root URL. |
| `Features` | `SP.Feature` collection | Features activated at the site collection scope. |
| `RecycleBin` | `SP.RecycleBinItem` collection | Items in the site collection recycle bin. Requires `Sites.FullControl.All` / `AllSites.FullControl`. |
| `SecondaryContact` | `SP.User` | The secondary site collection administrator. |

The `Usage` property (type `SP.UsageInfo`) is not returned in the default response — it requires an explicit `$select`. See [Get Storage and Usage Statistics](#get-storage-and-usage-statistics) below.

* * *

## API Operations

### Get the Site Collection

Returns the `SP.Site` entity with all default properties:

```http
GET https://contoso.sharepoint.com/sites/marketing/_api/site
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
```

**Response — 200 OK** (abridged)

```json
{
  "CompatibilityLevel": 15,
  "CurrentChangeToken": {
    "StringValue": "1;1;a1b2c3d4-e5f6-7890-abcd-ef1234567890;639222683731500000;918667384"
  },
  "DisableAppViews": false,
  "DisableCompanyWideSharingLinks": false,
  "DisableFlows": false,
  "GeoLocation": "NAM",
  "GroupId": "a3b4c5d6-e7f8-9012-34ab-cdef12345678",
  "HubSiteId": "00000000-0000-0000-0000-000000000000",
  "Id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "IsHubSite": false,
  "LockIssue": null,
  "MaxItemsPerThrottledOperation": 5000,
  "PrimaryUri": "https://contoso.sharepoint.com/sites/marketing",
  "ReadOnly": false,
  "ServerRelativeUrl": "/sites/marketing",
  "ShareByEmailEnabled": true,
  "ShareByLinkEnabled": false,
  "Url": "https://contoso.sharepoint.com/sites/marketing",
  "WriteLocked": false
}
```

Several properties in the schema are legacy SharePoint on-premises fields with no practical meaning in SharePoint Online. `CompatibilityLevel` is always `15`. `UpgradeReminderDate` and `UpgradeScheduledDate` return placeholder dates from 1899 and 1753 respectively. You can safely ignore these.

Preview properties — `GroupId`, `HubSiteId`, `IsHubSite`, `Classification`, `SensitivityLabelId`, and others — are returned in the default response even without an explicit `$select`. Their values reflect the current site configuration.

> **Delegated Permission:** Requires **AllSites.Read** for a user with modern SharePoint Visitor Group permission or SharePoint's built-in Read permission or greater.

> **Application Permission:** Requires the **Sites.Read.All** permission scope or higher.

* * *

### Get Selected Properties

Use `$select` to return only specific properties:

```http
GET https://contoso.sharepoint.com/sites/marketing/_api/site?$select=Id,Url,GroupId,IsHubSite,GeoLocation
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
```

**Response — 200 OK**

```json
{
  "GeoLocation": "NAM",
  "GroupId": "a3b4c5d6-e7f8-9012-34ab-cdef12345678",
  "Id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "IsHubSite": false,
  "Url": "https://contoso.sharepoint.com/sites/marketing"
}
```

> **Delegated Permission:** Requires **AllSites.Read** for a user with modern SharePoint Visitor Group permission or SharePoint's built-in Read permission or greater.

> **Application Permission:** Requires the **Sites.Read.All** permission scope or higher.

* * *

### Get Storage and Usage Statistics

The `Usage` property is not included in the default response. Request it explicitly with `$select`:

```http
GET https://contoso.sharepoint.com/sites/marketing/_api/site?$select=Usage
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
```

**Response — 200 OK**

```json
{
  "Usage": {
    "Bandwidth": 0,
    "DiscussionStorage": 0,
    "Hits": 0,
    "Storage": 1909785,
    "StoragePercentageUsed": 6.947757356101646e-8,
    "Visits": 0
  }
}
```

`Storage` is in bytes. `StoragePercentageUsed` is the fraction of the site collection's storage quota currently in use. The `Bandwidth`, `Hits`, and `Visits` values above are from a near-empty test site; active sites may return non-zero values for these fields.

> **Delegated Permission:** Requires **AllSites.Manage** for a user with modern SharePoint Owner Group permission or SharePoint's built-in Full Control permission level. Member-level users return 403 regardless of delegated scope (validated against SharePoint Online).

> **Application Permission:** Requires the **Sites.Read.All** permission scope or higher.

* * *

### Expand Navigation Properties

Navigation properties are not included in the default response. Use `$expand` to include them inline. Combine with `$select` to control which properties of the expanded entity are returned:

```http
GET https://contoso.sharepoint.com/sites/marketing/_api/site?$expand=Owner&$select=Id,Owner
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
```

**Response — 200 OK**

```json
{
  "Id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "Owner": {
    "Email": "marketing@contoso.onmicrosoft.com",
    "Id": 6,
    "IsHiddenInUI": true,
    "LoginName": "c:0o.c|federateddirectoryclaimprovider|a3b4c5d6-e7f8-9012-34ab-cdef12345678_o",
    "PrincipalType": 4,
    "Title": "Marketing Owners",
    "UserPrincipalName": null,
    "UserId": null
  }
}
```

For Microsoft 365 Group-connected sites, `Owner` is the Owners security group (`PrincipalType: 4`), not an individual user. `UserId` and `UserPrincipalName` are `null` in this case. For non-group-connected sites, `Owner` is an individual `SP.User` with the usual user properties.

Expanding `RootWeb` returns the full `SP.Web` entity for the site collection's top-level web. When called from the site collection's root URL this is the same data as `/_api/web`, but if called from a subsite URL, `RootWeb` still refers to the site collection root while `/_api/web` refers to the subsite. This can be useful when you need both site collection and site properties in a single request, but it returns the complete web entity and may be more data than you need. Use `$select` on the expanded property to narrow it:

```http
GET https://contoso.sharepoint.com/sites/marketing/_api/site?$expand=RootWeb&$select=Id,RootWeb/Id,RootWeb/Title,RootWeb/Url
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
```

> **Delegated Permission:** Requires **AllSites.Read** for a user with modern SharePoint Visitor Group permission or SharePoint's built-in Read permission or greater.

> **Application Permission:** Requires the **Sites.Read.All** permission scope or higher.

* * *

### Update Site Collection Properties

Send a `MERGE` request with only the properties to change. Omitted properties are unchanged:

```http
POST https://contoso.sharepoint.com/sites/marketing/_api/site
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Content-Type: application/json;odata.metadata=none
Authorization: Bearer <token>
X-HTTP-Method: MERGE
If-Match: *

{
  "DisableFlows": true
}
```

**Response — 204 No Content**

> **Delegated Permission:** Requires **AllSites.FullControl** for a user with modern SharePoint Owner Group permission or SharePoint's built-in Full Control permission level.

> **Application Permission:** Requires the **Sites.FullControl.All** permission scope. `Sites.ReadWrite.All` and `Sites.Manage.All` both return 403 (validated against SharePoint Online).

`If-Match: *` is required. Omitting it returns `400 Bad Request`.

Writable properties include `DisableFlows`, `DisableAppViews`, `DisableCompanyWideSharingLinks`, `ShareByEmailEnabled`, `AllowDesigner`, and `AllowMasterPageEditing`. Most other properties on `SP.Site` are read-only.

* * *

## Working with Features

A SharePoint feature is a packaged unit of functionality that can be activated or deactivated on a site collection or site. Site collection-scoped features are managed through `/_api/site/features`; site-scoped features are managed through `/_api/web/features` (covered in the Working with Sites post).

The two operations — activate and deactivate — both require `Sites.FullControl.All` / `AllSites.FullControl`.

### List Active Features

Returns the collection of currently activated site collection features:

```http
GET https://contoso.sharepoint.com/sites/marketing/_api/site/features?$select=DefinitionId,DisplayName
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
```

**Response — 200 OK**

```json
{
  "value": [
    {
      "DefinitionId": "00bfea71-1c5e-4a24-b310-ba51c3eb7a57",
      "DisplayName": "BasicWebParts"
    },
    {
      "DefinitionId": "ca7bd552-10b1-4563-85b9-5ed1d39c962a",
      "DisplayName": "Fields"
    }
  ]
}
```

Without `$select`, the default response returns only `DefinitionId` — `DisplayName` is not included. The `DisplayName` values are internal feature names, not the friendly names shown in the SharePoint administration UI. Each activated feature is identified by its GUID; you must know the GUID in advance to activate or deactivate a specific feature.

> **Delegated Permission:** Requires **AllSites.Read** for a user with modern SharePoint Visitor Group permission or SharePoint's built-in Read permission or greater.

> **Application Permission:** Requires the **Sites.Read.All** permission scope or higher.

* * *

### Activate a Feature

Call `add` on the features collection, passing the feature GUID, a `force` flag, and a `featdefScope` value. Set `force` to `false` for a standard activation and pass `featdefScope=0` (`FeatureDefinitionScope.None`, which was accepted by SharePoint Online in testing):

```http
POST https://contoso.sharepoint.com/sites/marketing/_api/site/features/add(featureId=guid'a1b2c3d4-e5f6-7890-abcd-ef1234567890',force=false,featdefScope=0)
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
Content-Length: 0
```

**Response — 200 OK**

```json
{
  "DefinitionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
```

The response returns the `DefinitionId` of the activated feature. Feature activation in SharePoint Online can involve background provisioning — lists, content types, or event receivers may be created asynchronously after the API call returns. A `GET` confirming the feature appears in the active features collection establishes that SharePoint has registered the activation, but not necessarily that every asynchronous provisioning side effect has completed. If you intend to deactivate the feature immediately after activating it, wait for that GET confirmation before calling `remove`.

> **Note:** `featdefScope=0` corresponds to `FeatureDefinitionScope.None` and worked in SharePoint Online testing, allowing SharePoint to resolve the feature definition. Microsoft's `FeatureCollection.Add` documentation states that this parameter should be `Site` or `Farm`, although Microsoft examples elsewhere also use `None`. The behavior shown here is based on live validation.

> **Delegated Permission:** Requires **AllSites.FullControl** for a user with modern SharePoint Owner Group permission or SharePoint's built-in Full Control permission level.

> **Application Permission:** Requires the **Sites.FullControl.All** permission scope. `Sites.ReadWrite.All` and `Sites.Manage.All` both return 403 (validated against SharePoint Online).

* * *

### Deactivate a Feature

Call `remove` on the features collection, passing the feature GUID and a `force` flag:

```http
POST https://contoso.sharepoint.com/sites/marketing/_api/site/features/remove(featureId=guid'a1b2c3d4-e5f6-7890-abcd-ef1234567890',force=false)
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
Content-Length: 0
```

**Response — 204 No Content**

Set `force` to `true` only if a standard deactivation returns an error — forcing it to proceed despite errors, which may leave orphaned content. Some features cannot be deactivated via REST regardless of permission level — for example, the Document ID Service returns 403 even with `Sites.FullControl.All` (validated). These features must be deactivated through the SharePoint administration UI or PowerShell. If `remove` returns 403 with FullControl scope, this may be the cause, though the status code alone does not establish it.

> **Delegated Permission:** Requires **AllSites.FullControl** for a user with modern SharePoint Owner Group permission or SharePoint's built-in Full Control permission level.

> **Application Permission:** Requires the **Sites.FullControl.All** permission scope (validated against SharePoint Online).

* * *

### Check Whether a Feature Is Active

Use `getbyid` to retrieve a specific feature by GUID:

```http
GET https://contoso.sharepoint.com/sites/marketing/_api/site/features/getbyid(guid'a1b2c3d4-e5f6-7890-abcd-ef1234567890')
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
```

**Response — 200 OK** (feature is active)

```json
{
  "DefinitionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
```

**Response — 200 OK** (feature is not active)

```json
{
  "@odata.null": true
}
```

When the feature is not active, SharePoint returns `200 OK` with `{"@odata.null":true}` — the OData v4 representation of a null single entity. It does not return `404 Not Found`. Check for the presence of `DefinitionId` in the response (or the absence of `@odata.null`) rather than relying on HTTP status to determine whether a feature is active.

> **Delegated Permission:** Requires **AllSites.Read** for a user with modern SharePoint Visitor Group permission or SharePoint's built-in Read permission or greater.

> **Application Permission:** Requires the **Sites.Read.All** permission scope or higher.

* * *

## Working with the Site Recycle Bin

`/_api/site/recyclebin` returns the items in the site collection recycle bin:

```http
GET https://contoso.sharepoint.com/sites/marketing/_api/site/recyclebin
OData-Version: 4.0
Accept: application/json;odata.metadata=none
Authorization: Bearer <token>
```

**Response — 200 OK** (illustrative — the test site recycle bin was empty during live validation; the shape below reflects the entity schema)

```json
{
  "value": [
    {
      "AuthorEmail": "alex@contoso.onmicrosoft.com",
      "AuthorName": "Alex Wilber",
      "DeletedByEmail": "alex@contoso.onmicrosoft.com",
      "DeletedByName": "Alex Wilber",
      "DeletedDate": "2026-08-12T14:00:00Z",
      "DirName": "sites/marketing/Documents",
      "Id": "b1c2d3e4-f5a6-7890-bcde-f12345678901",
      "ItemState": 1,
      "ItemType": 1,
      "LeafName": "report.docx",
      "Size": "24576",
      "Title": "report.docx"
    }
  ]
}
```

`ItemState` indicates which stage of the recycle bin the item is in: `1` = first-stage (end-user recycle bin), `2` = second-stage (site collection recycle bin). `Size` is returned as a JSON string, not a number (validated against SharePoint Online).

`ItemType` indicates what kind of object was recycled:

| `ItemType` | Meaning |
| --- | --- |
| `0` | None |
| `1` | File |
| `2` | File version |
| `3` | List item |
| `4` | List or library |
| `5` | Folder |
| `6` | Folder containing lists |
| `7` | Attachment |
| `8` | List item version |
| `9` | Cascade parent |
| `10` | Web (subsite) |
| `11` | App |

Values `1`–`4` were validated against SharePoint Online; values `5`–`11` are from the CSOM `RecycleBinItemType` documentation.

Two additional properties — `DirNamePath` and `LeafNamePath` — are also present in the response as `{ "DecodedUrl": "..." }` objects rather than plain strings. `DirNamePath.DecodedUrl` corresponds to `DirName`; `LeafNamePath.DecodedUrl` corresponds to `LeafName`.

> **Delegated Permission:** Requires **AllSites.FullControl** for a user with modern SharePoint Owner Group permission or SharePoint's built-in Full Control permission level.

> **Application Permission:** Requires the **Sites.FullControl.All** permission scope. `Sites.Read.All`, `Sites.ReadWrite.All`, and `Sites.Manage.All` all return 403 (validated against SharePoint Online).

* * *

## Quick Reference

### Headers

| Header | Value | When required |
| --- | --- | --- |
| `OData-Version` | `4.0` | All requests |
| `Accept` | `application/json;odata.metadata=none` | All requests |
| `Content-Type` | `application/json;odata.metadata=none` | JSON body requests |
| `X-HTTP-Method` | `MERGE` | Update requests |
| `If-Match` | `*` | Update requests |
| `Content-Length` | `0` | Feature activate/deactivate (bodyless POST) |
| `Authorization` | `Bearer <token>` | All requests |

### Status Codes

| Code | Meaning | When returned |
| --- | --- | --- |
| `200 OK` | Success with response body | GET requests; feature activate; `getbyid` (active or inactive — see body) |
| `204 No Content` | Success with no response body | MERGE (update); feature deactivate |
| `400 Bad Request` | Missing required header | MERGE without `If-Match` |
| `403 Forbidden` | Insufficient permission | MERGE or feature activate/deactivate with less than `Sites.FullControl.All`; recycle bin with less than `Sites.FullControl.All`; Usage with less than Owner-level user permission |
| `411 Length Required` | Missing Content-Length | Feature activate or deactivate without `Content-Length: 0` |

### Permission Requirements

The table below lists the minimum delegated and application permission scopes. Delegated scopes apply when calling with a Bearer token on behalf of a signed-in user; the minimum user permission level column shows what access the signed-in user needs when using classic SharePoint permissions and modern SharePoint group permissions. Application permissions apply when calling without a signed-in user context (app-only). The application permissions in this table are permissions on the Office 365 SharePoint Online API, not the same-named Microsoft Graph permissions. An SPFx solution using `SPHttpClient` does not require you to grant these delegated or application scopes to the solution; it calls SharePoint as the current user, whose SharePoint permissions govern the operation. Delegated and application scope requirements in this table were live-validated against SharePoint Online. Basic read operations were tested with a Member-level delegated user (AllSites.Read scope) and app-only (Sites.Read.All); elevated operations (Usage, recycle bin, write) were tested with an Owner-level delegated user and app-only FullControl tokens. The classic SharePoint permission-level minima in the table come from Microsoft's documentation.

| Operation | Minimum delegated permission | Minimum user permission level | Minimum tenant-wide application permission |
| --- | --- | --- | --- |
| Get site collection properties | `AllSites.Read` | Classic: Read; Group: Visitor | `Sites.Read.All` |
| Get selected properties | `AllSites.Read` | Classic: Read; Group: Visitor | `Sites.Read.All` |
| Get usage statistics | `AllSites.Manage` | Classic: Full Control; Group: Owner | `Sites.Read.All` |
| Expand navigation properties | `AllSites.Read` | Classic: Read; Group: Visitor | `Sites.Read.All` |
| Update site collection properties | `AllSites.FullControl` | Classic: Full Control; Group: Owner | `Sites.FullControl.All` |
| List active features | `AllSites.Read` | Classic: Read; Group: Visitor | `Sites.Read.All` |
| Check feature active | `AllSites.Read` | Classic: Read; Group: Visitor | `Sites.Read.All` |
| Activate a feature | `AllSites.FullControl` | Classic: Full Control; Group: Owner | `Sites.FullControl.All` |
| Deactivate a feature | `AllSites.FullControl` | Classic: Full Control; Group: Owner | `Sites.FullControl.All` |
| Get recycle bin items | `AllSites.FullControl` | Classic: Full Control; Group: Owner | `Sites.FullControl.All` |

> **Note:** The application permissions above are tenant-wide grants. For least-privilege access to specific site collections, the SharePoint **Sites.Selected** permission can be used for both application and delegated tokens. Sites.Selected consent alone does not grant access to any site — an explicit Read, Write, Manage, or FullControl role must be assigned on each target site collection via the Microsoft Graph `/sites/{id}/permissions` endpoint. For delegated tokens, access is the intersection of the signed-in user's own permissions and the role granted to the application for that site.

* * *

## Wrapping Up

`SP.Site` exposes the site collection container and its administrative configuration. Key takeaways:

*   `/_api/site` always resolves to the site collection — whichever sub-URL you prefix it with, you get the same `SP.Site` object.
    
*   Most properties are read-only. Write operations on `SP.Site` require `Sites.FullControl.All` (app-only) or `AllSites.FullControl` (delegated) — the highest permission level in the series.
    
*   Preview properties — `GroupId`, `IsHubSite`, `Classification`, and others — are returned in the default response without needing `$select`.
    
*   `Usage` (storage/bandwidth statistics) is not in the default response; request it with `$select=Usage`.
    
*   `DisplayName` is not returned in the default features response; add `$select=DefinitionId,DisplayName` to get it.
    
*   Feature activation may involve asynchronous background provisioning. Confirm a feature is listed in the active features collection before attempting to deactivate it.
    
*   Some features cannot be deactivated via REST regardless of permission level and require the SharePoint administration UI or PowerShell instead.
    
*   The site recycle bin (`/_api/site/recyclebin`) requires `Sites.FullControl.All` — it returns 403 even with `Sites.Manage.All`.
    

Happy coding!
