# SpaceRole

A *SpaceRole* is a bundle of permissions you grant to a member of a *Space*. It holds in one resource what a member can do (read, create, edit, delete, publish) to *Content Type*s, *Content*, and *Media*, whether they can execute and manage *Script*, and whether they can reach the *Space* settings. Filters that narrow the scope of a permission (to only certain *Content Type*s, only what the member created, and so on) are also defined inside the *SpaceRole*.

A *SpaceRole* you create applies to nobody on its own. You grant it to a member by putting a `Refer` to this *SpaceRole* into the `roles` of a [Space Membership](/api/reference/cma/space-membership.md). One member can hold several *SpaceRole*s at once. A *DeliveryAccessToken* is also bound to a single least-privilege *SpaceRole*, which determines the scope that token can deliver.

## Resource structure {#resource-structure}

The following is the single-read response for the *SpaceRole* "Product Read-only". Together with `sys` (system properties), it has the body properties that define permissions: `contentType`, `content`, `media`, `settings`, and `script`.

```json
{
  "sys": {
    "id": "3trmXRM3RqbgSnifyg7PLzmhWFANg9",
    "type": "SpaceRole",
    "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
    "createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
    "createdAt": "2026-06-16T09:53:16.617Z",
    "updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
    "updatedAt": "2026-06-16T09:53:16.617Z",
    "isLocked": false,
    "version": 1
  },
  "name": "Product Read-only",
  "contentType": { "All": { "Allow": [] } },
  "content": {
    "Read": {
      "Allow": [
        { "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } } }
      ]
    }
  },
  "media": { "All": { "Allow": [] } },
  "settings": [],
  "script": {}
}
```

Key properties:

