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 Types, 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 Types, 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. One member can hold several SpaceRoles at once. A DeliveryAccessToken is also bound to a single least-privilege SpaceRole, which determines the scope that token can deliver.
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.
{
"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 Types 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 (seesettingsbelow).isLocked: Whentrue, this is a role Weegloo provides by default (for example, Administrator), so it cannot be edited or deleted.
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<Space> | The Space this SpaceRole belongs to. |
createdBy | Refer<User> | The user who created it. |
createdAt | string (date-time) | Creation time. |
updatedBy | Refer<User> | 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
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 subscribes to. The value of each action is an object holding Allow and Deny arrays of rules.
"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 aReferthat points to that resource. In thecontentTypemap it means one specific Content Type; in thescriptmap, one specific Script.contentType: Limits to the Content Type the Content belongs to. You put in aReferthat points to a Content Type.createdBy: Limits to only resources created by a specific user. Put a specific user id insys.idto limit to what that person created, or the reserved value:selfto 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
contentTypemap you name the target withself, not withcontentType. What you narrow there is the Content Type itself. ThecontentTypefilter means "the kind this resource refers to", so it fits thecontentmap only. - A filter that narrows along an axis the resource does not have (
tagon a Content Type,contentTypeon Media) is not blocked at save time, but the rule is not evaluated the way you intended. Do not use it.
To evaluate a
createdByfilter (including:self) on CDA (delivery), the target Content Type'spublishWithAuthormust betrue. CDA evaluates this filter against thesys.createdByof the publish snapshot, so ifpublishWithAuthoris left at its defaultfalsethe snapshot has no author: anAllowrule matches nothing, and aDenyrule filters out no one. CMA (management) evaluates against thesys.createdByof the draft and is therefore independent of this setting. BecausepublishWithAuthoris not retroactive, turn it on before publishing content, and republish any Content that has already been published. See thepublishWithAuthordescription in Content Type.
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)
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.
{
"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)
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 above.
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 section above.
script (Script permissions)
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 aReferthat points to that Script (itstargetTypeisScript).createdBy: Limits by who created it (use:selffor "only the Scripts 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:
"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.
"script": {
"Execute": {
"Allow": [
{ "self": { "sys": { "id": "3trmXRMZcTAjDnphewjj1AaxYcaxlK", "type": "Refer", "targetType": "Script" } } }
]
}
}Bind this role to a Space Access Token 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.
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). See Script execution semantics, limits, and security for details.
Errors
These are the codes you meet when working with a SpaceRole. For codes that are common to every resource, see common errors.
| Code | Condition |
|---|---|
WGL400020 | The caller tried to save a SpaceRole whose rule carried a filter that has no meaning in that permission map. |
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.
Related documents
- Space Membership: Bind a SpaceRole into a member's
roles. - Delivery Access Token: The delivery token bound to a least-privilege SpaceRole.
- Content Type: The Content Type the permission rules point to.
