The SharePoint REST API in Practice
Endpoints, query options, request digests and the mistakes that turn a working integration into a slow or broken one.
Rajiv KumarApril 13, 20204 min read
A practical guide to the SharePoint REST API: why $select is not optional, how paging really works, what a request digest is for, and why anything built on ACS authentication stopped working in April 2026.
The SharePoint REST API is what you use when the platform's own tools do not fit — a custom integration, an external system that needs to read a list, a script in a language with no SharePoint SDK. It is well documented and mostly predictable, and the parts that catch people out are consistent enough to be worth knowing in advance.
The shape of the API
Every endpoint hangs off a site's _api path:
https://contoso.sharepoint.com/sites/finance/_api/web/lists/getbytitle('Invoices')/items
Three things are always true and worth internalising:
- The site in the URL scopes the request. There is no tenant-wide list query; you address one site at a time.
- Ask for JSON explicitly. Without an
Acceptheader you may get XML. - Reads are GET; writes need more. Creating and updating requires a request digest and the correct headers.
Reading data
The query options that matter, and the one that matters most:
GET /_api/web/lists/getbytitle('Invoices')/items
?$select=Id,Title,Amount,Status,Created
&$filter=Status eq 'Approved'
&$orderby=Created desc
&$top=100
Accept: application/json;odata=nometadata
$select is not optional in practice. Omit it and SharePoint returns every column on every item, including ones you did not know existed. On a wide list that is a large multiple of the payload you need. Naming columns explicitly is the single most effective thing you can do for performance.
odata=nometadata is similarly worth setting. It strips OData metadata you almost certainly are not using and makes responses substantially smaller and easier to read.
Expanding lookups
Lookup and person columns return an ID by default. To get the related values, expand them — and note that $select must name the expanded fields too:
GET /_api/web/lists/getbytitle('Invoices')/items
?$select=Id,Title,Author/Title,Author/EMail
&$expand=Author
Paging
The list view threshold applies to the API exactly as it does to the interface. Rather than constructing your own paging, follow the odata.nextLink the response provides — it encodes the paging state correctly, including for filtered queries.
Writing data
Writes need a request digest, which proves the request came from an authorised context.
POST /_api/contextinfo
Accept: application/json;odata=nometadata
Take FormDigestValue from the response and send it with the write:
POST /_api/web/lists/getbytitle('Invoices')/items
Accept: application/json;odata=nometadata
Content-Type: application/json;odata=verbose
X-RequestDigest: <FormDigestValue>
{
"__metadata": { "type": "SP.Data.InvoicesListItem" },
"Title": "INV-2043",
"Amount": 1250.00,
"Status": "Draft"
}
The __metadata.type value is the list's entity type name. It is derived from the list's internal name, not its display title, so a list renamed after creation keeps its original entity type. Read it from /_api/web/lists/getbytitle('Invoices')?$select=ListItemEntityTypeFullName rather than guessing.
Updates and deletes additionally need IF-MATCH and an X-HTTP-Method override:
POST /_api/web/lists/getbytitle('Invoices')/items(42)
X-RequestDigest: <FormDigestValue>
IF-MATCH: *
X-HTTP-Method: MERGE
IF-MATCH: * means "update regardless of version". Where concurrent edits are possible, send the item's actual ETag instead so a conflicting update fails rather than silently overwriting.
Authentication
For anything outside a SharePoint page, register an application in Microsoft Entra ID and authenticate with OAuth 2.0. Azure ACS-based authentication was retired for SharePoint Online in April 2026, so approaches built on appregnew.aspx registrations no longer work.
For new integrations, evaluate Microsoft Graph first. Graph covers a growing share of SharePoint functionality with a more consistent interface. The SharePoint REST API remains necessary for scenarios Graph does not yet reach, which is why both are worth knowing.
Common mistakes and better practice
- Omitting
$select. The most common performance problem, and the easiest to fix. - Constructing paging manually. Follow
odata.nextLink; hand-built$skippaging misbehaves on filtered queries. - Ignoring the view threshold. The API is subject to it too. Index the columns you filter on.
- Guessing the entity type name. Read
ListItemEntityTypeFullName; renamed lists keep their original internal name. - Using
IF-MATCH: *everywhere. Fine for single-writer automation, wrong where concurrent edits happen. - Building on retired authentication. ACS is gone. Use Entra ID.
- One request per item. For bulk work, use
$batchrather than a loop of individual calls.
Troubleshooting
| Response | Cause | Resolution |
|---|---|---|
401 Unauthorized | Token missing, expired, or issued by retired ACS | Authenticate through Entra ID and refresh the token |
403 Forbidden on write, reads work | Missing request digest, or insufficient permission | Fetch /_api/contextinfo and send X-RequestDigest |
400 with an entity type error | __metadata.type does not match the list | Read ListItemEntityTypeFullName from the list |
| Threshold error on a filtered query | Filter column not indexed | Index the column; keep result sets small |
| Lookup fields return only an ID | Not expanded | Add $expand and select the child fields |
429 Too Many Requests | Throttling | Honour Retry-After; batch requests; set a descriptive User-Agent |
| Update overwrote another user's change | IF-MATCH: * | Send the item's ETag instead |
Frequently asked questions
REST API or Microsoft Graph?
Graph first for new work where it covers the scenario — it is more consistent and more actively extended. The SharePoint REST API remains necessary for functionality Graph does not yet expose.
Why do writes fail when reads succeed?
Almost always the request digest. Reads do not need it; writes do.
Does the 5,000 item threshold apply to the API?
Yes. It is a platform limit, not an interface limit.
How should throttling be handled?
Honour the Retry-After header, back off rather than retrying immediately, batch where possible, and set a descriptive User-Agent so the service can identify your traffic.
Can ACS-based authentication still be used?
No. Azure ACS was retired for SharePoint Online in April 2026. Applications must use Microsoft Entra ID.
The parts worth getting right
Most REST API difficulty comes down to four things: select your columns, follow the provided paging link, fetch a digest before writing, and authenticate through Entra ID.
Get those right and the API is unremarkable to work with. Skip any of them and you get a slow integration, a paging bug, a 403 you cannot explain, or an integration that stopped working in April 2026.

