@datocms/cma-client 5.4.16 → 5.4.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -50,6 +50,16 @@ export type RoleType = 'role';
50
50
  * via the `definition` "id".
51
51
  */
52
52
  export type RoleIdentity = string;
53
+ /**
54
+ * ID of environment. Can only contain lowercase letters, numbers and dashes
55
+ *
56
+ * This interface was referenced by `Environment`'s JSON-Schema
57
+ * via the `definition` "identity".
58
+ *
59
+ * This interface was referenced by `Environment`'s JSON-Schema
60
+ * via the `definition` "id".
61
+ */
62
+ export type EnvironmentIdentity = string;
53
63
  /**
54
64
  * RFC 4122 UUID of item type expressed in URL-safe base64 format
55
65
  *
@@ -70,16 +80,6 @@ export type ItemTypeIdentity = string;
70
80
  * via the `definition` "id".
71
81
  */
72
82
  export type WorkflowIdentity = string;
73
- /**
74
- * ID of environment. Can only contain lowercase letters, numbers and dashes
75
- *
76
- * This interface was referenced by `Environment`'s JSON-Schema
77
- * via the `definition` "identity".
78
- *
79
- * This interface was referenced by `Environment`'s JSON-Schema
80
- * via the `definition` "id".
81
- */
82
- export type EnvironmentIdentity = string;
83
83
  /**
84
84
  * RFC 4122 UUID of upload collection expressed in URL-safe base64 format
85
85
  *
@@ -202,9 +202,9 @@ export type AccessTokenIdentity = string;
202
202
  */
