# (NEW!) Update Security Template Partially update a security, rights, or access template. Only the fields present in the body are changed. Business Rules: - type is not an updatable field. If present in the body, the request is rejected with 400. Type is fixed at creation because assets and metadata templates reference the template by id and assume its type. - At least one of name or groups must be present, or the request is rejected with 400. Unknown fields are also rejected with 400. - When groups is present, it is a full replacement of the template's group/permission set — omitted groups are removed, not left alone. - Every groups[].id and permissionIds[] entry must be a well-formed UUID and must exist for the customer (groups) or in the permission catalog (permissions). Unknown ids are rejected with 422. - name, if changed, is re-checked for uniqueness per customer. Optimistic Concurrency: - Opt-in via expectedLastUpdatedEpoch. If provided, it is compared against the template's current lastUpdatedEpoch; a mismatch is rejected with 409 and code: STALE_UPDATE. If omitted, the update proceeds last-write-wins. The response body is returned in the same shape as GET /security/templates/{id}. The user submitting the request must have the Security Template Management admin privilege. Endpoint: PATCH /security/templates/{templateId} Version: 1.5 Security: ApiKeyAuth, BasicAuth ## Header parameters: - `X-API-Key` (string, required) Customer-specific API key required to invoke API. - `Authorization` (string, required) Provided by Authentication Token creation operation. - `Content-Type` (string, required) Enum: "application/json" ## Path parameters: - `templateId` (string, required) The unique ID of the security template to update. Example: "a9380047-07d7-48aa-b4b7-474d00f0f428" ## Request fields (application/json): - `name` (string) Updated display name. Same validation as creation (trimmed, non-empty, maximum 75 characters); re-checked for uniqueness if changed. Example: "Confidential - Marketing" - `groups` (array) When present, this is a full replacement of the template's group/permission set — the service recomputes both stored columns from it. Omit to leave the current groups untouched. - `groups.id` (string, required) Group ID. Must exist for the authenticated customer. Example: "f22dccbc-6032-4279-9f19-d5dc91d9757e" - `groups.permissionIds` (array) IDs of the permissions granted to this group. An empty array means the group is present but grants nothing. Example: ["31bdde6b-1a2c-4d5e-8f90-1234567890ab"] - `expectedLastUpdatedEpoch` (integer) Optional optimistic-concurrency guard. When provided, it is compared against the template's current lastUpdatedEpoch; a mismatch is rejected with 409 and code: STALE_UPDATE. Omit for last-write-wins. Example: 1773070355217 ## Response 200 fields (application/json): - `id` (string) Unique ID of the template. Example: "a9380047-07d7-48aa-b4b7-474d00f0f428" - `name` (string) Display name of the template. Example: "Confidential" - `type` (string) Template classification. Set at creation and immutable thereafter. Enum: "security-template", "rights-template", "access-template" - `groupCount` (integer) Total number of groups on the template, across all pages. Example: 2 - `permissionCount` (integer) Total number of permissions granted across all groups, including the watermark permission. Example: 3 - `createdBy` (string) User ID of the template's creator. Example: "dc63db1b-1e63-43bc-877e-418931b6895c" - `createdEpoch` (integer) Unix timestamp (ms) of creation. Example: 1773070355217 - `createdDate` (string) ISO 8601 creation date. Example: "2026-03-09T15:32:35.217Z" - `lastUpdatedBy` (string) User ID of the user who last updated the template. Example: "dc63db1b-1e63-43bc-877e-418931b6895c" - `lastUpdatedEpoch` (integer) Unix timestamp (ms) of the last update. Pass this value back as expectedLastUpdatedEpoch on PATCH to guard against concurrent edits. Example: 1773070355217 - `lastUpdatedDate` (string) ISO 8601 last updated date. Example: "2026-03-09T15:32:35.217Z" - `groups` (object) Page of groups assigned to the template. - `groups.totalCount` (integer) Total number of groups on the template, across all pages. Example: 2 - `groups.items` (array) Groups on this page. - `groups.items.id` (string) Unique ID of the group. Example: "f22dccbc-6032-4279-9f19-d5dc91d9757e" - `groups.items.name` (string) Display name of the group. Example: "Marketing" - `groups.items.permissions` (array) Permissions evaluated against this group. Present only when includePermissions is true. - `groups.items.permissions.id` (string) Example: "31bdde6b-1a2c-4d5e-8f90-1234567890ab" - `groups.items.permissions.name` (string) Example: "View" - `groups.items.permissions.isPermitted` (boolean) Whether this group is granted the permission. Example: true - `groups.pageInfo` (object) Pagination metadata for groups.items. - `groups.pageInfo.hasNextPage` (boolean) Whether more groups exist beyond this page. - `groups.pageInfo.nextCursor` (string,null) Cursor for the next page of groups. Pass as groupCursor on the next request. Null if no more pages. ## Response 400 fields (application/json): - `message` (string) - `detail` (string) ## Response 401 fields (application/json): - `message` (string) - `detail` (string) ## Response 403 fields (application/json): - `message` (string) - `detail` (string) ## Response 404 fields (application/json): - `message` (string) - `detail` (string) ## Response 409 fields (application/json): - `message` (string) - `code` (string) Enum: "NAME_CONFLICT", "STALE_UPDATE" - `existingTemplateId` (string) Present only when code is NAME_CONFLICT. ## Response 422 fields (application/json): - `message` (string) - `invalidGroupIds` (array) - `invalidPermissionIds` (array)