Three important APIs to master SitecoreAI
A practical, Postman-first tour of every API you'll touch on SitecoreAI — with credentials, scopes, endpoints, and the gotchas that trip up everyone.
Start typing to search...
A practical, Postman-first tour of every API you'll touch on SitecoreAI — with credentials, scopes, endpoints, and the gotchas that trip up everyone.
There are really three APIs that matter on SitecoreAI. Each one tied to a distinct stage of the content lifecycle, and each one unlocked by a different credential type. Master those three and you can drive every programmatic interaction with the platform: reading content, editing it, running workflow, publishing, clearing cache, rotating keys.
This guide walks through each API: what it does, which credential unlocks it, where to create that credential, and the exact Postman request to fire. Everything here is drawn from real hands-on work wiring up a production workflow app, including the specific gotchas that waste the most time.
By the end you'll have three credentials, a working Postman collection, and a mental model that makes the whole platform click.
Every piece of content on SitecoreAI moves through three stages:
Each stage has its own API:
| Stage | API | What it does |
|---|---|---|
| Author | Authoring & Management GraphQL API | Create/edit items, run workflow |
| Publish | Edge Administration REST API | Manage cache, webhooks, settings |
| Deliver | Edge Delivery GraphQL API | Read published content |
Plus a fourth sibling of the Edge Admin API that most people miss:
| Extra | API | What it does |
|---|---|---|
| Token management | Edge Token REST API | Create / revoke the sc_apikey keys used by Delivery |
So the real count is 3 primary APIs + 1 reference API, and they're managed by 3 types of credentials.
Sitecore's own docs say "Sitecore Authoring and Management GraphQL API" — singular. Read the first line of the official reference:
The Sitecore Authoring and Management API provides a single endpoint and schema that allows you to manage your Sitecore content using GraphQL.
One endpoint. One schema. One credential scope.
What trips people up is that older blog posts and credential labels imply they're separate. They're not. The names describe two categories of operations inside the same API:
createItem, updateItem, deleteItem, moveItemexecuteWorkflowCommand, workflow state queriesSame URL. Same Bearer token. Different GraphQL mutations. That's the whole story.
All OAuth credentials are created on the Credentials page of your SitecoreAI project:
https://portal.sitecorecloud.io → Your project → Credentials| Tab | Scope | Use for |
|---|---|---|
| Organization | Works across every environment in the org | CI/CD pipelines, Sitecore CLI, cross-env tooling |
| Environment | Scoped to one environment | App runtime credentials (safer) |
Rule of thumb: app runtime → Environment tab. CI/CD → Organization tab. Environment-scoped creds have a smaller blast radius if they leak.
When you click Create credentials, you pick a type. The type is the scope preset. You don't get a separate scope picker in the UI.
| Type | Grants | Use for |
|---|---|---|
| Automation | xmcloud.cm:admin + xmclouddeploy.* | Authoring & Management GraphQL API |
| Edge administration | edge.* (cache, settings, webhooks, tokens) | Edge Admin REST API + Edge Token REST API |
| External editing host | CLI/editing host scopes | Sitecore CLI, external editing host deploys |
For typical app development, you need one Automation credential and one Edge administration credential. That's it.
The credential list in the portal does not show scopes. The only reliable way to see what a credential actually unlocks is to request an OAuth token and decode it:
access_token stringscope claimExample decoded scopes from an Automation credential:
xmclouddeploy.organizations:manage
xmclouddeploy.projects:manage
xmclouddeploy.environments:manage
xmclouddeploy.deployments:manage
xmcloud.cm:admin ← this one unlocks Authoring & ManagementExample from an Edge administration credential:
edge.caches:clear
edge.settings:read / update
edge.webhooks:create / read / update / delete
edge.tokens:create / read / update / delete
edge.content:publish
edge.content:clearallAnother useful claim: tenant_id — it tells you which Sitecore environment the token is bound to. More on this in the gotchas section.
Create a Postman environment with these variables before starting:
# Your environment's instance slug — from Environment host name on the Details tab
# e.g. fishtankcon7604-navigatoracc468-dev2cbf
SITECORE_INSTANCE=
# --- Edge Delivery (read) ---
SITECORE_EDGE_DELIVERY_ENDPOINT=https://xmc-{INSTANCE}.sitecorecloud.io/sitecore/api/graph/edge
SITECORE_API_KEY= # sc_apikey — Edge delivery key
# --- Authoring & Management (one API) ---
SITECORE_MANAGEMENT_ENDPOINT=https://xmc-{INSTANCE}.sitecorecloud.io/sitecore/api/authoring/graphql/v1
SITECORE_MANAGEMENT_CLIENT_ID= # from Automation credential
SITECORE_MANAGEMENT_CLIENT_SECRET= # from Automation credential
SITECORE_MANAGEMENT_AUDIENCE=https://api.sitecorecloud.io
# --- Edge Administration + Token ---
EDGE_ADMIN_ENDPOINT=https://edge.sitecorecloud.io/api/admin/v1
EDGE_TOKEN_ENDPOINT=https://edge.sitecorecloud.io/api/apikey/v1
EDGE_ADMIN_CLIENT_ID= # from Edge administration credential
EDGE_ADMIN_CLIENT_SECRET= # from Edge administration credential
EDGE_ADMIN_AUDIENCE=https://api.sitecorecloud.io
# --- Test data ---
TEST_ITEM_ID={YOUR-TEST-ITEM-GUID} # format: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
WORKFLOW_COMMAND_ID= # from GetWorkflow response (see below)Important: Once variables are filled, activate the environment using the dropdown in the top-right of Postman. If you leave it on "No environment," your {{variables}} won't resolve and every request will fail in confusing ways.
Role: Read published content from the delivery layer. This is what your website calls.
Endpoint: https://xmc-{instance}.sitecorecloud.io/sitecore/api/graph/edge
Protocol: GraphQL
Auth: sc_apikey header (no OAuth, a single long-lived string)
Where to get the key:
POST /api/apikey/v1/tokens/sitecore/system/Settings/Services/API KeysPOST {{SITECORE_EDGE_DELIVERY_ENDPOINT}}
Content-Type: application/json
sc_apikey: {{SITECORE_API_KEY}}
{
"query": "query GetItems($path: String!, $lang: String!) { item(path: $path, language: $lang) { id name path children(first: 10) { results { id name path } } } }",
"variables": {
"path": "/sitecore/content",
"lang": "en"
}
}item(path, language) — fetch a single itemitem.children, item.ancestors — navigate the treesearch(...) — full-text search across published contentsite(name) — site-specific queriessc_apikey is sufficient.Role: Everything on the CM side — content CRUD, workflow, templates, versions. One API covers it all.
Endpoint: https://xmc-{instance}.sitecorecloud.io/sitecore/api/authoring/graphql/v1
Protocol: GraphQL
Auth: OAuth Bearer (Automation credential, scope xmcloud.cm:admin)
POST https://auth.sitecorecloud.io/oauth/token
Content-Type: application/json
{
"client_id": "{{SITECORE_MANAGEMENT_CLIENT_ID}}",
"client_secret": "{{SITECORE_MANAGEMENT_CLIENT_SECRET}}",
"audience": "https://api.sitecorecloud.io",
"grant_type": "client_credentials"
}Response contains access_token, save it to {{management_access_token}}.
Postman Tests tab script to auto-save:
if (pm.response.code === 200) {
const body = pm.response.json();
pm.environment.set('management_access_token', body.access_token);
console.log('✅ Token saved. Expires in', body.expires_in, 'seconds');
}⚠ Important: The straightforward-looking mutation with $fields: [ItemFieldInput!]! as a variable will fail with:
"The specified value type of field `fields` does not match the field type."on SitecoreAI. The fix is to inline the fields array inside the mutation and parameterize only the value:
POST {{SITECORE_MANAGEMENT_ENDPOINT}}
Content-Type: application/json
Authorization: Bearer {{management_access_token}}
{
"query": "mutation UpdateItem($itemId: ID!, $value: String!) { updateItem(input: { itemId: $itemId, fields: [{ name: "__Display Name", value: $value }] }) { item { itemId name } } }",
"operationName": "UpdateItem",
"variables": {
"itemId": "{{TEST_ITEM_ID}}",
"value": "Updated from Postman"
}
}Field naming notes:
__ (double underscore): __Display Name, __Icon, __WorkflowTitle, approvalItemStatusPOST {{SITECORE_MANAGEMENT_ENDPOINT}}
Content-Type: application/json
Authorization: Bearer {{management_access_token}}
{
"query": "mutation ExecuteWorkflowCommand($item: ItemQueryInput!, $commandId: String!) { executeWorkflowCommand(input: { item: $item, commandId: $commandId }) { successful message } }",
"operationName": "ExecuteWorkflowCommand",
"variables": {
"item": { "itemId": "{{TEST_ITEM_ID}}" },
"commandId": "{{WORKFLOW_COMMAND_ID}}"
}
}Critical observation: this request uses the same endpoint URL and the same Bearer token as the updateItem above. The only difference is the mutation. This is the concrete proof that "Authoring API" and "Management API" are one API.
commandIdFirst query the item's current workflow state:
query GetWorkflow($itemId: ID!) {
item(where: { itemId: $itemId }) {
itemId
name
workflow {
workflow { workflowId name }
workflowState {
stateId
displayName
finalState
}
}
}
}The available commands for the current state are returned in the schema. Copy the relevant commandId GUID into your WORKFLOW_COMMAND_ID env var.
Content CRUD is only one corner of the surface. Other operations available:
| Category | Operations |
|---|---|
| Content CRUD | createItem, updateItem, deleteItem, moveItem, renameItem, copyItem, duplicateItem |
| Templates | createItemTemplate, updateItemTemplate, deleteItemTemplate |
| Versions | addItemVersion, deleteItemVersion |
| Workflow | executeWorkflowCommand, workflow state queries |
| Query & search | item(where: …), item.children, item.ancestors, search(…), itemTemplate(…) |
Rule of thumb: anything you can do in the Content Editor UI, you can automate through this one endpoint.
Full schema explorer: https://edge-platform.sitecorecloud.io/api/graphql/ide
Both APIs have item() and search() queries, but they're not the same:
| Authoring & Management | Edge Delivery | |
|---|---|---|
| Data source | CM database (drafts + published) | Edge index (published only) |
| Speed | Direct CM hit — slower | CDN-cached — fast |
| Use case | Admin tooling, dashboards, automation | Website, mobile app |
| Auth | OAuth Bearer | sc_apikey |
If your website calls search(), use Edge Delivery. If your admin dashboard needs to see drafts, use Authoring & Management.
Role: Manage the Edge delivery layer itself — NOT publish content, NOT create delivery keys.
Endpoint: https://edge.sitecorecloud.io/api/admin/v1
Protocol: REST (not GraphQL — the only one in the tour)
Auth: OAuth Bearer (Edge administration credential, edge.* scopes)
Note: This API manages the Edge layer infrastructure. Publishing happens CM-side (through workflow rules or manually triggered through the CM's publishing pipeline). Delivery API keys are managed by the separate Token API below.
Same OAuth pattern as Management, but use the Edge administration credentials:
POST https://auth.sitecorecloud.io/oauth/token
Content-Type: application/json
{
"client_id": "{{EDGE_ADMIN_CLIENT_ID}}",
"client_secret": "{{EDGE_ADMIN_CLIENT_SECRET}}",
"audience": "https://api.sitecorecloud.io",
"grant_type": "client_credentials"
}Decode the returned token on jwt.io and you'll see edge.* scopes, a completely different set from the Automation token.
The Admin API exposes exactly these endpoints:
| Resource | Method | Path | Purpose |
|---|---|---|---|
| Cache | DELETE | /cache | Clear the entire tenant cache (202 Accepted) |
| Content | DELETE | /content | Wipe all tenant data (danger — use carefully) |
| Settings | GET | /settings | Read cache TTLs and auto-clear flags |
| Settings | PUT | /settings | Replace all settings |
| Settings | PATCH | /settings | Modify individual settings |
| Webhooks | GET | /webhooks | List all webhooks |
| Webhooks | GET | /webhooks/{id} | Fetch one |
| Webhooks | POST | /webhooks | Create |
| Webhooks | PUT | /webhooks/{id} | Update |
| Webhooks | DELETE | /webhooks/{id} | Delete |
DELETE {{EDGE_ADMIN_ENDPOINT}}/cache
Authorization: Bearer {{edge_admin_token}}Expected response: 202 Accepted with empty body.
POST {{EDGE_ADMIN_ENDPOINT}}/webhooks
Content-Type: application/json
Authorization: Bearer {{edge_admin_token}}
{
"label": "my-webhook",
"uri": "https://webhook.site/your-uuid-here",
"executionMode": "OnEnd"
}Response contains the new webhook's id. Save it if you want to delete it later.
DELETE {{EDGE_ADMIN_ENDPOINT}}/webhooks/{id}
Authorization: Bearer {{edge_admin_token}}One of the most confusing points in Sitecore. There are two completely different webhook systems:
| Sitecore CM webhooks | Edge webhooks | |
|---|---|---|
| Where stored | Items in CM tree (/sitecore/system/Webhooks/…) | Edge platform |
| What triggers them | CM events (item saved, workflow transition) | Edge events (content published, cache cleared) |
| Managed by | Sitecore CM UI | Edge Admin REST API |
| Template | Webhook Event Handler | (Edge-native, no template) |
If you see webhooks in Content Editor under /sitecore/system/Webhooks/ but GET /webhooks on the Edge Admin API returns [], that's not a bug. They're separate systems.
Role: Programmatically manage the sc_apikey values used by the Delivery API.
Endpoint: https://edge.sitecorecloud.io/api/apikey/v1
Protocol: REST
Auth: OAuth Bearer (same Edge administration credential as Admin API, edge.tokens:* scopes are included)
| Method | Path | Purpose |
|---|---|---|
POST | /tokens | Create a new delivery API key |
GET | /tokens | List all delivery keys |
< />< code="" /> < /> | /tokens/{id} | Get one |
DELETE | /tokens/{id} | Revoke a key |
The Admin API does not create sc_apikey values, even though you'd expect it to given the edge.tokens:* scopes on the Edge admin credential. Sitecore split these into two APIs:
Both share the same OAuth credential and token. Just different base URLs.
Docs: https://doc.sitecore.com/sai/en/developers/sitecoreai/token-api.html
These are the specific traps that cost real hours during implementation:
Old blog posts and tutorials say you need separate SITECORE_CLIENT_ID and SITECORE_MANAGEMENT_CLIENT_ID env vars, implying two OAuth credentials. You don't. One Automation credential handles both. The split is historical, not technical. Save yourself the env-var noise.
__Display NameWhat Content Editor shows as "Display name" has the internal field name __Display Name (double underscore, capital N). All Sitecore system fields use the __ prefix. Passing the display label to GraphQL won't work.
ItemFieldInput type mismatch on updateItemThis mutation signature looks correct but fails with "value type does not match field type":
mutation UpdateItem($itemId: ID!, $fields: [ItemFieldInput!]!) {
updateItem(input: { itemId: $itemId, fields: $fields }) { … }
}The fix is to inline the fields array and only parameterize values:
mutation UpdateItem($itemId: ID!, $value: String!) {
updateItem(input: {
itemId: $itemId,
fields: [{ name: "__Display Name", value: $value }]
}) { item { itemId name } }
}The access_token returned from OAuth contains a tenant_id claim (a UUID) and sometimes a human-readable tenant name. Decode the token on jwt.io if you need to verify which environment the credential is bound to, as the portal's credentials list doesn't show this.
Example from a real Edge admin token:
"https://auth.sitecorecloud.io/claims/tenant_id": "820303df-29b7-4a38-182d-08dce89597b5"Cross-reference this UUID against your environment's Details page in the portal.
The Sitecore portal shows a friendly project name like "Tidal Accelerator / dev" but the actual hostname slug can include legacy names like navigatoracc468:
xmc-fishtankcon7604-navigatoracc468-dev2cbf.sitecorecloud.ioWhen debugging, trust the Environment host name on the Details tab, not the project display name. This bit me when Edge webhook responses returned tenantId: fishtankcon7604-navigatoracc468-… and I thought I was in the wrong environment. I wasn't.
Tokens expire (typically 24 hours for Edge admin, less for Automation). Hitting the OAuth endpoint on every request will rate-limit you. Cache the token and refresh with a 5-minute buffer before expiry:
if (cachedToken && cachedToken.expiresAt > Date.now()) {
return cachedToken.value;
}
// ...refresh
cachedToken = {
value: newToken,
expiresAt: Date.now() + (expires_in - 300) * 1000, // 5 min buffer
};Sitecore GraphQL expects GUIDs with braces and hyphens:
❌ 110EC58AA0F24AC48393C866D813B8D1
✅ {110EC58A-A0F2-4AC4-8393-C866D813B8D1}Strip all braces/hyphens/spaces from the input and reformat to the canonical shape before sending.
If your variables show as orange/red in the URL bar and never resolve, check the top-right of Postman. The environment dropdown must be explicitly selected. "No environment" is the default and is the silent killer of Postman debugging sessions.
One table to rule them all:
| What you want to do | Credential | Scope on token | Endpoint | Auth header |
|---|---|---|---|---|
| Read content on your site | Edge delivery key | (key, no scope) | /sitecore/api/graph/edge | sc_apikey: {key} |
| Create / edit content | Automation | xmcloud.cm:admin | /sitecore/api/authoring/graphql/v1 | Authorization: Bearer {token} |
| Advance a workflow | Automation (same) | xmcloud.cm:admin | /sitecore/api/authoring/graphql/v1 | Authorization: Bearer {token} |
| Query / search CM | Automation (same) | xmcloud.cm:admin | /sitecore/api/authoring/graphql/v1 | Authorization: Bearer {token} |
| Clear CDN cache | Edge administration | edge.caches:clear | /api/admin/v1/cache | Authorization: Bearer {token} |
| Manage webhooks | Edge administration | edge.webhooks: | /api/admin/v1/webhooks | Authorization: Bearer {token} |
| Manage Edge settings | Edge administration | edge.settings: | /api/admin/v1/settings | Authorization: Bearer {token} |
| Create delivery API key | Edge administration | edge.tokens:create | /api/apikey/v1/tokens | Authorization: Bearer {token} |
Credentials needed to cover the whole surface:
sc_apikey — a string)Three credentials, full API coverage. That's it.
Use this the first time you wire up a new environment:
client_id + client_secretclient_id + client_secretPOST /oauth/token (Automation) returns 200 and saves tokenPOST /oauth/token (Edge admin) returns 200 and saves tokentenant_id matches target environmentGET /sitecore/api/graph/edge with a simple query returns contentPOST /sitecore/api/authoring/graphql/v1 with a simple mutation succeedsDELETE /api/admin/v1/cache returns 202 AcceptedIf all pass, you have working access to every API on the platform.
SitecoreAI's API surface is more cohesive than it first appears. Once you accept three facts (Authoring and Management are one API, the credential type determines the scope, and Experience Edge has three sibling APIs sharing one admin credential) everything clicks. The confusion comes from naming inconsistencies in docs and UI labels, not from genuine architectural complexity.
The patterns presented here have been battle-tested against live SitecoreAI instances running workflow automation, content approvals across multiple sites, and bulk content updates. If you're building any programmatic integration with SitecoreAI, start with this guide, make Postman your friend, and decode every token you get your hands on.