203
203
  export type AccessTokenDestroyHrefSchema = {
204
204
  /**
205
- * New owner for resources previously owned by the deleted access token. This argument specifies the new owner type.
205
+ * New owner for resources previously owned by the deleted access token. This argument specifies the new owner type. Use `account` or `organization` to reassign to the project's owner — `client.site.find().owner` returns the right type/id pair to pass.
206
206
  */
207
- destination_user_type?: 'account' | 'user' | 'access_token' | 'sso_user';
207
+ destination_user_type?: 'account' | 'organization' | 'user' | 'access_token' | 'sso_user';
208
208
  /**
209
209
  * New owner for resources previously owned by the deleted access token. This argument specifies the new owner ID.
210
210
  */
@@ -1560,7 +1560,82 @@ export type SiteSelfHrefSchema = {
1560
1560
  [k: string]: unknown;
1561
1561
  };
1562
1562
  /**
1563
- * A Role represents a specific set of actions an editor (or an API token) can perform on your administrative area.
1563
+ * A Role groups the permissions that govern what a credential can do in a project. The same role definition is applied to **collaborators**, **SSO users**, and **API tokens** alike design roles around what the *credential* should be allowed to do, not who is holding it.
1564
+ *
1565
+ * > [!PROTIP] 📘 Same role, different identities
1566
+ * > Ask "what is the *credential* allowed to do?" — not "what is this *person* allowed to do?". For API tokens specifically, the role's permissions are further constrained by the token's API surface flags (`can_access_cda`, `can_access_cda_preview`, `can_access_cma`); see the [API token](/docs/content-management-api/resources/access-token) resource for details.
1567
+ *
1568
+ * ## How permissions are computed
1569
+ *
1570
+ * Most of the granular permissions on a role come as a `positive_<resource>_permissions` / `negative_<resource>_permissions` pair: build triggers, search indexes, records (`item_type`), uploads. They all follow the same rule:
1571
+ *
1572
+ * > Effective permissions = `(inherited ∪ positive_*) − negative_*`
1573
+ *
1574
+ * Positive entries (and entries pulled in via `relationships.inherits_permissions_from`) grant access. Negative entries always win when they overlap. The idiomatic recipe for "almost everything" is a single `action: "all"` positive entry plus targeted negative entries to subtract — instead of enumerating each allowed action.
1575
+ *
1576
+ * > [!WARNING] ⚠️ Send `positive_*` and `negative_*` together
1577
+ * > For each resource family (records, uploads, build triggers, search indexes), the matching `positive_*` and `negative_*` arrays must be **both present or both absent** in a create/update payload. On **update**, sent arrays *replace* the stored ones wholesale, so always read the role first and pass back the existing entries on the side you're not changing — sending `[]` to satisfy the constraint will erase everything that was there. (On create, `[]` is fine since there's nothing to lose.) The [Update endpoint](/docs/content-management-api/resources/role/update) documents an SDK helper that handles this diff for records and uploads.
1578
+ *
1579
+ * The computed result is exposed on every role response under `meta.final_permissions`; the raw declared values stay on `attributes.*`. See [Effective vs declared permissions](#effective-vs-declared-permissions) below.
1580
+ *
1581
+ * ## Project-level permissions
1582
+ *
1583
+ * These attributes gate access to project-wide capabilities. They apply uniformly across the whole project; granular control over individual records and uploads lives under [Per-environment content permissions](#per-environment-content-permissions).
1584
+ *
1585
+ * - **Project-wide flags.** Boolean attributes named `can_*` (`can_edit_schema`, `can_manage_environments`, `can_manage_access_tokens`, …) cover the schema, environments, users, webhooks, and so on — see the property table for the full list.
1586
+ * - **Environment access.** `environments_access` controls *which* environments the credential can enter at all (`all`, `primary_only`, `sandbox_only`, or `none`). Use `none` when the role is meant only to be inherited from.
1587
+ * - **Build triggers.** The role may **manually fire** the build triggers listed in `positive_build_trigger_permissions`, minus those listed in `negative_build_trigger_permissions`. Use `build_trigger: null` on an entry to cover every trigger at once. Creating, editing, or deleting trigger definitions is gated separately by `can_manage_build_triggers`.
1588
+ * - **Search indexes.** The role may **manually re-index** the search indexes listed in `positive_search_index_permissions`, minus those listed in `negative_search_index_permissions`. Use `search_index: null` on an entry to cover every index. Managing the index definitions themselves is gated separately by `can_manage_search_indexes`.
1589
+ *
1590
+ * ## Per-environment content permissions
1591
+ *
1592
+ * The role's access to **records** and **uploads** is governed by two positive/negative array pairs. Every entry is **scoped to a single environment** via the required `environment` field — to grant the same permission across multiple environments, repeat the entry once per environment id (or use `inherits_permissions_from` together with `environments_access`). The computation is the same `(inherited ∪ positive_*) − negative_*` rule from [How permissions are computed](#how-permissions-are-computed), evaluated per environment.
1593
+ *
1594
+ * ###### Records
1595
+ *
1596
+ * Permission entries live in `positive_item_type_permissions` (and the `negative_*` counterpart). Each entry is a discriminated union keyed by `action`:
1597
+ *
1598
+ * - `all` — every action below
1599
+ * - `read` — read records
1600
+ * - `create` — create new records
1601
+ * - `update` — edit existing records
1602
+ * - `publish` — publish/unpublish records
1603
+ * - `duplicate` — duplicate records
1604
+ * - `delete` — destroy records
1605
+ * - `edit_creator` — change a record's `creator` relationship
1606
+ * - `take_over` — wrest a record from another user currently editing it
1607
+ * - `move_to_stage` — move a record between workflow stages
1608
+ *
1609
+ * Per entry you can also restrict by:
1610
+ *
1611
+ * - `item_type` — restrict to a specific model (`null` = all models)
1612
+ * - `workflow` — restrict to records associated with a workflow (mutually exclusive with `item_type`)
1613
+ * - `on_creator` — `anyone`, `self` (records the credential created), or `role` (records created by anyone with this role)
1614
+ * - `localization_scope` + `locale` — for `create`/`update`/`publish`/`all`: restrict to localized vs non-localized content, optionally pinning to one locale (on `all` the scope is forced to `"all"`)
1615
+ * - `on_stage` / `to_stage` — for workflow-aware actions: restrict to records currently on a stage, or to moves towards a stage
1616
+ *
1617
+ * The shape of each entry depends on the `action` — see the property tables on each endpoint for which sub-fields are valid per branch.
1618
+ *
1619
+ * > [!WARNING] ⚠️ Some restrictors require an Enterprise plan
1620
+ * > Workflow-aware permissions — the `move_to_stage` action and the `workflow` / `on_stage` / `to_stage` restrictors — require [Workflows](https://www.datocms.com/features/workflows), an Enterprise feature. Per-content-scope restrictions are also gated: only `localization_scope: "all"` is available on every plan, while `"localized"` (with its companion `locale`) and `"not_localized"` both require Enterprise. Setting any of these on a non-Enterprise project will return an error — check the [pricing page](https://www.datocms.com/pricing) before relying on them.
1621
+ *
1622
+ * ###### Uploads
1623
+ *
1624
+ * Permission entries live in `positive_upload_permissions` (and the `negative_*` counterpart). Same discriminated-union shape as records, with the upload-relevant actions (`read`, `create`, `update`, `delete`, `edit_creator`, `replace_asset`, `move`, `all`), scoped by `upload_collection` instead of `item_type`. The `move` action also accepts `move_to_upload_collection` to restrict the destination of the move.
1625
+ *
1626
+ * ## Inheriting from other roles
1627
+ *
1628
+ * `relationships.inherits_permissions_from` accepts a list of role ids whose permissions are unioned into this role's positive set before the negative set is subtracted (per [How permissions are computed](#how-permissions-are-computed)). This is how built-in roles are typically extended without copying their full permission tree — duplicate the closest built-in role, then add a `negative_*` entry to take something away, or set `inherits_permissions_from` and add only the positive entries that differ.
1629
+ *
1630
+ * ## Effective vs declared permissions
1631
+ *
1632
+ * Two views of a role's permissions are surfaced on the response:
1633
+ *
1634
+ * - **`attributes.*`** — the permissions declared *on this role directly*. This is what was sent on create/update; it does not reflect anything inherited from `relationships.inherits_permissions_from`.
1635
+ * - **`meta.final_permissions`** — the **effective** permissions after walking the inheritance chain and applying the rule from [How permissions are computed](#how-permissions-are-computed). This is the set actually enforced when a credential bound to this role makes a request.
1636
+ *
1637
+ * When debugging "why can't this user do X?", read `meta.final_permissions`, not `attributes`.
1638
+ *
1564
1639
  *
1565
1640
  * This interface was referenced by `DatoApi`'s JSON-Schema
1566
1641
  * via the `definition` "role".
@@ -1588,11 +1663,11 @@ export type RoleAttributes = {
1588
1663
  */
1589
1664
  can_edit_favicon: boolean;
1590
1665
  /**
1591
- * Can change project global properties
1666
+ * Can change project-wide settings (project name, internal subdomain, frontend preview URL, deployment settings)
1592
1667
  */
1593
1668
  can_edit_site: boolean;
1594
1669
  /**
1595
- * Can create and edit models and plugins
1670
+ * Can create and edit the project schema: models, block models, fields, fieldsets, validators, and plugins
1596
1671
  */
1597
1672
  can_edit_schema: boolean;
1598
1673
  /**
@@ -1600,11 +1675,11 @@ export type RoleAttributes = {
1600
1675
  */
1601
1676
  can_manage_menu: boolean;
1602
1677
  /**
1603
- * Can change locales, timezone and UI theme
1678
+ * Can edit per-environment settings of the environments this role has access to: locales, timezone, and UI theme. This is *not* about creating or switching environments — see `can_manage_environments` for that, and `environments_access` for which environments this role can enter at all.
1604
1679
  */
1605
1680
  can_edit_environment: boolean;
1606
1681
  /**
1607
- * Can promote environments to primary and manage maintenance mode
1682
+ * Can promote a sandbox environment to primary (atomic swap) and toggle the project's maintenance mode. Distinct from `can_manage_environments`, which covers creating/forking/deleting sandboxes.
1608
1683
  */
1609
1684
  can_promote_environments: boolean;
1610
1685
  /**
@@ -1636,7 +1711,7 @@ export type RoleAttributes = {
1636
1711
  */
1637
1712
  can_manage_webhooks: boolean;
1638
1713
  /**
1639
- * Can create and delete sandbox environments and promote them to primary environment
1714
+ * Can create, fork, and delete sandbox environments. Promotion to primary is gated separately by `can_promote_environments`.
1640
1715
  */
1641
1716
  can_manage_environments: boolean;
1642
1717
  /**
@@ -1668,130 +1743,396 @@ export type RoleAttributes = {
1668
1743
  */
1669
1744
  can_access_search_index_events_log: boolean;
1670
1745
  /**
1671
- * Allowed actions on a model (or all) for a role
1746
+ * Allowed actions on a model (or all) for a role.
1747
+ *
1748
+ * The shape of each entry depends on the `action` (discriminated union). Idiomatic recipes:
1749
+ * - To grant every action, use a single `action: "all"` entry with `localization_scope: "all"`.
1750
+ * - To grant a subset (e.g. create+read+update but not delete), prefer a single `action: "all"` entry plus `negative_item_type_permissions` entries for the actions to exclude — instead of listing each allowed action separately.
1672
1751
  */
1673
- positive_item_type_permissions: {
1674
- item_type?: ItemTypeIdentity | null;
1675
- workflow?: WorkflowIdentity | null;
1676
- on_stage?: null | string;
1677
- to_stage?: null | string;
1678
- environment: EnvironmentIdentity;
1679
- /**
1680
- * Permitted action
1681
- */
1682
- action: 'all' | 'read' | 'update' | 'create' | 'duplicate' | 'delete' | 'publish' | 'edit_creator' | 'take_over' | 'move_to_stage';
1683
- /**
1684
- * Permitted creator
1685
- */
1686
- on_creator?: 'anyone' | 'self' | 'role' | null;
1687
- /**
1688
- * Permitted content scope
1689
- */
1690
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
1691
- /**
1692
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
1693
- */
1694
- locale?: string | null;
1695
- }[];
1752
+ positive_item_type_permissions: (RoleItemTypePermissionAll | RoleItemTypePermissionRead | RoleItemTypePermissionCreate | RoleItemTypePermissionUpdateOrPublish | RoleItemTypePermissionDuplicate | RoleItemTypePermissionDeleteOrEditCreatorOrTakeOver | RoleItemTypePermissionMoveToStage)[];
1696
1753
  /**
1697
- * Prohibited actions on a model (or all) for a role
1754
+ * Prohibited actions on a model (or all) for a role. Negative permissions take precedence and are typically paired with a broader positive `action: "all"` entry to subtract specific actions (e.g. forbid `delete`).
1698
1755
  */
1699
- negative_item_type_permissions: {
1700
- item_type?: ItemTypeIdentity | null;
1701
- workflow?: WorkflowIdentity | null;
1702
- on_stage?: null | string;
1703
- to_stage?: null | string;
1704
- environment: EnvironmentIdentity;
1705
- /**
1706
- * Permitted action
1707
- */
1708
- action: 'all' | 'read' | 'update' | 'create' | 'duplicate' | 'delete' | 'publish' | 'edit_creator' | 'take_over' | 'move_to_stage';
1709
- /**
1710
- * Permitted creator
1711
- */
1712
- on_creator?: 'anyone' | 'self' | 'role' | null;
1713
- /**
1714
- * Permitted content scope
1715
- */
1716
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
1717
- /**
1718
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
1719
- */
1720
- locale?: string | null;
1721
- }[];
1756
+ negative_item_type_permissions: (RoleItemTypePermissionAll | RoleItemTypePermissionRead | RoleItemTypePermissionCreate | RoleItemTypePermissionUpdateOrPublish | RoleItemTypePermissionDuplicate | RoleItemTypePermissionDeleteOrEditCreatorOrTakeOver | RoleItemTypePermissionMoveToStage)[];
1722
1757
  /**
1723
- * Allowed actions on a model (or all) for a role
1758
+ * Allowed actions on uploads (or all) for a role.
1759
+ *
1760
+ * The shape of each entry depends on the `action` (discriminated union). To grant a subset, prefer a single `action: "all"` entry plus `negative_upload_permissions` entries for the actions to exclude.
1724
1761
  */
1725
- positive_upload_permissions: {
1726
- environment: EnvironmentIdentity;
1727
- /**
1728
- * Permitted action
1729
- */
1730
- action: 'all' | 'read' | 'update' | 'create' | 'delete' | 'edit_creator' | 'replace_asset' | 'move';
1731
- /**
1732
- * Permitted creator
1733
- */
1734
- on_creator?: 'anyone' | 'self' | 'role' | null;
1735
- /**
1736
- * Permitted content scope
1737
- */
1738
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
1739
- /**
1740
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
1741
- */
1742
- locale?: string | null;
1743
- upload_collection?: UploadCollectionIdentity | null;
1744
- move_to_upload_collection?: UploadCollectionIdentity | null;
1745
- }[];
1762
+ positive_upload_permissions: (RoleUploadPermissionAll | RoleUploadPermissionUpdate | RoleUploadPermissionCreate | RoleUploadPermissionReadOrDeleteOrEditCreatorOrReplaceAsset | RoleUploadPermissionMove)[];
1746
1763
  /**
1747
- * Prohibited actions on a model (or all) for a role
1764
+ * Prohibited actions on uploads (or all) for a role. Negative permissions take precedence and are typically paired with a broader positive `action: "all"` entry to subtract specific actions.
1748
1765
  */
1749
- negative_upload_permissions: {
1750
- environment: EnvironmentIdentity;
1751
- /**
1752
- * Permitted action
1753
- */
1754
- action: 'all' | 'read' | 'update' | 'create' | 'delete' | 'edit_creator' | 'replace_asset' | 'move';
1755
- /**
1756
- * Permitted creator
1757
- */
1758
- on_creator?: 'anyone' | 'self' | 'role' | null;
1759
- /**
1760
- * Permitted content scope
1761
- */
1762
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
1763
- /**
1764
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
1765
- */
1766
- locale?: string | null;
1767
- upload_collection?: UploadCollectionIdentity | null;
1768
- move_to_upload_collection?: UploadCollectionIdentity | null;
1769
- }[];
1766
+ negative_upload_permissions: (RoleUploadPermissionAll | RoleUploadPermissionUpdate | RoleUploadPermissionCreate | RoleUploadPermissionReadOrDeleteOrEditCreatorOrReplaceAsset | RoleUploadPermissionMove)[];
1770
1767
  /**
1771
- * Allowed build triggers for a role
1768
+ * Build triggers this role is allowed to **manually fire**. An entry with `build_trigger: null` covers every build trigger. Note: this does not control creating/editing build triggers themselves that is gated by `can_manage_build_triggers`.
1772
1769
  */
1773
1770
  positive_build_trigger_permissions: {
1774
1771
  build_trigger?: BuildTriggerIdentity | null;
1775
1772
  }[];
1776
1773
  /**
1777
- * Prohibited build triggers for a role
1774
+ * Build triggers this role is **forbidden** from manually firing. Negative entries take precedence over positive ones; pair with a `build_trigger: null` positive entry to allow all-but-N.
1778
1775
  */
1779
1776
  negative_build_trigger_permissions: {
1780
1777
  build_trigger?: BuildTriggerIdentity | null;
1781
1778
  }[];
1782
1779
  /**
1783
- * Search indexes that can be triggered by a role
1780
+ * Search indexes this role is allowed to **manually re-index**. An entry with `search_index: null` covers every search index. Note: this does not control creating/editing search indexes themselves — that is gated by `can_manage_search_indexes`.
1784
1781
  */
1785
1782
  positive_search_index_permissions: {
1786
1783
  search_index?: SearchIndexIdentity | null;
1787
1784
  }[];
1788
1785
  /**
1789
- * Search indexes that can't be triggered by a role
1786
+ * Search indexes this role is **forbidden** from manually re-indexing. Negative entries take precedence over positive ones; pair with a `search_index: null` positive entry to allow all-but-N.
1790
1787
  */
1791
1788
  negative_search_index_permissions: {
1792
1789
  search_index?: SearchIndexIdentity | null;
1793
1790
  }[];
1794
1791
  };