- `contentType`: The permission map for *Content Type*s themselves (the schema). It defines, per action, the permission to read, create, edit, delete, and publish a *Content Type*.
- `content`: The permission map for *Content* (the content data). The example above limits the role to reading only the *Content* of one specific *Content Type*.
- `media`: The permission map for *Media* (files and images).
- `script`: The permission map for *Script* (declarative backend endpoints that your frontend calls). Sets execution (`Execute`) and management (create/read/edit/delete) per action.
- `settings`: A string array that defines access to *Space* settings. It is not a permission map: it lists action names directly. Full access is `["SETTING_ALL"]`, granting no settings access at all is `[]`, and you can also pick only the settings you need (see [`settings`](#settings-space-settings-access) below).
- `isLocked`: When `true`, this is a role Weegloo provides by default (for example, Administrator), so it cannot be edited or deleted.

## System properties (sys) {#system-properties-sys}

Every *SpaceRole* carries common system properties in the `sys` object. `space`, `createdBy`, and `updatedBy` are in the `Refer` shape (`{ "sys": { "id", "type": "Refer", "targetType" } }`).

| Property | Type | Description |
|---|---|---|
| `id` | string | Unique resource identifier. |
| `type` | string | Resource kind. For a *SpaceRole* this is always `"SpaceRole"`. |
| `space` | Refer&lt;Space&gt; | The *Space* this *SpaceRole* belongs to. |
| `createdBy` | Refer&lt;User&gt; | The user who created it. |
| `createdAt` | string (date-time) | Creation time. |
| `updatedBy` | Refer&lt;User&gt; | The user who last updated it. |
| `updatedAt` | string (date-time) | Last update time. |
| `isLocked` | boolean | When `true`, this is a default-provided role and cannot be edited or deleted. Roles you create yourself are `false`. |
| `version` | integer (≥1) | Resource version. It increases by 1 with every change. |

A *SpaceRole* is a settings resource with no publishing concept. So unlike *Content* and *Media*, its `sys` has no `publish`, `archive`, or `status`, only `version`. The `version` increases each time you update the *SpaceRole*.

## Permission maps: contentType, content, media {#permission-maps-contenttype-content-media}

`contentType`, `content`, and `media` are each a **map keyed by action**. The actions you can use are `Create`, `Read`, `Edit`, `Delete`, `Publish`, `Unpublish`, `Archive`, and `Unarchive`, plus `All`, which refers to every action at once. **There is no action called `Save`.** The permission to modify is `Edit`, and `Save` is the name of an event a [Webhook](/api/reference/cma/webhook.md#topics) subscribes to. The value of each action is an object holding `Allow` and `Deny` arrays of rules.

```json
"content": {
  "Read":   { "Allow": [ /* rule */ ], "Deny": [ /* rule */ ] },
  "Edit":   { "Allow": [ /* rule */ ] }
}
```

Each rule object has optional filters that narrow the permission's scope.

- `self`: Limits the target the rule applies to the **resource itself**, one single resource. You put in a `Refer` that points to that resource. In the `contentType` map it means one specific *Content Type*; in the `script` map, one specific *Script*.
- `contentType`: Limits to the *Content Type* the *Content* **belongs to**. You put in a `Refer` that points to a *Content Type*.
- `createdBy`: Limits to only resources created by a specific user. Put a specific user id in `sys.id` to limit to what that person created, or the reserved value `:self` to limit to "only what the user making the current call created".
- `tag`: Limits to only resources carrying a specific *Tag*.

**Which filter carries meaning in which permission map is fixed.** If you put in a filter that does not fit, saving the role is rejected. Were it quietly ignored, a rule you believed you had narrowed would become a full allow.

| Permission map | Filters you can use | Filters that make the save fail |
|---|---|---|
| `contentType` | `self` (that *Content Type* itself), `createdBy` | `contentType` |
| `content` | `contentType` (the kind the *Content* belongs to), `createdBy`, `tag` | `self` |
| `media` | `createdBy`, `tag` | `self` |
| `script` | `self` (that *Script* itself), `createdBy` | `contentType`, `tag` |

- **In the `contentType` map you name the target with `self`, not with `contentType`.** What you narrow there is the *Content Type* itself. The `contentType` filter means "the kind this resource refers to", so it fits the `content` map only.
- A filter that narrows along an axis the resource does not have (`tag` on a *Content Type*, `contentType` on *Media*) is not blocked at save time, but the rule is not evaluated the way you intended. Do not use it.

> **To evaluate a `createdBy` filter (including `:self`) on CDA (delivery), the target *Content Type*'s `publishWithAuthor` must be `true`.** CDA evaluates this filter against the `sys.createdBy` of the publish snapshot, so if `publishWithAuthor` is left at its default `false` the snapshot has no author: an `Allow` rule matches nothing, and a `Deny` rule filters out no one. CMA (management) evaluates against the `sys.createdBy` of the draft and is therefore independent of this setting. Because `publishWithAuthor` is not retroactive, turn it on before publishing content, and republish any *Content* that has already been published. See the `publishWithAuthor` description in [Content Type](/api/reference/cma/content-type.md).

**An empty `Allow` array `[]` means the action is allowed across the entire kind.** Because the filter is empty there is nothing to filter out, so the action is open to all resources.

**An empty `Deny` array `[]` works the other way around.** It does not mean "nothing is denied": it **denies the entire kind** and blocks that action completely. It stays blocked even if you write an `Allow` alongside it. Leaving `[]` to mean "there is nothing to deny" does the exact opposite, so when you want to deny nothing, leave the `Deny` key out entirely.

### Example 1: Administrator (full permissions, provided by default) {#example-1-administrator-full-permissions-provided-by-default}

The Administrator role gives an empty `Allow` to the `All` action of `contentType`, `content`, `media`, and `script` to allow everything, and gives `["SETTING_ALL"]` to `settings` to reach all *Space* settings. Because Weegloo provides this role by default, its `sys.isLocked` is `true` and it cannot be edited or deleted.

```json
{
  "sys": {
    "id": "3trmXRM3RqbgSnifyg7PAlm4FWTPQ8",
    "type": "SpaceRole",
    "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
    "createdBy": { "sys": { "id": "_", "type": "Refer", "targetType": "User" } },
    "createdAt": "2026-06-14T14:56:04.737Z",
    "updatedBy": { "sys": { "id": "_", "type": "Refer", "targetType": "User" } },
    "updatedAt": "2026-06-14T14:56:04.737Z",
    "isLocked": true,
    "version": 1
  },
  "name": "Administrator",
  "description": "Members of this role have full access to everything in this space.",
  "contentType": { "All": { "Allow": [] } },
  "content": { "All": { "Allow": [] } },
  "media": { "All": { "Allow": [] } },
  "settings": ["SETTING_ALL"],
  "script": { "All": { "Allow": [] } }
}
```

### Example 2: Read-only (one specific Content Type) {#example-2-read-only-one-specific-content-type}

This is an example of a least-privilege role you create yourself. It puts a rule only on the `Read` action of `content`, and limits that rule to one specific *Content Type* with the rule's `contentType` filter. The *Content Type* itself and *Media* are left open with `All` and an empty `Allow`, but for the content data only reading that one kind is possible. Because `settings` is `[]`, it cannot reach *Space* settings. Bind this role to a *DeliveryAccessToken* and the delivery token will read only that scope. The JSON of this role is the same as "Product Read-only" in [Resource structure](#resource-structure) above.

### `settings` (Space settings access) {#settings-space-settings-access}

`settings` is not a permission map but a string array. It holds access to *Space* settings, and it has no `Allow`/`Deny` and no filters. The actions you put in the array are allowed, and the actions you leave out are not.

Full access is `["SETTING_ALL"]`, and you leave it `[]` to grant no access at all. When you need something in between, pick the actions below.

| Action | What it gives access to |
|---|---|
| `SETTING_GENERAL` | The *Space* itself (name, description, and so on) |
| `SETTING_LOCALE` | *Locale* |
| `SETTING_WEBHOOK` | *Webhook* (including call history and status) |
| `SETTING_APP` | *Market App* installation |
| `SETTING_TAG` | *Tag* |
| `SETTING_DELIVERY_ACCESS_TOKEN` | *Delivery Access Token* |
| `SETTING_SPACE_ACCESS_TOKEN` | *Space Access Token* |
| `SETTING_USER` | *Space Membership* (member assignment) |
| `SETTING_ROLE` | *SpaceRole* |
| `SETTING_WEB_HOSTING` | *Web Hosting* and custom domains |
| `SETTING_SERVICE_LOGIN` | *ServiceLogin*, *ServiceUser*, *ServiceUserRole* |
| `SETTING_EMAIL_ACCOUNT` | The mail sending account |
| `SETTING_MONITORING` | Reading usage and metrics |
| `SETTING_SCHEDULER` | *Scheduler* and its execution records |
| `SETTING_ALL` | All of the above |

The two kinds of token have separate actions. If you grant only `SETTING_DELIVERY_ACCESS_TOKEN`, the role can issue a read-only *Delivery Access Token* but cannot issue a *Space Access Token*, which can write as well.

The actions in `settings` are called only with a console login session or a *Personal Access Token*. A *Space Access Token*, a *Delivery Access Token*, or a *ServiceUser* token cannot call the APIs in this list, no matter which actions the role holds.

> The action list of the permission maps (`contentType`, `content`, `media`, `script`), the filter keys (`self`, `contentType`, `createdBy`, `tag`), the meaning of `:self`, and which filter is valid in which map all follow the [Permission maps: contentType, content, media](#permission-maps-contenttype-content-media) section above.

### script (Script permissions) {#script-permission}

`script` is the permission map for *Script* (declarative backend endpoints that your frontend calls). Its structure is the same as `content` and `media`: actions as keys, with `Allow`/`Deny` rule arrays as values. The actions it uses are:

- `Create`, `Read`, `Edit`, `Delete`: Create, read, update, and delete a *Script* resource.
- `Execute`: Run a *Script* (call `/execute`). This action is unique to *Script*.
- `All`: The umbrella action that includes all of the above.

Because a *Script* is not a resource you publish, publish actions such as `Publish`/`Unpublish` are not used. The rule filters you can use are **`self` and `createdBy`**.

- `self`: Limits to **a single specific** *Script*. You put in a `Refer` that points to that *Script* (its `targetType` is `Script`).
- `createdBy`: Limits by who created it (use `:self` for "only the *Script*s the caller created").

`contentType` and `tag` are axes that do not attach to *Script*, so putting them in makes saving the role fail.

For example, to let someone execute any *Script* but read only the ones they created:

```json
"script": {
  "Execute": { "Allow": [] },
  "Read": {
    "Allow": [
      { "createdBy": { "sys": { "id": ":self", "type": "Refer", "targetType": "User" } } }
    ]
  }
}
```

**Narrowing with `self` produces the least privilege: the right to execute one *Script* and nothing else.** When you give execute permission to an outside system such as a payment provider, this is how you open the one entry point that system will call and leave everything else closed.

```json
"script": {
  "Execute": {
    "Allow": [
      { "self": { "sys": { "id": "3trmXRMZcTAjDnphewjj1AaxYcaxlK", "type": "Refer", "targetType": "Script" } } }
    ]
  }
}
```

Bind this role to a [Space Access Token](/api/reference/cma/space-access-token.md) and that token executes only the one *Script* you named. Why you narrow it to a single execute permission, and the fact that running a *Script* borrows the author's permissions, are covered in [Script execution semantics, limits, and security](/api/reference/script/execution-and-limits.md#execution-identity-and-authorization).

This `script` permission decides "can you execute and manage the *Script* resource." Separately, when you **author** a *Script* (create or edit it), at save time the author must actually hold the *Content*/*Media* action permissions that the *Script*'s statements operate on; otherwise the save is rejected (see [Script errors](/api/reference/script/execution-and-limits.md#errors)). See [Script execution semantics, limits, and security](/api/reference/script/execution-and-limits.md#security-model) for details.

## Errors {#errors}

These are the codes you meet when working with a *SpaceRole*. For codes that are common to every resource, see [common errors](/api/reference/common/errors.md).

| Code | Condition |
|---|---|
| `WGL400020` | The caller tried to save a *SpaceRole* whose rule carried a filter that has no meaning in that permission map. |

## API {#api}

The base URL for all endpoints below is `https://cma.weegloo.com/v1`, and a Bearer token that authenticates against CMA is required in the `Authorization` header. Role updates (`PUT`, `PATCH`) must also send the `X-Weegloo-Version` header (the current resource's `sys.version`) for optimistic concurrency control. Create and delete do not have this header. Default-provided roles whose `sys.isLocked` is `true` cannot be edited or deleted.

```api-endpoint
{
  "title": "List SpaceRoles",
  "method": "GET",
  "path": "/spaces/{spaceId}/roles",
  "description": "Reads the SpaceRoles of one Space, page by page. Default-provided roles (where isLocked is true) come along too.",
  "responseStatus": 200,
  "baseUrl": "https://cma.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true }
  },
  "queryParameterSchema": {
    "limit": { "type": "integer", "description": "Number of items to return per page (1-100)", "default": 15 },
    "skip": { "type": "integer", "description": "Number of items to skip", "default": 0 },
    "next": { "type": "string", "description": "Next-page cursor (the value from links.next in the previous response)" },
    "prev": { "type": "string", "description": "Previous-page cursor (the value from links.prev in the previous response)" },
    "order": { "type": "string", "description": "Sort criteria. Multiple sorts separated by commas (e.g. sys.createdAt,sys.id)", "default": "sys.createdAt,sys.id" },
    "select": { "type": "string", "description": "Fields to include (sys.id,sys.createdAt) or exclude (-sys.id). Do not mix inclusion and exclusion." },
    "include": { "type": "integer", "description": "Related-resource inclusion level. 0=default, 1=related resources, 2=nested relations, 3=full", "default": 0 }
  },
  "additionalQueryParams": true,
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" }
  },
  "responseExample": {
    "sys": { "type": "TotalPageResponse" },
    "limit": 15,
    "totalCount": 2,
    "items": [
      {
        "sys": {
          "id": "3trmXRM3RqbgSnifyg7PAlm4FWTPQ8",
          "type": "SpaceRole",
          "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
          "createdBy": { "sys": { "id": "_", "type": "Refer", "targetType": "User" } },
          "createdAt": "2026-06-14T14:56:04.737Z",
          "updatedBy": { "sys": { "id": "_", "type": "Refer", "targetType": "User" } },
          "updatedAt": "2026-06-14T14:56:04.737Z",
          "isLocked": true,
          "version": 1
        },
        "name": "Administrator",
        "description": "Members of this role have full access to everything in this space.",
        "contentType": { "All": { "Allow": [] } },
        "content": { "All": { "Allow": [] } },
        "media": { "All": { "Allow": [] } },
        "settings": ["SETTING_ALL"],
        "script": { "All": { "Allow": [] } }
      },
      {
        "sys": {
          "id": "3trmXRM3RqbgSnifyg7PLzmhWFANg9",
          "type": "SpaceRole",
          "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
          "createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
          "createdAt": "2026-06-16T09:53:16.617Z",
          "updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
          "updatedAt": "2026-06-16T09:53:16.617Z",
          "isLocked": false,
          "version": 1
        },
        "name": "Product Read-only",
        "contentType": { "All": { "Allow": [] } },
        "content": {
          "Read": {
            "Allow": [
              { "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } } }
            ]
          }
        },
        "media": { "All": { "Allow": [] } },
        "settings": [],
        "script": {}
      }
    ],
    "links": { "self": "/v1/spaces/tcq4V2Xb/roles" }
  }
}
```

```api-endpoint
{
  "title": "Read a single SpaceRole",
  "method": "GET",
  "path": "/spaces/{spaceId}/roles/{roleId}",
  "description": "Reads one SpaceRole by sys.id.",
  "responseStatus": 200,
  "baseUrl": "https://cma.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true },
    "roleId": { "type": "string", "description": "The sys.id of the SpaceRole", "required": true }
  },
  "queryParameterSchema": {
    "include": { "type": "integer", "description": "Related-resource inclusion level. 0=default, 1=related resources, 2=nested relations, 3=full", "default": 0 }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" }
  },
  "responseExample": {
    "sys": {
      "id": "3trmXRM3RqbgSnifyg7PLzmhWFANg9",
      "type": "SpaceRole",
      "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
      "createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
      "createdAt": "2026-06-16T09:53:16.617Z",
      "updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
      "updatedAt": "2026-06-16T09:53:16.617Z",
      "isLocked": false,
      "version": 1
    },
    "name": "Product Read-only",
    "contentType": { "All": { "Allow": [] } },
    "content": {
      "Read": {
        "Allow": [
          { "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } } }
        ]
      }
    },
    "media": { "All": { "Allow": [] } },
    "settings": [],
    "script": {}
  }
}
```

```api-endpoint
{
  "title": "Create a SpaceRole",
  "method": "POST",
  "path": "/spaces/{spaceId}/roles",
  "description": "Creates a new SpaceRole in one Space. The body holds name, the contentType/content/media permission maps, and the settings array. Bind the sys.id in the response to a Space Membership's roles or to a DeliveryAccessToken to apply it.",
  "responseStatus": 201,
  "baseUrl": "https://cma.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" }
  },
  "requestBodySchema": {
    "type": "object",
    "required": ["name", "contentType", "content", "media", "settings"],
    "properties": {
      "name": { "type": "string", "description": "Role name" },
      "description": { "type": "string", "description": "Role description (optional)" },
      "contentType": { "type": "object", "description": "Permission map for Content Types. Keyed by action (Create/Read/Edit/Delete/Publish/Unpublish/Archive/Unarchive/All), with { Allow, Deny } rule arrays as values. An empty Allow array allows everything. Rule filters allow only self (that Content Type itself)/createdBy." },
      "content": { "type": "object", "description": "Permission map for Content. Rules narrow scope with contentType/createdBy/tag filters (self is rejected)." },
      "media": { "type": "object", "description": "Permission map for Media. Rule filters allow only createdBy/tag (self is rejected)." },
      "script": { "type": "object", "description": "The permission map for Script. Actions are Create/Read/Edit/Delete/Execute/All. Execute is the Script execution permission. Rule filters allow only self (one specific Script)/createdBy, and contentType/tag are rejected. Optional (if omitted, no script permission)." },
      "settings": { "type": "array", "description": "Access to Space settings. Full access is [\"SETTING_ALL\"]; none is []. Individual actions can be specified.", "items": { "type": "string", "enum": ["SETTING_ALL", "SETTING_GENERAL", "SETTING_LOCALE", "SETTING_WEBHOOK", "SETTING_APP", "SETTING_TAG", "SETTING_DELIVERY_ACCESS_TOKEN", "SETTING_SPACE_ACCESS_TOKEN", "SETTING_USER", "SETTING_ROLE", "SETTING_WEB_HOSTING", "SETTING_SERVICE_LOGIN", "SETTING_EMAIL_ACCOUNT", "SETTING_MONITORING", "SETTING_SCHEDULER"] } }
    },
    "example": {
      "name": "Product Editor",
      "description": "Role that can edit only Product content",
      "contentType": { "All": { "Allow": [] } },
      "content": {
        "Edit": {
          "Allow": [
            { "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } } }
          ]
        }
      },
      "media": { "All": { "Allow": [] } },
      "settings": [],
      "script": {}
    }
  },
  "responseExample": {
    "sys": {
      "id": "3trmXRM3RqbgSnifyg7PLunKOM9OrZ",
      "type": "SpaceRole",
      "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
      "createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
      "createdAt": "2026-06-18T11:21:08.059Z",
      "updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
      "updatedAt": "2026-06-18T11:21:08.059Z",
      "isLocked": false,
      "version": 1
    },
    "name": "Product Editor",
    "description": "Role that can edit only Product content",
    "contentType": { "All": { "Allow": [] } },
    "content": {
      "Edit": {
        "Allow": [
          { "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } } }
        ]
      }
    },
    "media": { "All": { "Allow": [] } },
    "settings": [],
    "script": {}
  }
}
```

```api-endpoint
{
  "title": "Update a SpaceRole",
  "method": "PUT",
  "path": "/spaces/{spaceId}/roles/{roleId}",
  "description": "Replaces the whole SpaceRole. The body holds name and the full permission maps. The example below sets createdBy to :self in the content Edit rule to narrow it to 'edit only the Product Content the caller created'. :self limits to only what the user making the current call created. You must carry the current sys.version in the X-Weegloo-Version header.",
  "responseStatus": 200,
  "baseUrl": "https://cma.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true },
    "roleId": { "type": "string", "description": "The sys.id of the SpaceRole", "required": true }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" },
    "X-Weegloo-Version": { "type": "integer", "description": "The current resource's sys.version (optimistic concurrency control)" }
  },
  "requestBodySchema": {
    "type": "object",
    "required": ["name", "contentType", "content", "media", "settings"],
    "properties": {
      "name": { "type": "string", "description": "Role name" },
      "description": { "type": "string", "description": "Role description (optional)" },
      "contentType": { "type": "object", "description": "Permission map for Content Types. Rule filters allow only self (that Content Type itself)/createdBy." },
      "content": { "type": "object", "description": "Permission map for Content. Put :self in createdBy.sys.id to limit to only what the caller created. Rule filters are contentType/createdBy/tag." },
      "media": { "type": "object", "description": "Permission map for Media. Rule filters are createdBy/tag." },
      "script": { "type": "object", "description": "The permission map for Script. Actions are Create/Read/Edit/Delete/Execute/All. Execute is the Script execution permission. Rule filters are self (one specific Script)/createdBy. Optional." },
      "settings": { "type": "array", "description": "Access to Space settings.", "items": { "type": "string" } }
    },
    "example": {
      "name": "My Product Editor",
      "description": "Edit only the products you created",
      "contentType": { "All": { "Allow": [] } },
      "content": {
        "Edit": {
          "Allow": [
            {
              "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } },
              "createdBy": { "sys": { "id": ":self", "type": "Refer", "targetType": "User" } }
            }
          ]
        }
      },
      "media": { "All": { "Allow": [] } },
      "settings": [],
      "script": {}
    }
  },
  "responseExample": {
    "sys": {
      "id": "3trmXRM3RqbgSnifyg7PLunKOM9OrZ",
      "type": "SpaceRole",
      "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
      "createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
      "createdAt": "2026-06-18T11:21:08.059Z",
      "updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
      "updatedAt": "2026-06-18T11:21:30.000Z",
      "isLocked": false,
      "version": 2
    },
    "name": "My Product Editor",
    "description": "Edit only the products you created",
    "contentType": { "All": { "Allow": [] } },
    "content": {
      "Edit": {
        "Allow": [
          {
            "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } },
            "createdBy": { "sys": { "id": ":self", "type": "Refer", "targetType": "User" } }
          }
        ]
      }
    },
    "media": { "All": { "Allow": [] } },
    "settings": [],
    "script": {}
  }
}
```

```api-endpoint
{
  "title": "Partially update a SpaceRole (JSON Patch)",
  "method": "PATCH",
  "path": "/spaces/{spaceId}/roles/{roleId}",
  "description": "Updates only part of a SpaceRole with RFC 6902 JSON Patch. The request Content-Type header must be application/json-patch+json. You must carry the current sys.version in the X-Weegloo-Version header.",
  "responseStatus": 200,
  "baseUrl": "https://cma.weegloo.com/v1",
  "requestContentType": "application/json-patch+json",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true },
    "roleId": { "type": "string", "description": "The sys.id of the SpaceRole", "required": true }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" },
    "Content-Type": { "type": "string", "description": "application/json-patch+json (RFC 6902 JSON Patch)" },
    "X-Weegloo-Version": { "type": "integer", "description": "The current resource's sys.version (optimistic concurrency control)" }
  },
  "requestBodySchema": {
    "type": "array",
    "description": "An array of RFC 6902 JSON Patch operations (op / path / value / from). path is an RFC 6901 JSON Pointer.",
    "items": {
      "type": "object",
      "required": ["op", "path"],
      "properties": {
        "op": { "type": "string", "enum": ["add", "remove", "replace", "move", "copy", "test"], "description": "Operation kind" },
        "path": { "type": "string", "description": "Target location (JSON Pointer). Example: /description" },
        "value": { "description": "The value used by add/replace/test" },
        "from": { "type": "string", "description": "The source location for move/copy" }
      }
    },
    "example": [
      { "op": "replace", "path": "/description", "value": "Edit only products you authored" }
    ]
  },
  "responseExample": {
    "sys": {
      "id": "3trmXRM3RqbgSnifyg7PLunKOM9OrZ",
      "type": "SpaceRole",
      "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
      "createdBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
      "createdAt": "2026-06-18T11:21:08.059Z",
      "updatedBy": { "sys": { "id": "3p4tcFbQRwz503VXdtHXNI5dZH5TVB", "type": "Refer", "targetType": "User" } },
      "updatedAt": "2026-06-18T11:21:45.000Z",
      "isLocked": false,
      "version": 3
    },
    "name": "My Product Editor",
    "description": "Edit only products you authored",
    "contentType": { "All": { "Allow": [] } },
    "content": {
      "Edit": {
        "Allow": [
          {
            "contentType": { "sys": { "id": "3trmXRM3RqbgSnifyg7PAmlxvX4fGY", "type": "Refer", "targetType": "ContentType" } },
            "createdBy": { "sys": { "id": ":self", "type": "Refer", "targetType": "User" } }
          }
        ]
      }
    },
    "media": { "All": { "Allow": [] } },
    "settings": [],
    "script": {}
  }
}
```

```api-endpoint
{
  "title": "Delete a SpaceRole",
  "method": "DELETE",
  "path": "/spaces/{spaceId}/roles/{roleId}",
  "description": "Deletes a SpaceRole. Default-provided roles whose sys.isLocked is true cannot be deleted. On success it responds with 204 No Content and no response body.",
  "responseStatus": 204,
  "baseUrl": "https://cma.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true },
    "roleId": { "type": "string", "description": "The sys.id of the SpaceRole", "required": true }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" }
  }
}
```

## Related documents {#related-documents}

- [Space Membership](/api/reference/cma/space-membership.md): Bind a *SpaceRole* into a member's `roles`.
- [Delivery Access Token](/api/reference/cma/delivery-access-token.md): The delivery token bound to a least-privilege *SpaceRole*.
- [Content Type](/api/reference/cma/content-type.md): The *Content Type* the permission rules point to.
