My workspace and the API
The API follows the same model as the My workspace feature of the user interface: changes to attributes, attribute connectors, cache profiles, and policies are staged in a private workspace first, and are applied to the project only when the workspace is promoted. This applies to every caller, including M2M clients, which each have their own workspace per project.
If you migrate scripts from an earlier version, review them. Requests that used to return 201, 200, or 204 now return 202, and the change is not part of the project until you promote it.
What is staged
The following requests are staged instead of applied:
| Area | Staged requests |
|---|---|
| Attributes | POST, PATCH, and DELETE on /api/dictionary/attributes |
| Attribute connectors | POST, PATCH, and DELETE on /api/attribute-connectors |
| Cache profiles | POST, PUT, and DELETE on /api/cache-profiles |
| Policies | PATCH on /api/policy-package/<package> |
| Imports | POST on the three import endpoints of attributes, attribute connectors, and policies |
The following are not staged and are applied immediately:
- creating a policy package (
POST /api/policy-package) - composing and rolling back domains, projects, users and clients, and policy insights
Read requests always return the current project state, never your staged changes.
Staged responses
A staged request returns 202 Accepted with an X-Draft-Id response header and a body that describes what was staged:
Imports return a different 202 body, with the draftId, a summary, the items that were staged, and the failures. Read the import sections of the attributes, attribute connectors, and policies references.
{
"draftId": "5f0a8d3e-7c1b-4d62-9d0c-3a1f6c1e2b44",
"staged": [
{
"artifactType": "ATTRIBUTE",
"artifactFqn": "resource.department",
"intent": "CREATE",
"content": {
"namespace": "resource",
"name": "department",
"type": "string",
"category": "resourceCat"
},
"reservedArtifactId": "0f7b5bd2-9d5f-45f0-a9b9-8c8d0f4a6a11"
}
]
}
| Field | Description |
|---|---|
draftId | The workspace the change was staged in. It is omitted if the change cancelled out against what is already in the project and nothing is left to stage. |
staged[].artifactType | ATTRIBUTE, ATTRIBUTE_CONNECTOR, CACHE_PROFILE, or POLICY. |
staged[].artifactFqn | The item's fully qualified name, or <package>/<file> for a policy. |
staged[].intent | CREATE, UPDATE, or DELETE. |
staged[].content | The body of your request, which is not the merged result. For a PATCH, it contains only the patch. It is null for a delete. |
staged[].reservedArtifactId | The ID that the attribute will have after promotion. Only returned when an attribute is created. |
By default, a request is staged in the caller's own workspace, which is created automatically. To stage into a specific workspace, send its ID in the X-Draft-Id request header.
Staged requests are not validated. Rules such as reserved words, read-only attributes, and required fields are checked when you promote, not when you stage the change. A successful 202 does not mean the change is valid.
A request that changes an item that does not exist, in the project or in the workspace, returns 404 with an empty body.
A request that creates an item whose fully qualified name already exists in the project is not rejected. It is staged as an update of the existing item and, when you promote the workspace, it overwrites that item.
Repeated changes to the same item are merged. For example, an edit to an item you created in the workspace stays a create, a create followed by a delete cancels out, and a change that matches the project's current content is dropped.
Review your workspace
| Method | Path | Description |
|---|---|---|
GET | /api/drafts | List the workspaces you can access, with their change counts. |
GET | /api/drafts/{draftId} | Get the full contents of a workspace. |
DELETE | /api/drafts/{draftId}/artifacts/{artifactType}/{artifactFqn} | Discard a single staged item. If it was the last one, the workspace is deleted. |
DELETE | /api/drafts/{draftId} | Discard the whole workspace. |
POST | /api/drafts/{draftId}/promote | Apply the workspace to the project. |
All requests require the X-Project-Id header. You can only access your own workspace, with one exception: a Project admin can also access the workspaces of machine-to-machine clients in the project. A workspace you cannot access is reported as 404.
GET /api/drafts returns an array with the following fields for each workspace:
| Field | Description |
|---|---|
draftId | The workspace ID. |
owner | The owner's userId, and firstName, lastName, and email when known. |
changeCount | The number of staged changes. |
changesByArtifactType | The number of staged changes by artifact type. |
createdAt, updatedAt | When the workspace was created and last changed. |
GET /api/drafts/{draftId} returns only the draftId, the owner, the changeCount, and an artifacts array. Each entry of artifacts has:
| Field | Description |
|---|---|
artifactType, artifactFqn | What was changed. |
changeType | CREATED, EDITED, or DELETED. |
content | The staged content. Omitted for deleted items. |
headContent | The content in the project when the change was staged. Omitted for new items and policies. |
stagedBy | Who staged the change. |
baseVersionId | The project version the change was staged against. |
createdAt, updatedAt | When the entry was staged and last changed. |
Promote your changes
Promoting a workspace checks for conflicts with changes made in the project since you started, validates every staged change, and applies everything in a single transaction. Either all changes are applied or none are. Changes are applied in the following order: cache profiles, attributes, attribute connectors, and policies. When it succeeds, the response is 204 and the workspace is deleted.
curl -X POST "https://<authorization-hub-url>/api/drafts/<draft-id>/promote" \
-H "Authorization: Bearer <access_token>" \
-H "X-Project-Id: <project-id>" \
-H "Content-Type: application/json" \
-d '{"message": "Add department attribute"}'
The request body is optional:
| Field | Description |
|---|---|
message | A note stored with the change set. |
resolutions | How to resolve conflicts. See Resolve conflicts. |
Validation errors
If any staged change is invalid, nothing is applied and the response is 422 with the DRAFT_VALIDATION_FAILED error code. Each message names the item and the problem:
{
"status": "UNPROCESSABLE_CONTENT",
"errorCode": "DRAFT_VALIDATION_FAILED",
"errorMessage": ["ATTRIBUTE resource.permit: 'permit' is a reserved word"],
"timestamp": "2026-10-13T09:15:30.123+02:00[Europe/Athens]"
}
Fix the problem in the workspace, by staging a corrected change or discarding the item, and promote again.
Resolve conflicts
A conflict is detected per item when the project changed after you started editing it. Conflicts are checked before the changes are validated, so a promote that is rejected with 409 can still fail with 422 after you resolve the conflicts, if a staged change is invalid. The response is 409 with a list of conflicts:
{
"conflicts": [
{
"draftId": "5f0a8d3e-7c1b-4d62-9d0c-3a1f6c1e2b44",
"artifactType": "ATTRIBUTE",
"fqn": "resource.department",
"reason": "MODIFIED",
"liveArtifactVersionId": "c3b8a1f0-52c4-4e3f-8d89-2a3bd2c8e0a9",
"liveArtifactAuthor": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"liveArtifactTimestamp": "2026-10-13T08:42:10Z"
}
]
}
reason | Meaning |
|---|---|
MODIFIED | The item was changed in the project after you staged your change. |
DELETED | The item was deleted from the project. |
RENAMED | The item was renamed in the project. renamedFqn holds the new name. |
NAME_TAKEN | You staged a new item with a name that now exists in the project. |
Promote again, and add a resolutions entry for each conflict:
{
"message": "Add department attribute",
"resolutions": [
{
"artifactType": "ATTRIBUTE",
"fqn": "resource.department",
"choice": "KEEP_MINE",
"liveArtifactVersionId": "c3b8a1f0-52c4-4e3f-8d89-2a3bd2c8e0a9"
}
]
}
choice | Result |
|---|---|
KEEP_CURRENT | Discards your staged change and keeps what is in the project. |
KEEP_MINE | Applies your staged content over the project's. Requires liveArtifactVersionId from the conflict response, unless the item no longer exists in the project. |
MIX | Applies the content you provide, for example after merging both versions. Requires content, and liveArtifactVersionId unless the item no longer exists in the project. |
Attribution
When a workspace is promoted, each change is applied under the user or client that staged it, not the user that promoted the workspace. This is reflected in the activity feed and in the artifact's created/updated by. The workspace owner is recorded only as the author of the change set, which neither the UI nor the API shows. The audit log always records the caller that sent the request.
Example: update an attribute from a pipeline
# 1. Stage the change. The response is 202 with the workspace ID.
curl -X PATCH "https://<authorization-hub-url>/api/dictionary/attributes/resource.department" \
-H "Authorization: Bearer <access_token>" \
-H "X-Project-Id: <project-id>" \
-H "Content-Type: application/merge-patch+json" \
-d '{"description": "The department that owns the resource"}'
# 2. Apply the workspace to the project. The response is 204.
curl -X POST "https://<authorization-hub-url>/api/drafts/<draft-id>/promote" \
-H "Authorization: Bearer <access_token>" \
-H "X-Project-Id: <project-id>"