1792
+ /**
1793
+ * Item-type permission entry granting all actions on a model. Requires `localization_scope: "all"`.
1794
+ *
1795
+ * This interface was referenced by `Role`'s JSON-Schema
1796
+ * via the `definition` "item_type_permission_all".
1797
+ */
1798
+ export type RoleItemTypePermissionAll = {
1799
+ /**
1800
+ * Permitted action
1801
+ */
1802
+ action: 'all';
1803
+ environment: EnvironmentIdentity;
1804
+ /**
1805
+ * Restricts the permission to a specific model. When `null`, the permission applies to all models.
1806
+ */
1807
+ item_type?: ItemTypeIdentity | null;
1808
+ /**
1809
+ * Restricts the permission to records associated with a specific workflow. Mutually exclusive with `item_type`.
1810
+ */
1811
+ workflow?: WorkflowIdentity | null;
1812
+ /**
1813
+ * Restrict to records currently on a workflow stage.
1814
+ */
1815
+ on_stage?: string | null;
1816
+ /**
1817
+ * Restrict to moves towards a specific workflow stage.
1818
+ */
1819
+ to_stage?: string | null;
1820
+ /**
1821
+ * Permitted creator
1822
+ */
1823
+ on_creator: 'anyone' | 'self' | 'role';
1824
+ /**
1825
+ * For `action: "all"` this must be `"all"`.
1826
+ */
1827
+ localization_scope: 'all';
1828
+ [k: string]: unknown;
1829
+ };
1830
+ /**
1831
+ * Item-type permission entry granting `read` on records. `localization_scope` and `locale` must be omitted (or null).
1832
+ *
1833
+ * This interface was referenced by `Role`'s JSON-Schema
1834
+ * via the `definition` "item_type_permission_read".
1835
+ */
1836
+ export type RoleItemTypePermissionRead = {
1837
+ /**
1838
+ * Permitted action
1839
+ */
1840
+ action: 'read';
1841
+ environment: EnvironmentIdentity;
1842
+ /**
1843
+ * Restricts the permission to a specific model. When `null`, the permission applies to all models.
1844
+ */
1845
+ item_type?: ItemTypeIdentity | null;
1846
+ /**
1847
+ * Restricts the permission to records associated with a specific workflow. Mutually exclusive with `item_type`.
1848
+ */
1849
+ workflow?: WorkflowIdentity | null;
1850
+ /**
1851
+ * Permitted creator
1852
+ */
1853
+ on_creator: 'anyone' | 'self' | 'role';
1854
+ [k: string]: unknown;
1855
+ };
1856
+ /**
1857
+ * Item-type permission entry granting `create` on records. Requires `localization_scope`; if `localization_scope: "localized"`, `locale` is also required. `on_creator`, `on_stage`, and `to_stage` are not applicable and must be omitted (or null).
1858
+ *
1859
+ * This interface was referenced by `Role`'s JSON-Schema
1860
+ * via the `definition` "item_type_permission_create".
1861
+ */
1862
+ export type RoleItemTypePermissionCreate = {
1863
+ /**
1864
+ * Permitted action
1865
+ */
1866
+ action: 'create';
1867
+ environment: EnvironmentIdentity;
1868
+ /**
1869
+ * Restricts the permission to a specific model. When `null`, the permission applies to all models.
1870
+ */
1871
+ item_type?: ItemTypeIdentity | null;
1872
+ /**
1873
+ * Restricts the permission to records associated with a specific workflow. Mutually exclusive with `item_type`.
1874
+ */
1875
+ workflow?: WorkflowIdentity | null;
1876
+ /**
1877
+ * Permitted content scope
1878
+ */
1879
+ localization_scope: 'all' | 'localized' | 'not_localized';
1880
+ /**
1881
+ * Required (non-null) when `localization_scope` is `"localized"`; must be omitted otherwise.
1882
+ */
1883
+ locale?: string | null;
1884
+ [k: string]: unknown;
1885
+ };
1886
+ /**
1887
+ * Item-type permission entry granting `update` or `publish` on records. Requires `localization_scope`; if `localization_scope: "localized"`, `locale` is also required.
1888
+ *
1889
+ * This interface was referenced by `Role`'s JSON-Schema
1890
+ * via the `definition` "item_type_permission_update_or_publish".
1891
+ */
1892
+ export type RoleItemTypePermissionUpdateOrPublish = {
1893
+ /**
1894
+ * Permitted action
1895
+ */
1896
+ action: 'update' | 'publish';
1897
+ environment: EnvironmentIdentity;
1898
+ /**
1899
+ * Restricts the permission to a specific model. When `null`, the permission applies to all models.
1900
+ */
1901
+ item_type?: ItemTypeIdentity | null;
1902
+ /**
1903
+ * Restricts the permission to records associated with a specific workflow. Mutually exclusive with `item_type`.
1904
+ */
1905
+ workflow?: WorkflowIdentity | null;
1906
+ /**
1907
+ * Restrict to records currently on a workflow stage.
1908
+ */
1909
+ on_stage?: string | null;
1910
+ /**
1911
+ * Permitted creator
1912
+ */
1913
+ on_creator: 'anyone' | 'self' | 'role';
1914
+ /**
1915
+ * Permitted content scope
1916
+ */
1917
+ localization_scope: 'all' | 'localized' | 'not_localized';
1918
+ /**
1919
+ * Required (non-null) when `localization_scope` is `"localized"`; must be omitted otherwise.
1920
+ */
1921
+ locale?: string | null;
1922
+ [k: string]: unknown;
1923
+ };
1924
+ /**
1925
+ * Item-type permission entry granting `duplicate` on records. `on_creator`, `localization_scope` and `locale` are not applicable and must be omitted (or null).
1926
+ *
1927
+ * This interface was referenced by `Role`'s JSON-Schema
1928
+ * via the `definition` "item_type_permission_duplicate".
1929
+ */
1930
+ export type RoleItemTypePermissionDuplicate = {
1931
+ /**
1932
+ * Permitted action
1933
+ */
1934
+ action: 'duplicate';
1935
+ environment: EnvironmentIdentity;
1936
+ /**
1937
+ * Restricts the permission to a specific model. When `null`, the permission applies to all models.
1938
+ */
1939
+ item_type?: ItemTypeIdentity | null;
1940
+ /**
1941
+ * Restricts the permission to records associated with a specific workflow. Mutually exclusive with `item_type`.
1942
+ */
1943
+ workflow?: WorkflowIdentity | null;
1944
+ /**
1945
+ * Restrict to records currently on a workflow stage.
1946
+ */
1947
+ on_stage?: string | null;
1948
+ [k: string]: unknown;
1949
+ };
1950
+ /**
1951
+ * Item-type permission entry granting `delete`, `edit_creator`, or `take_over` on records. `localization_scope` and `locale` must be omitted (or null).
1952
+ *
1953
+ * This interface was referenced by `Role`'s JSON-Schema
1954
+ * via the `definition` "item_type_permission_delete_or_edit_creator_or_take_over".
1955
+ */
1956
+ export type RoleItemTypePermissionDeleteOrEditCreatorOrTakeOver = {
1957
+ /**
1958
+ * Permitted action
1959
+ */
1960
+ action: 'delete' | 'edit_creator' | 'take_over';
1961
+ environment: EnvironmentIdentity;
1962
+ /**
1963
+ * Restricts the permission to a specific model. When `null`, the permission applies to all models.
1964
+ */
1965
+ item_type?: ItemTypeIdentity | null;
1966
+ /**
1967
+ * Restricts the permission to records associated with a specific workflow. Mutually exclusive with `item_type`.
1968
+ */
1969
+ workflow?: WorkflowIdentity | null;
1970
+ /**
1971
+ * Restrict to records currently on a workflow stage.
1972
+ */
1973
+ on_stage?: string | null;
1974
+ /**
1975
+ * Permitted creator
1976
+ */
1977
+ on_creator: 'anyone' | 'self' | 'role';
1978
+ [k: string]: unknown;
1979
+ };
1980
+ /**
1981
+ * Item-type permission entry granting `move_to_stage` on records. `localization_scope` and `locale` must be omitted (or null).
1982
+ *
1983
+ * This interface was referenced by `Role`'s JSON-Schema
1984
+ * via the `definition` "item_type_permission_move_to_stage".
1985
+ */
1986
+ export type RoleItemTypePermissionMoveToStage = {
1987
+ /**
1988
+ * Permitted action
1989
+ */
1990
+ action: 'move_to_stage';
1991
+ environment: EnvironmentIdentity;
1992
+ /**
1993
+ * Restricts the permission to a specific model. When `null`, the permission applies to all models.
1994
+ */
1995
+ item_type?: ItemTypeIdentity | null;
1996
+ /**
1997
+ * Restricts the permission to records associated with a specific workflow. Mutually exclusive with `item_type`.
1998
+ */
1999
+ workflow?: WorkflowIdentity | null;
2000
+ /**
2001
+ * Restrict to records currently on a workflow stage.
2002
+ */
2003
+ on_stage?: string | null;
2004
+ /**
2005
+ * Restrict to moves towards a specific workflow stage.
2006
+ */
2007
+ to_stage?: string | null;
2008
+ /**
2009
+ * Permitted creator
2010
+ */
2011
+ on_creator: 'anyone' | 'self' | 'role';
2012
+ [k: string]: unknown;
2013
+ };
2014
+ /**
2015
+ * Upload permission entry granting all actions on uploads. Requires `localization_scope: "all"`.
2016
+ *
2017
+ * This interface was referenced by `Role`'s JSON-Schema
2018
+ * via the `definition` "upload_permission_all".
2019
+ */
2020
+ export type RoleUploadPermissionAll = {
2021
+ /**
2022
+ * Permitted action
2023
+ */
2024
+ action: 'all';
2025
+ environment: EnvironmentIdentity;
2026
+ /**
2027
+ * Restricts the permission to a specific upload collection. When `null`, the permission applies to all collections.
2028
+ */
2029
+ upload_collection?: UploadCollectionIdentity | null;
2030
+ /**
2031
+ * Permitted creator
2032
+ */
2033
+ on_creator: 'anyone' | 'self' | 'role';
2034
+ /**
2035
+ * For `action: "all"` this must be `"all"`.
2036
+ */
2037
+ localization_scope: 'all';
2038
+ [k: string]: unknown;
2039
+ };
2040
+ /**
2041
+ * Upload permission entry granting `update` on uploads. Requires `localization_scope`; if `localization_scope: "localized"`, `locale` is also required.
2042
+ *
2043
+ * This interface was referenced by `Role`'s JSON-Schema
2044
+ * via the `definition` "upload_permission_update".
2045
+ */
2046
+ export type RoleUploadPermissionUpdate = {
2047
+ /**
2048
+ * Permitted action
2049
+ */
2050
+ action: 'update';
2051
+ environment: EnvironmentIdentity;
2052
+ /**
2053
+ * Restricts the permission to a specific upload collection. When `null`, the permission applies to all collections.
2054
+ */
2055
+ upload_collection?: UploadCollectionIdentity | null;
2056
+ /**
2057
+ * Permitted creator
2058
+ */
2059
+ on_creator: 'anyone' | 'self' | 'role';
2060
+ /**
2061
+ * Permitted content scope
2062
+ */
2063
+ localization_scope: 'all' | 'localized' | 'not_localized';
2064
+ /**
2065
+ * Required (non-null) when `localization_scope` is `"localized"`; must be omitted otherwise.
2066
+ */
2067
+ locale?: string | null;
2068
+ [k: string]: unknown;
2069
+ };
2070
+ /**
2071
+ * Upload permission entry granting `create` on uploads. `on_creator`, `localization_scope` and `locale` are not applicable and must be omitted (or null).
2072
+ *
2073
+ * This interface was referenced by `Role`'s JSON-Schema
2074
+ * via the `definition` "upload_permission_create".
2075
+ */
2076
+ export type RoleUploadPermissionCreate = {
2077
+ /**
2078
+ * Permitted action
2079
+ */
2080
+ action: 'create';
2081
+ environment: EnvironmentIdentity;
2082
+ /**
2083
+ * Restricts the permission to a specific upload collection. When `null`, the permission applies to all collections.
2084
+ */
2085
+ upload_collection?: UploadCollectionIdentity | null;
2086
+ [k: string]: unknown;
2087
+ };
2088
+ /**
2089
+ * Upload permission entry granting `read`, `delete`, `edit_creator`, or `replace_asset` on uploads. `localization_scope` and `locale` must be omitted (or null).
2090
+ *
2091
+ * This interface was referenced by `Role`'s JSON-Schema
2092
+ * via the `definition` "upload_permission_read_or_delete_or_edit_creator_or_replace_asset".
2093
+ */
2094
+ export type RoleUploadPermissionReadOrDeleteOrEditCreatorOrReplaceAsset = {
2095
+ /**
2096
+ * Permitted action
2097
+ */
2098
+ action: 'read' | 'delete' | 'edit_creator' | 'replace_asset';
2099
+ environment: EnvironmentIdentity;
2100
+ /**
2101
+ * Restricts the permission to a specific upload collection. When `null`, the permission applies to all collections.
2102
+ */
2103
+ upload_collection?: UploadCollectionIdentity | null;
2104
+ /**
2105
+ * Permitted creator
2106
+ */
2107
+ on_creator: 'anyone' | 'self' | 'role';
2108
+ [k: string]: unknown;
2109
+ };
2110
+ /**
2111
+ * Upload permission entry granting `move` on uploads. `localization_scope` and `locale` must be omitted (or null). `move_to_upload_collection` is only valid here.
2112
+ *
2113
+ * This interface was referenced by `Role`'s JSON-Schema
2114
+ * via the `definition` "upload_permission_move".
2115
+ */
2116
+ export type RoleUploadPermissionMove = {
2117
+ /**
2118
+ * Permitted action
2119
+ */
2120
+ action: 'move';
2121
+ environment: EnvironmentIdentity;
2122
+ /**
2123
+ * Restricts the permission to a specific upload collection. When `null`, the permission applies to all collections.
2124
+ */
2125
+ upload_collection?: UploadCollectionIdentity | null;
2126
+ /**
2127
+ * Restricts the destination upload collection of the move action. When `null`, any destination is allowed.
2128
+ */
2129
+ move_to_upload_collection?: UploadCollectionIdentity | null;
2130
+ /**
2131
+ * Permitted creator
2132
+ */
2133
+ on_creator: 'anyone' | 'self' | 'role';
2134
+ [k: string]: unknown;
2135
+ };
1795
2136
  /**
1796
2137
  * JSON API links
1797
2138
  *
@@ -1832,11 +2173,11 @@ export type RoleMeta = {
1832
2173
  */
