| name | fabric-rest-api |
| description | Use for Microsoft Fabric REST API patterns: listing and paginating workspaces/items with continuationToken/continuationUri, calling /v1/workspaces/{wsId}/items, handling long-running operations (202 Accepted, Location header, polling /v1/operations/{id}, Retry-After, /result), the runtime item ID vs .platform logicalId distinction (PowerBIEntityNotFound root cause), the 201-or-202 create pattern, jobType values for /jobs/instances (RunNotebook, Pipeline, SparkJob, Refresh — NOT DefaultJob), the `definition` envelope and `?updateMetadata=true` `.platform` flag, job scheduling (Daily/Weekly/Monthly), 429 rate limiting with Retry-After, capacity assignment, and the GA `sensitivityLabel` field on List/Get/Update Item responses (GUID only, not settable via PATCH). |
Fabric REST API patterns
Base URL: https://api.fabric.microsoft.com/v1
Finding Workspaces and Items
- List workspaces:
GET /v1/workspaces → paginate with continuationToken
- Find by name: iterate results until
displayName matches
- List items in workspace:
GET /v1/workspaces/{wsId}/items?type={ItemType}
- Type-specific endpoints return extra
properties (connection strings, etc.):
GET /v1/workspaces/{wsId}/{lakehouses|warehouses|notebooks|semanticModels|...}
- Cross-workspace discovery (no
wsId in path): POST /v1/catalog/search with { "search": "Sales Revenue", "pageSize": 50, "filter": "Type eq 'Lakehouse'" } → permission-trimmed items (each with id GUID + workspaceId) across your whole accessible estate, by catalog metadata (name/description/workspace name). OneLake Catalog Search API (Preview, March 2026); same capability as the fab find CLI verb (fabric-cli skill) and the Fabric Core MCP server's search_catalog tool.
Sensitivity Labels on Item Responses
As of March 2026 GA, List Items / Get Item / Update Item responses include a sensitivityLabel property on the Item object when the item has a Purview information-protection label applied:
{
"id": "34fa05fc-e7ba-435a-b1ab-63534b6aa4f9",
"displayName": "PDF_Env",
"type": "Environment",
"workspaceId": "2ae4b0b9-895b-4676-bfcd-125b1f20e34d",
"sensitivityLabel": { "sensitivityLabelId": "4922deb9-fe99-4f4f-971c-9bdf556ec6a9" }
}
Field name gotcha — spec vs runtime drift. The MS Learn Item definition page documents this inner field as id, but the live API returns sensitivityLabelId. Verified across 233 labeled items in 7 workspaces (May 2026) on both GET /v1/workspaces/{wsId}/items and GET /v1/workspaces/{wsId}/items/{itemId} — 233/233 use sensitivityLabelId. Trust the runtime, not the schema page.
The sensitivityLabel object carries only the label GUID — there is no displayName / name on the response. Resolving the GUID to a human-readable label name requires a separate call (Microsoft Graph /security/informationProtection/sensitivityLabels or Purview). The sensitivityLabel field is omitted entirely on unlabeled items.
Read-only on these endpoints. The Update Item PATCH body schema (UpdateItemRequest) accepts only displayName and description — it does NOT accept a sensitivityLabel field. To apply, change, or remove labels programmatically, call the admin APIs POST /v1/admin/labels/bulkSetLabels / bulkRemoveLabels (require Tenant.ReadWrite.All + Fabric admin role; ≤ 25 req/hour, ≤ 2000 items/request).
Item IDs: Runtime vs logicalId
Every Fabric item has two GUIDs, and they are NOT interchangeable. Using the wrong one is a leading cause of PowerBIEntityNotFound / EntityNotFound errors when referencing items by ID from a pipeline, notebook parameter, REST call, or Variable Library variable.
| Identifier | Source | Resolved by | Use for |
|---|
| Runtime item ID | Fabric portal URL (…/items/{guid}); GET /v1/workspaces/{wsId}/items response id | The Fabric engine at execution time | Pipeline activity notebookId / pipelineId, Variable Library values consumed at runtime, REST /items/{id} calls, notebookutils.runtime.context lookups |
| logicalId | .platform file → config.logicalId | Git integration / source-control tooling | .platform payloads, PBIP + pbir-cli + fab import source-control operations |
The two values can look visually similar — Git integration sometimes derives one as a byte-swapped permutation of the other (segments reshuffled) — but Fabric will NOT silently fall back from one to the other at runtime.
Rule of thumb: if the value ends up in a payload the Fabric engine reads (pipeline definition, Variable Library value, REST body), use the runtime item ID. If it ends up in a file the Git integration layer reads (.platform, PBIP manifest), use the logicalId.
To fetch the runtime ID:
- Portal: open the item, copy the trailing GUID from the URL
- REST:
GET /v1/workspaces/{wsId}/items → find by displayName, return id
fab CLI: fab get "Workspace.Workspace/Item.ItemType" -q id
Variable Library specifically: variable string values are passed verbatim to consumers — they are NOT resolved against .platform logicalIds. Always store the runtime item ID.
Long-Running Operations (LRO)
Many mutating calls return 202 Accepted with Location and x-ms-operation-id headers.
- Poll:
GET /v1/operations/{operationId} → status: Running|Succeeded|Failed
- Get result:
GET /v1/operations/{operationId}/result (after Succeeded)
- Honor
Retry-After header. Use exponential backoff if absent.
Item creation is 201-OR-202, not "always sync" or "always LRO" — the same endpoint can return either depending on current provisioning load. Always branch on status code; never assume sync. A function that only inspects the body on 2xx will silently return before the item is queryable whenever Fabric picks the LRO path, racing any immediately-downstream call that expects the new item to exist.
Canonical create_* pattern for Fabric item creation:
def create_item(access_token: str, item_name: str, ...) -> str:
"""Return the newly-created item's GUID. Handles 201 and 202."""
workspace_id = notebookutils.runtime.context["currentWorkspaceId"]
endpoint = f"https://api.fabric.microsoft.com/v1/workspaces/{workspace_id}/<items_path>"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json",
}
body = {"displayName": item_name}
response = requests.post(endpoint, headers=headers, json=body)
if response.status_code == 201:
item_id = response.json()["id"]
elif response.status_code == 202:
result_response = poll_lro(response, headers, return_result=True)
item_id = result_response.json()["id"]
else:
response.raise_for_status()
return item_id
The poll_lro helper honors Retry-After, polls Location until the operation reaches Succeeded, and (with return_result=True) fetches /result to return the actual created-item body.
Definition APIs
Item types with content (Notebook, SemanticModel, Report, DataPipeline) accept a definition object containing format, parts, and base64-encoded payloads.
PATCH /v1/workspaces/{wsId}/items/{itemId}/definition[?updateMetadata=true]
?updateMetadata=true controls whether .platform is honored. Without it, any .platform part in definition.parts is silently ignored — displayName/description won't update.
- Conversely, setting
?updateMetadata=true requires a .platform part. The flag without .platform returns 400.
- For content-only updates (typical), omit the flag.
- Notebook-specific alternative:
POST /v1/workspaces/{wsId}/notebooks/{id}/updateDefinition — same body shape.
getDefinition is a POST with empty body ('{}') — bare POST returns HTTP 411 Length Required. Result is fetched via the LRO's {Location}/result URL (note the /result suffix).
- Per-item-type specifics live in
fabric-tmdl-api (semantic models), fabric-spark (notebooks, SparkJobDefinition, Environment, Lakehouse shortcuts), fabric-eventhouse (Eventhouse, KQLDatabase), fabric-variable-library (VariableLibrary), and pbir-cli/pbir-report-workflow (Report).
Support matrix
| Item Type | Formats | Main parts |
|---|
| Notebook | ipynb (default), FabricGitSource | notebook-content.ipynb or .py/.sql/.scala/.r |
| DataPipeline | (default) | pipeline-content.json |
| SemanticModel | TMSL, TMDL (prefer) | definition/database.tmdl, model.tmdl, tables/*.tmdl, definition.pbism |
| Report | PBIR-Legacy, PBIR (prefer) | definition/report.json, version.json, pages/*, definition.pbir |
| Lakehouse | LakehouseDefinitionV1 | lakehouse.metadata.json (+ optional shortcuts.metadata.json) |
| SparkJobDefinition | SparkJobDefinitionV1, SparkJobDefinitionV2 | SparkJobDefinitionV1.json (+ Main/, Libs/ for V2) |
| Environment | (default — set null) | Libraries/PublicLibraries/environment.yml, Setting/Sparkcompute.yml |
| VariableLibrary | omit format entirely | variables.json, settings.json, valueSets/<name>.json |
| Eventhouse | JSON | EventhouseProperties.json |
| KQLDatabase | JSON | DatabaseProperties.json (+ optional DatabaseSchema.kql) |
| Other (KQLDashboard, CopyJob, Dataflow, Eventstream, MirroredDatabase, GraphQLApi, etc.) | varies | see MS schema index |
definition.pbir byConnection only: Fabric REST API supports only byConnection semantic-model references in PBIR. The byPath form (used locally with pbir-cli) is not accepted by the Fabric REST endpoints — switch to byConnection before deploying.
Job Execution
POST /v1/workspaces/{wsId}/items/{itemId}/jobs/instances?jobType={jobType}
| Item Type | jobType |
|---|
| Notebook | RunNotebook |
| DataPipeline | Pipeline |
| SparkJobDefinition | SparkJob |
| SemanticModel | Refresh |
Gotcha: DefaultJob does NOT work for most item types. Use the type-specific value above.
Job Scheduling
POST /v1/workspaces/{wsId}/items/{itemId}/jobs/{jobType}/schedules
URL path is /jobs/{jobType}/schedules — NOT /jobs/instances/schedules. Body:
{
"enabled": true,
"configuration": {
"startDateTime": "2026-01-01T06:00:00.000Z",
"endDateTime": "2027-01-01T06:00:00.000Z",
"type": "Daily",
"interval": 1,
"localTimeZoneId": "UTC",
"times": ["06:00"]
}
}
enabled, configuration.startDateTime, configuration.endDateTime, and configuration.type are all required. Omitting endDateTime returns 400. type ∈ Daily | Weekly | Monthly; Weekly also requires weekDays (array of day names). List with GET .../schedules; delete with DELETE .../schedules/{scheduleId}.
Rate Limiting
429 Too Many Requests includes a Retry-After header (seconds). Honor it; never tight-loop. Use exponential backoff with jitter when Retry-After is absent.
| Category | Approximate limit |
|---|
| Admin APIs | 200 req/hour per principal per tenant |
| OneLake (ADLS) | Standard Azure Storage throttling, per workspace |
| Warehouse TDS | ~128 concurrent connections (varies by SKU) |
Watch x-ms-ratelimit-remaining-* response headers to back off before hitting the limit.
Capacity
GET /v1/capacities — list available capacities. Filter state == "Active".
POST /v1/workspaces/{wsId}/assignToCapacity with { "capacityId": "..." } — assigns workspace to capacity.
- Lakehouse, Warehouse, Notebook execution, and Spark Job Definitions all require workspace capacity. Without it, item creation returns
FeatureNotAvailable.
- After assignment, verify
GET /v1/workspaces/{wsId} shows capacityAssignmentProgress: "Completed" before creating capacity-dependent items.
Pagination
All list APIs use continuation-token pagination. Keep calling with ?continuationToken={value} until the token is null. The response also includes continuationUri — the fully-formed next-page URL — which you can call directly without re-constructing the query string. The token itself is opaque; never modify it.
Reference