1833
2174
  can_edit_favicon: boolean;
1834
2175
  /**
1835
- * Can change project global properties
2176
+ * Can change project-wide settings (project name, internal subdomain, frontend preview URL, deployment settings)
1836
2177
  */
1837
2178
  can_edit_site: boolean;
1838
2179
  /**
1839
- * Can create and edit models and plugins
2180
+ * Can create and edit the project schema: models, block models, fields, fieldsets, validators, and plugins
1840
2181
  */
1841
2182
  can_edit_schema: boolean;
1842
2183
  /**
@@ -1844,11 +2185,11 @@ export type RoleMeta = {
1844
2185
  */
1845
2186
  can_manage_menu: boolean;
1846
2187
  /**
1847
- * Can change locales, timezone and UI theme
2188
+ * Can edit per-environment settings of the environments this role has access to: locales, timezone, and UI theme. This is *not* about creating or switching environments — see `can_manage_environments` for that, and `environments_access` for which environments this role can enter at all.
1848
2189
  */
1849
2190
  can_edit_environment: boolean;
1850
2191
  /**
1851
- * Can promote environments to primary and manage maintenance mode
2192
+ * Can promote a sandbox environment to primary (atomic swap) and toggle the project's maintenance mode. Distinct from `can_manage_environments`, which covers creating/forking/deleting sandboxes.
1852
2193
  */
1853
2194
  can_promote_environments: boolean;
1854
2195
  /**
@@ -1880,7 +2221,7 @@ export type RoleMeta = {
1880
2221
  */
1881
2222
  can_manage_webhooks: boolean;
1882
2223
  /**
1883
- * Can create and delete sandbox environments and promote them to primary environment
2224
+ * Can create, fork, and delete sandbox environments. Promotion to primary is gated separately by `can_promote_environments`.
1884
2225
  */
1885
2226
  can_manage_environments: boolean;
1886
2227
  /**
@@ -1912,125 +2253,47 @@ export type RoleMeta = {
1912
2253
  */
1913
2254
  can_access_search_index_events_log: boolean;
1914
2255
  /**
1915
- * Allowed actions on a model (or all) for a role
2256
+ * Allowed actions on a model (or all) for a role.
2257
+ *
2258
+ * The shape of each entry depends on the `action` (discriminated union). Idiomatic recipes:
2259
+ * - To grant every action, use a single `action: "all"` entry with `localization_scope: "all"`.
2260
+ * - To grant a subset (e.g. create+read+update but not delete), prefer a single `action: "all"` entry plus `negative_item_type_permissions` entries for the actions to exclude — instead of listing each allowed action separately.
1916
2261
  */
1917
- positive_item_type_permissions: {
1918
- item_type?: ItemTypeIdentity | null;
1919
- workflow?: WorkflowIdentity | null;
1920
- on_stage?: null | string;
1921
- to_stage?: null | string;
1922
- environment: EnvironmentIdentity;
1923
- /**
1924
- * Permitted action
1925
- */
1926
- action: 'all' | 'read' | 'update' | 'create' | 'duplicate' | 'delete' | 'publish' | 'edit_creator' | 'take_over' | 'move_to_stage';
1927
- /**
1928
- * Permitted creator
1929
- */
1930
- on_creator?: 'anyone' | 'self' | 'role' | null;
1931
- /**
1932
- * Permitted content scope
1933
- */
1934
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
1935
- /**
1936
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
1937
- */
1938
- locale?: string | null;
1939
- }[];
2262
+ positive_item_type_permissions: (RoleItemTypePermissionAll | RoleItemTypePermissionRead | RoleItemTypePermissionCreate | RoleItemTypePermissionUpdateOrPublish | RoleItemTypePermissionDuplicate | RoleItemTypePermissionDeleteOrEditCreatorOrTakeOver | RoleItemTypePermissionMoveToStage)[];
1940
2263
  /**
1941
- * Prohibited actions on a model (or all) for a role
2264
+ * Prohibited actions on a model (or all) for a role. Negative permissions take precedence and are typically paired with a broader positive `action: "all"` entry to subtract specific actions (e.g. forbid `delete`).
1942
2265
  */
1943
- negative_item_type_permissions: {
1944
- item_type?: ItemTypeIdentity | null;
1945
- workflow?: WorkflowIdentity | null;
1946
- on_stage?: null | string;
1947
- to_stage?: null | string;
1948
- environment: EnvironmentIdentity;
1949
- /**
1950
- * Permitted action
1951
- */
1952
- action: 'all' | 'read' | 'update' | 'create' | 'duplicate' | 'delete' | 'publish' | 'edit_creator' | 'take_over' | 'move_to_stage';
1953
- /**
1954
- * Permitted creator
1955
- */
1956
- on_creator?: 'anyone' | 'self' | 'role' | null;
1957
- /**
1958
- * Permitted content scope
1959
- */
1960
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
1961
- /**
1962
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
1963
- */
1964
- locale?: string | null;
1965
- }[];
2266
+ negative_item_type_permissions: (RoleItemTypePermissionAll | RoleItemTypePermissionRead | RoleItemTypePermissionCreate | RoleItemTypePermissionUpdateOrPublish | RoleItemTypePermissionDuplicate | RoleItemTypePermissionDeleteOrEditCreatorOrTakeOver | RoleItemTypePermissionMoveToStage)[];
1966
2267
  /**
1967
- * Allowed actions on a model (or all) for a role
2268
+ * Allowed actions on uploads (or all) for a role.
2269
+ *
2270
+ * The shape of each entry depends on the `action` (discriminated union). To grant a subset, prefer a single `action: "all"` entry plus `negative_upload_permissions` entries for the actions to exclude.
1968
2271
  */
1969
- positive_upload_permissions: {
1970
- environment: EnvironmentIdentity;
1971
- /**
1972
- * Permitted action
1973
- */
1974
- action: 'all' | 'read' | 'update' | 'create' | 'delete' | 'edit_creator' | 'replace_asset' | 'move';
1975
- /**
1976
- * Permitted creator
1977
- */
1978
- on_creator?: 'anyone' | 'self' | 'role' | null;
1979
- /**
1980
- * Permitted content scope
1981
- */
1982
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
1983
- /**
1984
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
1985
- */
1986
- locale?: string | null;
1987
- upload_collection?: UploadCollectionIdentity | null;
1988
- move_to_upload_collection?: UploadCollectionIdentity | null;
1989
- }[];
2272
+ positive_upload_permissions: (RoleUploadPermissionAll | RoleUploadPermissionUpdate | RoleUploadPermissionCreate | RoleUploadPermissionReadOrDeleteOrEditCreatorOrReplaceAsset | RoleUploadPermissionMove)[];
1990
2273
  /**
1991
- * Prohibited actions on a model (or all) for a role
2274
+ * Prohibited actions on uploads (or all) for a role. Negative permissions take precedence and are typically paired with a broader positive `action: "all"` entry to subtract specific actions.
1992
2275
  */
1993
- negative_upload_permissions: {
1994
- environment: EnvironmentIdentity;
1995
- /**
1996
- * Permitted action
1997
- */
1998
- action: 'all' | 'read' | 'update' | 'create' | 'delete' | 'edit_creator' | 'replace_asset' | 'move';
1999
- /**
2000
- * Permitted creator
2001
- */
2002
- on_creator?: 'anyone' | 'self' | 'role' | null;
2003
- /**
2004
- * Permitted content scope
2005
- */
2006
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
2007
- /**
2008
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
2009
- */
2010
- locale?: string | null;
2011
- upload_collection?: UploadCollectionIdentity | null;
2012
- move_to_upload_collection?: UploadCollectionIdentity | null;
2013
- }[];
2276
+ negative_upload_permissions: (RoleUploadPermissionAll | RoleUploadPermissionUpdate | RoleUploadPermissionCreate | RoleUploadPermissionReadOrDeleteOrEditCreatorOrReplaceAsset | RoleUploadPermissionMove)[];
2014
2277
  /**
2015
- * Allowed build triggers for a role
2278
+ * Build triggers this role is allowed to **manually fire**. An entry with `build_trigger: null` covers every build trigger. Note: this does not control creating/editing build triggers themselves that is gated by `can_manage_build_triggers`.
2016
2279
  */
2017
2280
  positive_build_trigger_permissions: {
2018
2281
  build_trigger?: BuildTriggerIdentity | null;
2019
2282
  }[];
2020
2283
  /**
2021
- * Prohibited build triggers for a role
2284
+ * Build triggers this role is **forbidden** from manually firing. Negative entries take precedence over positive ones; pair with a `build_trigger: null` positive entry to allow all-but-N.
2022
2285
  */
2023
2286
  negative_build_trigger_permissions: {
2024
2287
  build_trigger?: BuildTriggerIdentity | null;
2025
2288
  }[];
2026
2289
  /**
2027
- * Search indexes that can be triggered by a role
2290
+ * Search indexes this role is allowed to **manually re-index**. An entry with `search_index: null` covers every search index. Note: this does not control creating/editing search indexes themselves — that is gated by `can_manage_search_indexes`.
2028
2291
  */
2029
2292
  positive_search_index_permissions: {
2030
2293
  search_index?: SearchIndexIdentity | null;
2031
2294
  }[];
2032
2295
  /**
2033
- * Search indexes that can't be triggered by a role
2296
+ * Search indexes this role is **forbidden** from manually re-indexing. Negative entries take precedence over positive ones; pair with a `search_index: null` positive entry to allow all-but-N.
2034
2297
  */
2035
2298
  negative_search_index_permissions: {
2036
2299
  search_index?: SearchIndexIdentity | null;
@@ -2057,11 +2320,11 @@ export type RoleCreateSchema = {
2057
2320
  */
2058
2321
  can_edit_favicon?: boolean;
2059
2322
  /**
2060
- * Can change project global properties
2323
+ * Can change project-wide settings (project name, internal subdomain, frontend preview URL, deployment settings)
2061
2324
  */
2062
2325
  can_edit_site?: boolean;
2063
2326
  /**
2064
- * Can create and edit models and plugins
2327
+ * Can create and edit the project schema: models, block models, fields, fieldsets, validators, and plugins
2065
2328
  */
2066
2329
  can_edit_schema?: boolean;
2067
2330
  /**
@@ -2069,11 +2332,11 @@ export type RoleCreateSchema = {
2069
2332
  */
2070
2333
  can_manage_menu?: boolean;
2071
2334
  /**
2072
- * Can change locales, timezone and UI theme
2335
+ * Can edit per-environment settings of the environments this role has access to: locales, timezone, and UI theme. This is *not* about creating or switching environments — see `can_manage_environments` for that, and `environments_access` for which environments this role can enter at all.
2073
2336
  */
2074
2337
  can_edit_environment?: boolean;
2075
2338
  /**
2076
- * Can promote environments to primary and manage maintenance mode
2339
+ * Can promote a sandbox environment to primary (atomic swap) and toggle the project's maintenance mode. Distinct from `can_manage_environments`, which covers creating/forking/deleting sandboxes.
2077
2340
  */
2078
2341
  can_promote_environments?: boolean;
2079
2342
  /**
@@ -2105,7 +2368,7 @@ export type RoleCreateSchema = {
2105
2368
  */
2106
2369
  can_manage_webhooks?: boolean;
2107
2370
  /**
2108
- * Can create and delete sandbox environments and promote them to primary environment
2371
+ * Can create, fork, and delete sandbox environments. Promotion to primary is gated separately by `can_promote_environments`.
2109
2372
  */
2110
2373
  can_manage_environments?: boolean;
2111
2374
  /**
@@ -2137,125 +2400,47 @@ export type RoleCreateSchema = {
2137
2400
  */
2138
2401
  can_access_search_index_events_log?: boolean;
2139
2402
  /**
2140
- * Allowed actions on a model (or all) for a role
2403
+ * Allowed actions on a model (or all) for a role.
2404
+ *
2405
+ * The shape of each entry depends on the `action` (discriminated union). Idiomatic recipes:
2406
+ * - To grant every action, use a single `action: "all"` entry with `localization_scope: "all"`.
2407
+ * - To grant a subset (e.g. create+read+update but not delete), prefer a single `action: "all"` entry plus `negative_item_type_permissions` entries for the actions to exclude — instead of listing each allowed action separately.
2141
2408
  */
2142
- positive_item_type_permissions?: {
2143
- item_type?: ItemTypeIdentity | null;
2144
- workflow?: WorkflowIdentity | null;
2145
- on_stage?: null | string;
2146
- to_stage?: null | string;
2147
- environment: EnvironmentIdentity;
2148
- /**
2149
- * Permitted action
2150
- */
2151
- action: 'all' | 'read' | 'update' | 'create' | 'duplicate' | 'delete' | 'publish' | 'edit_creator' | 'take_over' | 'move_to_stage';
2152
- /**
2153
- * Permitted creator
2154
- */
2155
- on_creator?: 'anyone' | 'self' | 'role' | null;
2156
- /**
2157
- * Permitted content scope
2158
- */
2159
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
2160
- /**
2161
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
2162
- */
2163
- locale?: string | null;
2164
- }[];
2409
+ positive_item_type_permissions?: (RoleItemTypePermissionAll | RoleItemTypePermissionRead | RoleItemTypePermissionCreate | RoleItemTypePermissionUpdateOrPublish | RoleItemTypePermissionDuplicate | RoleItemTypePermissionDeleteOrEditCreatorOrTakeOver | RoleItemTypePermissionMoveToStage)[];
2165
2410
  /**
2166
- * Prohibited actions on a model (or all) for a role
2411
+ * Prohibited actions on a model (or all) for a role. Negative permissions take precedence and are typically paired with a broader positive `action: "all"` entry to subtract specific actions (e.g. forbid `delete`).
2167
2412
  */
2168
- negative_item_type_permissions?: {
2169
- item_type?: ItemTypeIdentity | null;
2170
- workflow?: WorkflowIdentity | null;
2171
- on_stage?: null | string;
2172
- to_stage?: null | string;
2173
- environment: EnvironmentIdentity;
2174
- /**
2175
- * Permitted action
2176
- */
2177
- action: 'all' | 'read' | 'update' | 'create' | 'duplicate' | 'delete' | 'publish' | 'edit_creator' | 'take_over' | 'move_to_stage';
2178
- /**
2179
- * Permitted creator
2180
- */
2181
- on_creator?: 'anyone' | 'self' | 'role' | null;
2182
- /**
2183
- * Permitted content scope
2184
- */
2185
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
2186
- /**
2187
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
2188
- */
2189
- locale?: string | null;
2190
- }[];
2413
+ negative_item_type_permissions?: (RoleItemTypePermissionAll | RoleItemTypePermissionRead | RoleItemTypePermissionCreate | RoleItemTypePermissionUpdateOrPublish | RoleItemTypePermissionDuplicate | RoleItemTypePermissionDeleteOrEditCreatorOrTakeOver | RoleItemTypePermissionMoveToStage)[];
2191
2414
  /**
2192
- * Allowed actions on a model (or all) for a role
2415
+ * Allowed actions on uploads (or all) for a role.
2416
+ *
2417
+ * The shape of each entry depends on the `action` (discriminated union). To grant a subset, prefer a single `action: "all"` entry plus `negative_upload_permissions` entries for the actions to exclude.
2193
2418
  */
2194
- positive_upload_permissions?: {
2195
- environment: EnvironmentIdentity;
2196
- /**
2197
- * Permitted action
2198
- */
2199
- action: 'all' | 'read' | 'update' | 'create' | 'delete' | 'edit_creator' | 'replace_asset' | 'move';
2200
- /**
2201
- * Permitted creator
2202
- */
2203
- on_creator?: 'anyone' | 'self' | 'role' | null;
2204
- /**
2205
- * Permitted content scope
2206
- */
2207
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
2208
- /**
2209
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
2210
- */
2211
- locale?: string | null;
2212
- upload_collection?: UploadCollectionIdentity | null;
2213
- move_to_upload_collection?: UploadCollectionIdentity | null;
2214
- }[];
2419
+ positive_upload_permissions?: (RoleUploadPermissionAll | RoleUploadPermissionUpdate | RoleUploadPermissionCreate | RoleUploadPermissionReadOrDeleteOrEditCreatorOrReplaceAsset | RoleUploadPermissionMove)[];
2215
2420
  /**
2216
- * Prohibited actions on a model (or all) for a role
2421
+ * Prohibited actions on uploads (or all) for a role. Negative permissions take precedence and are typically paired with a broader positive `action: "all"` entry to subtract specific actions.
2217
2422
  */
2218
- negative_upload_permissions?: {
2219
- environment: EnvironmentIdentity;
2220
- /**
2221
- * Permitted action
2222
- */
2223
- action: 'all' | 'read' | 'update' | 'create' | 'delete' | 'edit_creator' | 'replace_asset' | 'move';
2224
- /**
2225
- * Permitted creator
2226
- */
2227
- on_creator?: 'anyone' | 'self' | 'role' | null;
2228
- /**
2229
- * Permitted content scope
2230
- */
2231
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
2232
- /**
2233
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
2234
- */
2235
- locale?: string | null;
2236
- upload_collection?: UploadCollectionIdentity | null;
2237
- move_to_upload_collection?: UploadCollectionIdentity | null;
2238
- }[];
2423
+ negative_upload_permissions?: (RoleUploadPermissionAll | RoleUploadPermissionUpdate | RoleUploadPermissionCreate | RoleUploadPermissionReadOrDeleteOrEditCreatorOrReplaceAsset | RoleUploadPermissionMove)[];
2239
2424
  /**
2240
- * Allowed build triggers for a role
2425
+ * Build triggers this role is allowed to **manually fire**. An entry with `build_trigger: null` covers every build trigger. Note: this does not control creating/editing build triggers themselves that is gated by `can_manage_build_triggers`.
2241
2426
  */
2242
2427
  positive_build_trigger_permissions?: {
2243
2428
  build_trigger?: BuildTriggerIdentity | null;
2244
2429
  }[];
2245
2430
  /**
2246
- * Prohibited build triggers for a role
2431
+ * Build triggers this role is **forbidden** from manually firing. Negative entries take precedence over positive ones; pair with a `build_trigger: null` positive entry to allow all-but-N.
2247
2432
  */
2248
2433
  negative_build_trigger_permissions?: {
2249
2434
  build_trigger?: BuildTriggerIdentity | null;
2250
2435
  }[];
2251
2436
  /**
2252
- * Search indexes that can be triggered by a role
2437
+ * Search indexes this role is allowed to **manually re-index**. An entry with `search_index: null` covers every search index. Note: this does not control creating/editing search indexes themselves — that is gated by `can_manage_search_indexes`.
2253
2438
  */
2254
2439
  positive_search_index_permissions?: {
2255
2440
  search_index?: SearchIndexIdentity | null;
2256
2441
  }[];
2257
2442
  /**
2258
- * Search indexes that can't be triggered by a role
2443
+ * Search indexes this role is **forbidden** from manually re-indexing. Negative entries take precedence over positive ones; pair with a `search_index: null` positive entry to allow all-but-N.
2259
2444
  */
2260
2445
  negative_search_index_permissions?: {
2261
2446
  search_index?: SearchIndexIdentity | null;
@@ -2303,11 +2488,11 @@ export type RoleUpdateSchema = {
2303
2488
  */
2304
2489
  can_edit_favicon?: boolean;
2305
2490
  /**
2306
- * Can change project global properties
2491
+ * Can change project-wide settings (project name, internal subdomain, frontend preview URL, deployment settings)
2307
2492
  */
2308
2493
  can_edit_site?: boolean;
2309
2494
  /**
2310
- * Can create and edit models and plugins
2495
+ * Can create and edit the project schema: models, block models, fields, fieldsets, validators, and plugins
2311
2496
  */
2312
2497
  can_edit_schema?: boolean;
2313
2498
  /**
@@ -2315,11 +2500,11 @@ export type RoleUpdateSchema = {
2315
2500
  */
2316
2501
  can_manage_menu?: boolean;
2317
2502
  /**
2318
- * Can change locales, timezone and UI theme
2503
+ * Can edit per-environment settings of the environments this role has access to: locales, timezone, and UI theme. This is *not* about creating or switching environments — see `can_manage_environments` for that, and `environments_access` for which environments this role can enter at all.
2319
2504
  */
2320
2505
  can_edit_environment?: boolean;
2321
2506
  /**
2322
- * Can promote environments to primary and manage maintenance mode
2507
+ * Can promote a sandbox environment to primary (atomic swap) and toggle the project's maintenance mode. Distinct from `can_manage_environments`, which covers creating/forking/deleting sandboxes.
2323
2508
  */
2324
2509
  can_promote_environments?: boolean;
2325
2510
  /**
@@ -2351,7 +2536,7 @@ export type RoleUpdateSchema = {
2351
2536
  */
2352
2537
  can_manage_webhooks?: boolean;
2353
2538
  /**
2354
- * Can create and delete sandbox environments and promote them to primary environment
2539
+ * Can create, fork, and delete sandbox environments. Promotion to primary is gated separately by `can_promote_environments`.
2355
2540
  */
2356
2541
  can_manage_environments?: boolean;
2357
2542
  /**
@@ -2383,125 +2568,47 @@ export type RoleUpdateSchema = {
2383
2568
  */
2384
2569
  can_access_search_index_events_log?: boolean;
2385
2570
  /**
2386
- * Allowed actions on a model (or all) for a role
2571
+ * Allowed actions on a model (or all) for a role.
2572
+ *
2573
+ * The shape of each entry depends on the `action` (discriminated union). Idiomatic recipes:
2574
+ * - To grant every action, use a single `action: "all"` entry with `localization_scope: "all"`.
2575
+ * - To grant a subset (e.g. create+read+update but not delete), prefer a single `action: "all"` entry plus `negative_item_type_permissions` entries for the actions to exclude — instead of listing each allowed action separately.
2387
2576
  */
2388
- positive_item_type_permissions?: {
2389
- item_type?: ItemTypeIdentity | null;
2390
- workflow?: WorkflowIdentity | null;
2391
- on_stage?: null | string;
2392
- to_stage?: null | string;
2393
- environment: EnvironmentIdentity;
2394
- /**
2395
- * Permitted action
2396
- */
2397
- action: 'all' | 'read' | 'update' | 'create' | 'duplicate' | 'delete' | 'publish' | 'edit_creator' | 'take_over' | 'move_to_stage';
2398
- /**
2399
- * Permitted creator
2400
- */
2401
- on_creator?: 'anyone' | 'self' | 'role' | null;
2402
- /**
2403
- * Permitted content scope
2404
- */
2405
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
2406
- /**
2407
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
2408
- */
2409
- locale?: string | null;
2410
- }[];
2577
+ positive_item_type_permissions?: (RoleItemTypePermissionAll | RoleItemTypePermissionRead | RoleItemTypePermissionCreate | RoleItemTypePermissionUpdateOrPublish | RoleItemTypePermissionDuplicate | RoleItemTypePermissionDeleteOrEditCreatorOrTakeOver | RoleItemTypePermissionMoveToStage)[];
2411
2578
  /**
2412
- * Prohibited actions on a model (or all) for a role
2579
+ * Prohibited actions on a model (or all) for a role. Negative permissions take precedence and are typically paired with a broader positive `action: "all"` entry to subtract specific actions (e.g. forbid `delete`).
2413
2580
  */
2414
- negative_item_type_permissions?: {
2415
- item_type?: ItemTypeIdentity | null;
2416
- workflow?: WorkflowIdentity | null;
2417
- on_stage?: null | string;
2418
- to_stage?: null | string;
2419
- environment: EnvironmentIdentity;
2420
- /**
2421
- * Permitted action
2422
- */
2423
- action: 'all' | 'read' | 'update' | 'create' | 'duplicate' | 'delete' | 'publish' | 'edit_creator' | 'take_over' | 'move_to_stage';
2424
- /**
2425
- * Permitted creator
2426
- */
2427
- on_creator?: 'anyone' | 'self' | 'role' | null;
2428
- /**
2429
- * Permitted content scope
2430
- */
2431
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
2432
- /**
2433
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
2434
- */
2435
- locale?: string | null;
2436
- }[];
2581
+ negative_item_type_permissions?: (RoleItemTypePermissionAll | RoleItemTypePermissionRead | RoleItemTypePermissionCreate | RoleItemTypePermissionUpdateOrPublish | RoleItemTypePermissionDuplicate | RoleItemTypePermissionDeleteOrEditCreatorOrTakeOver | RoleItemTypePermissionMoveToStage)[];
2437
2582
  /**
2438
- * Allowed actions on a model (or all) for a role
2583
+ * Allowed actions on uploads (or all) for a role.
2584
+ *
2585
+ * The shape of each entry depends on the `action` (discriminated union). To grant a subset, prefer a single `action: "all"` entry plus `negative_upload_permissions` entries for the actions to exclude.
2439
2586
  */
2440
- positive_upload_permissions?: {
2441
- environment: EnvironmentIdentity;
2442
- /**
2443
- * Permitted action
2444
- */
2445
- action: 'all' | 'read' | 'update' | 'create' | 'delete' | 'edit_creator' | 'replace_asset' | 'move';
2446
- /**
2447
- * Permitted creator
2448
- */
2449
- on_creator?: 'anyone' | 'self' | 'role' | null;
2450
- /**
2451
- * Permitted content scope
2452
- */
2453
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
2454
- /**
2455
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
2456
- */
2457
- locale?: string | null;
2458
- upload_collection?: UploadCollectionIdentity | null;
2459
- move_to_upload_collection?: UploadCollectionIdentity | null;
2460
- }[];
2587
+ positive_upload_permissions?: (RoleUploadPermissionAll | RoleUploadPermissionUpdate | RoleUploadPermissionCreate | RoleUploadPermissionReadOrDeleteOrEditCreatorOrReplaceAsset | RoleUploadPermissionMove)[];
2461
2588
  /**
2462
- * Prohibited actions on a model (or all) for a role
2589
+ * Prohibited actions on uploads (or all) for a role. Negative permissions take precedence and are typically paired with a broader positive `action: "all"` entry to subtract specific actions.
2463
2590
  */
2464
- negative_upload_permissions?: {
2465
- environment: EnvironmentIdentity;
2466
- /**
2467
- * Permitted action
2468
- */
2469
- action: 'all' | 'read' | 'update' | 'create' | 'delete' | 'edit_creator' | 'replace_asset' | 'move';
2470
- /**
2471
- * Permitted creator
2472
- */
2473
- on_creator?: 'anyone' | 'self' | 'role' | null;
2474
- /**
2475
- * Permitted content scope
2476
- */
2477
- localization_scope?: 'all' | 'localized' | 'not_localized' | null;
2478
- /**
2479
- * Permitted localized content in this locale. Required when `localization_scope` is `localized`
2480
- */
2481
- locale?: string | null;
2482
- upload_collection?: UploadCollectionIdentity | null;
2483
- move_to_upload_collection?: UploadCollectionIdentity | null;
2484
- }[];
2591
+ negative_upload_permissions?: (RoleUploadPermissionAll | RoleUploadPermissionUpdate | RoleUploadPermissionCreate | RoleUploadPermissionReadOrDeleteOrEditCreatorOrReplaceAsset | RoleUploadPermissionMove)[];
2485
2592
  /**
2486
- * Allowed build triggers for a role
2593
+ * Build triggers this role is allowed to **manually fire**. An entry with `build_trigger: null` covers every build trigger. Note: this does not control creating/editing build triggers themselves that is gated by `can_manage_build_triggers`.
2487
2594
  */
2488
2595
  positive_build_trigger_permissions?: {
2489
2596
  build_trigger?: BuildTriggerIdentity | null;
2490
2597
  }[];
2491
2598
  /**
2492
- * Prohibited build triggers for a role
2599
+ * Build triggers this role is **forbidden** from manually firing. Negative entries take precedence over positive ones; pair with a `build_trigger: null` positive entry to allow all-but-N.
2493
2600
  */
2494
2601
  negative_build_trigger_permissions?: {
2495
2602
  build_trigger?: BuildTriggerIdentity | null;
2496
2603
  }[];
2497
2604
  /**
2498
- * Search indexes that can be triggered by a role
2605
+ * Search indexes this role is allowed to **manually re-index**. An entry with `search_index: null` covers every search index. Note: this does not control creating/editing search indexes themselves — that is gated by `can_manage_search_indexes`.
2499
2606
  */
2500
2607
  positive_search_index_permissions?: {
2501
2608
  search_index?: SearchIndexIdentity | null;
2502
2609
  }[];
2503
2610
  /**
2504
- * Search indexes that can't be triggered by a role
2611
+ * Search indexes this role is **forbidden** from manually re-indexing. Negative entries take precedence over positive ones; pair with a `search_index: null` positive entry to allow all-but-N.
2505
2612
  */
2506
2613
  negative_search_index_permissions?: {
2507
2614
  search_index?: SearchIndexIdentity | null;
@@ -2805,7 +2912,16 @@ export type SsoUserDestroyTargetSchema = {
2805
2912
  data: SsoUser;
2806
2913
  };
2807
2914
  /**
2808
- * An API token allows access to our API. It is linked to a Role, which describes what actions can be performed.
2915
+ * An API token authenticates programmatic access to a project. Each token combines two layers of access control:
2916
+ *
2917
+ * 1. A **Role** that defines what actions are permitted (the same Role resource used for human collaborators).
2918
+ * 2. A set of **API surface flags** (`can_access_cda`, `can_access_cda_preview`, `can_access_cma`) that gate which APIs the token can hit at all.
2919
+ *
2920
+ * The token's effective capabilities are the *intersection* of the two.
2921
+ *
2922
+ * > [!PROTIP] 💡 A CDA-only token can safely reuse a write-capable Role
2923
+ * > A token with only `can_access_cda: true` is safe to attach to a Role that grants `update`/`publish`/`delete` — the Content Delivery API exposes no write endpoints, so those actions have no surface to act on. This makes it practical to share a single Role definition between an editor (acting via the dashboard / CMA) and a public read token (used by a frontend / CDA) for the same project.
2924
+ *
2809
2925
  *
2810
2926
  * This interface was referenced by `DatoApi`'s JSON-Schema
2811
2927
  * via the `definition` "access_token".
@@ -2828,21 +2944,24 @@ export type AccessTokenAttributes = {
2828
2944
  */
2829
2945
  name: string;
2830
2946
  /**
2831
- * The actual API token (or null if the current user has no permission to read the token)
2947
+ * The secret value used as the `Authorization: Bearer <token>` credential. Returned on every endpoint (create, update, retrieve, list, rotate) to callers whose current role has `can_manage_access_tokens`; otherwise `null`.
2832
2948
  */
2833
2949
  token?: null | string;
2834
2950
  /**
2835
- * Whether this API token can access the Content Delivery API published content endpoint
2951
+ * Whether this API token can call the Content Delivery API (`graphql.datocms.com`) to fetch **published** content.
2836
2952
  */
2837
2953
  can_access_cda: boolean;
2838
2954
  /**
2839
- * Whether this API token can access the Content Delivery API draft content endpoint
2955
+ * Whether this API token can call the Content Delivery API with the `X-Include-Drafts: true` header to fetch **draft** (current, unpublished) content. There is no separate endpoint — the CDA is a single GraphQL endpoint and this flag governs whether requesting drafts is allowed.
2840
2956
  */
2841
2957
  can_access_cda_preview: boolean;
2842
2958
  /**
2843
2959
  * Whether this API token can access the Content Management API
2844
2960
  */
2845
2961
  can_access_cma: boolean;
2962
+ /**
2963
+ * Internal marker for the project's built-in factory tokens (e.g. read-only API token), seeded by DatoCMS when the project is created. Read-only attribute. When non-null, attribute updates are rejected with `NON_EDITABLE_ACCESS_TOKEN`, but the token can still be deleted and regenerated. `null` for any token created via this API.
2964
+ */
2846
2965
  hardcoded_type: null | string;
2847
2966
  /**
2848
2967
  * When this API token was last used to access the Content Management API
@@ -2890,11 +3009,11 @@ export type AccessTokenCreateSchema = {
2890
3009
  */
2891
3010
  name: string;
2892
3011
  /**
2893
- * Whether this API token can access the Content Delivery API published content endpoint
3012
+ * Whether this API token can call the Content Delivery API (`graphql.datocms.com`) to fetch **published** content.
2894
3013
  */
2895
3014
  can_access_cda: boolean;
2896
3015
  /**
2897
- * Whether this API token can access the Content Delivery API draft content endpoint
3016
+ * Whether this API token can call the Content Delivery API with the `X-Include-Drafts: true` header to fetch **draft** (current, unpublished) content. There is no separate endpoint — the CDA is a single GraphQL endpoint and this flag governs whether requesting drafts is allowed.
2898
3017
  */
2899
3018
  can_access_cda_preview: boolean;
2900
3019
  /**
@@ -2907,7 +3026,7 @@ export type AccessTokenCreateSchema = {
2907
3026
  * Role
2908
3027
  */
2909
3028
  role: {
2910
- data: RoleData | null;
3029
+ data: RoleData;
2911
3030
  };
2912
3031
  };
2913
3032
  };
@@ -2933,11 +3052,11 @@ export type AccessTokenUpdateSchema = {
2933
3052
  */
2934
3053
  name: string;
2935
3054
  /**
2936
- * Whether this API token can access the Content Delivery API published content endpoint
3055
+ * Whether this API token can call the Content Delivery API (`graphql.datocms.com`) to fetch **published** content.
2937
3056
  */
2938
3057
  can_access_cda: boolean;
2939
3058
  /**
2940
- * Whether this API token can access the Content Delivery API draft content endpoint
3059
+ * Whether this API token can call the Content Delivery API with the `X-Include-Drafts: true` header to fetch **draft** (current, unpublished) content. There is no separate endpoint — the CDA is a single GraphQL endpoint and this flag governs whether requesting drafts is allowed.
2941
3060
  */
2942
3061
  can_access_cda_preview: boolean;
2943
3062
  /**
@@ -2945,12 +3064,12 @@ export type AccessTokenUpdateSchema = {
2945
3064
  */
2946
3065
  can_access_cma: boolean;
2947
3066
  };
2948
- relationships: {
3067
+ relationships?: {
2949
3068
  /**
2950
3069
  * Role
2951
3070
  */
2952
3071
  role: {
2953
- data: RoleData | null;
3072
+ data: RoleData;
2954
3073
  };
2955
3074
  };
2956
3075
  };