Skip to Content
API ReferenceGovernance

Governance API

The Governance module provides fine-grained access control and compliance features including role-based access control (RBAC), user groups, destination policies, access policies, and deletion rules.

Endpoint Groups

GroupDescription
RolesSystem and custom role management
PermissionsGranular permission definitions
GroupsUser group management
MembersGroup membership management
Destination PoliciesSync-time governance policies
Access PoliciesData row-level access restrictions
Deletion RulesAudience-scoped warehouse deletion with audit logs

Roles

Roles define sets of permissions that can be assigned to workspace members or groups. Zeotap includes three built-in system roles (owner, admin, member) and supports custom roles.

MethodPathDescription
GET/api/v1/workspaces/{id}/rolesList all roles
POST/api/v1/workspaces/{id}/rolesCreate a custom role
GET/api/v1/workspaces/{id}/roles/{roleId}Get a role with permissions
PUT/api/v1/workspaces/{id}/roles/{roleId}Update a custom role
DELETE/api/v1/workspaces/{id}/roles/{roleId}Delete a custom role

List Roles

GET /api/v1/workspaces/{id}/roles

[ { "id": "00000000-0000-0000-0000-000000000001", "workspace_id": null, "name": "owner", "description": "Full access to all workspace resources", "is_system": true, "permissions": ["sources.read", "sources.write", "sources.delete", "..."], "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" }, { "id": "550e8400-e29b-41d4-a716-446655440000", "workspace_id": "660e8400-e29b-41d4-a716-446655440000", "name": "data_analyst", "description": "Read-only access to models and audiences", "is_system": false, "permissions": ["sources.read", "models.read", "audiences.read"], "created_at": "2024-01-15T09:30:00Z", "updated_at": "2024-01-15T09:30:00Z" } ]

Create Custom Role

POST /api/v1/workspaces/{id}/roles

Request Body

FieldTypeRequiredDescription
namestringYesRole name (must be unique within workspace)
descriptionstringNoDescription of the role’s purpose
permissionsarray of stringsYesPermission keys to grant
{ "name": "data_analyst", "description": "Read-only access to models and audiences", "permissions": [ "sources.read", "models.read", "audiences.read", "traits.read", "insights.read" ] }

System Roles

RoleIDDescription
owner00000000-0000-0000-0000-000000000001Full access; can manage billing and workspace settings
admin00000000-0000-0000-0000-000000000002Full access except billing and ownership transfer
member00000000-0000-0000-0000-000000000003Standard access; cannot manage workspace settings

Permissions

Permissions are granular access control strings organized by category.

MethodPathDescription
GET/api/v1/permissionsList all available permissions (global catalog)
GET/api/v1/workspaces/{id}/permissions/meGet the caller’s permissions in this workspace

Response

[ { "id": "550e8400-e29b-41d4-a716-446655440000", "key": "sources.read", "category": "sources", "description": "View sources and connection details", "created_at": "2024-01-01T00:00:00Z" }, { "id": "660e8400-e29b-41d4-a716-446655440000", "key": "sources.write", "category": "sources", "description": "Create and update sources", "created_at": "2024-01-01T00:00:00Z" } ]

Permission Categories

CategoryPermissionsDescription
sourcesread, write, deleteData warehouse connections
modelsread, write, deleteSQL models
destinationsread, write, deleteWrite targets
syncsread, write, delete, triggerReverse ETL pipelines
audiencesread, write, deleteAudiences
traitsread, write, deleteComputed attributes
identity_graphsread, write, delete, triggerIdentity resolution graphs
journeysread, write, delete, activateOrchestration workflows
eventsread, write, deleteStreams (real-time event collection)
loadersread, write, delete, triggerData loaders
governanceread, writeRBAC and compliance
insightsreadAnalytics and monitoring
workspaceread, write, membersWorkspace settings

Groups

Groups organize workspace members and can be assigned a role that applies to all members.

MethodPathDescription
GET/api/v1/workspaces/{id}/groupsList all groups
POST/api/v1/workspaces/{id}/groupsCreate a group
GET/api/v1/workspaces/{id}/groups/{groupId}Get a group
PUT/api/v1/workspaces/{id}/groups/{groupId}Update a group
DELETE/api/v1/workspaces/{id}/groups/{groupId}Delete a group

Create Group

POST /api/v1/workspaces/{id}/groups

{ "name": "Marketing Team", "description": "Marketing department members", "role_id": "550e8400-e29b-41d4-a716-446655440000" }

Group Object

FieldTypeDescription
idstring (UUID)Unique identifier
workspace_idstring (UUID)Owning workspace
namestringGroup name
descriptionstringDescription
role_idstring (UUID) or nullRole assigned to group members
role_namestringName of the assigned role
member_countintegerNumber of members in the group
created_atstring (ISO 8601)Creation timestamp
updated_atstring (ISO 8601)Last update timestamp

Members

Manage group membership.

MethodPathDescription
GET/api/v1/workspaces/{id}/groups/{groupId}/membersList group members
POST/api/v1/workspaces/{id}/groups/{groupId}/membersAdd a member
DELETE/api/v1/workspaces/{id}/groups/{groupId}/members/{accountId}Remove a member

Add Member

POST /api/v1/workspaces/{id}/groups/{groupId}/members

{ "account_id": "770e8400-e29b-41d4-a716-446655440000" }

Group Member Object

FieldTypeDescription
group_idstring (UUID)Group ID
account_idstring (UUID)Account ID
emailstringMember email
namestringMember name
avatar_urlstringMember avatar URL
created_atstring (ISO 8601)When the member was added

Destination Policies

Destination policies are sync-time governance policies that restrict which records can be sent to specific destination types. They act as guardrails to prevent sensitive data from reaching certain platforms. The API path remains destination-rules for backwards compatibility.

MethodPathDescription
GET/api/v1/workspaces/{id}/destination-rulesList all destination policies
POST/api/v1/workspaces/{id}/destination-rulesCreate a destination policy
GET/api/v1/workspaces/{id}/destination-rules/{ruleId}Get a destination policy
PUT/api/v1/workspaces/{id}/destination-rules/{ruleId}Update a destination policy
DELETE/api/v1/workspaces/{id}/destination-rules/{ruleId}Delete a destination policy
GET/api/v1/workspaces/{id}/destination-types/{destType}/rulesList destination policies by destination type

Create Destination Policy

POST /api/v1/workspaces/{id}/destination-rules

{ "name": "GDPR - No EU Customers to Facebook", "description": "Prevent EU customer data from being synced to Facebook Ads", "parent_model_id": "770e8400-e29b-41d4-a716-446655440000", "destination_type": "facebook_ads", "filter_tree": { "type": "condition", "condition_type": "property", "column": "country", "operator": "not_in", "value": ["DE", "FR", "IT", "ES", "NL", "BE", "AT", "SE", "DK", "FI"] }, "enabled": true }

Destination Policy Object

FieldTypeDescription
idstring (UUID)Unique identifier
workspace_idstring (UUID)Owning workspace
parent_model_idstring (UUID)Model the policy applies to
destination_typestringDestination type this policy restricts
namestringDisplay name
descriptionstringDescription
filter_treeobjectFilter criteria (same format as audience filters)
enabledbooleanWhether the policy is active
created_bystring (UUID)Account that created the policy
created_atstring (ISO 8601)Creation timestamp
updated_atstring (ISO 8601)Last update timestamp

Access Policies

Access Policies provide row-level access control by restricting which records a user or group can see. They use filter trees (same as audiences) to define visibility boundaries. The API path remains subsets for backwards compatibility.

Access Policy Categories

Categories organize access policies into logical groups (e.g., Region, Brand, Business Unit).

MethodPathDescription
GET/api/v1/workspaces/{id}/subset-categoriesList categories
GET/api/v1/workspaces/{id}/subset-categories/{catId}Get a category
POST/api/v1/workspaces/{id}/subset-categoriesCreate a category
PUT/api/v1/workspaces/{id}/subset-categories/{catId}Update a category
DELETE/api/v1/workspaces/{id}/subset-categories/{catId}Delete a category

Access Policy Endpoints

MethodPathDescription
GET/api/v1/workspaces/{id}/subsetsList all access policies
GET/api/v1/workspaces/{id}/subsets/meList access policies that apply to the caller
POST/api/v1/workspaces/{id}/subsetsCreate an access policy
GET/api/v1/workspaces/{id}/subsets/{subsetId}Get an access policy
PUT/api/v1/workspaces/{id}/subsets/{subsetId}Update an access policy
DELETE/api/v1/workspaces/{id}/subsets/{subsetId}Delete an access policy

Create Access Policy

{ "name": "US Region", "description": "Only US customer records", "category_id": "550e8400-e29b-41d4-a716-446655440000", "parent_model_id": "770e8400-e29b-41d4-a716-446655440000", "filter_tree": { "type": "condition", "condition_type": "property", "column": "country", "operator": "equals", "value": "US" } }

Access Policy Assignments

Assign access policies to groups to restrict their data visibility. Assignments are nested under each access policy.

MethodPathDescription
GET/api/v1/workspaces/{id}/subsets/{subsetId}/assignmentsList assignments for an access policy
POST/api/v1/workspaces/{id}/subsets/{subsetId}/assignmentsCreate an assignment
DELETE/api/v1/workspaces/{id}/subsets/{subsetId}/assignments/{assignmentId}Remove an assignment
GET/api/v1/workspaces/{id}/groups/{groupId}/subsetsList access policies assigned to a group
PUT/api/v1/workspaces/{id}/groups/{groupId}/subsetsReplace the set of access policies assigned to a group

Create Assignment

{ "group_id": "aae8400-e29b-41d4-a716-446655440000" }

Access Policy Object

FieldTypeDescription
idstring (UUID)Unique identifier
category_idstring (UUID)Parent category
workspace_idstring (UUID)Owning workspace
parent_model_idstring (UUID) or nullModel the access policy applies to
namestringDisplay name
descriptionstringDescription
filter_treeobjectFilter criteria
created_bystring (UUID)Account that created the access policy
created_atstring (ISO 8601)Creation timestamp
updated_atstring (ISO 8601)Last update timestamp

Deletion Rules

Deletion rules erase warehouse data for an audience-scoped population, on demand or on a schedule, and record every run in an audit log. See Deletion Rules for the eligibility rules and safety controls.

MethodPathDescription
GET/api/v1/workspaces/{id}/deletion-rulesList all deletion rules
POST/api/v1/workspaces/{id}/deletion-rulesCreate a deletion rule
POST/api/v1/workspaces/{id}/deletion-rules/impactResolve what else reads a candidate target list
GET/api/v1/workspaces/{id}/deletion-rules/{ruleId}Get a deletion rule
PUT/api/v1/workspaces/{id}/deletion-rules/{ruleId}Update a deletion rule
DELETE/api/v1/workspaces/{id}/deletion-rules/{ruleId}Delete a deletion rule (its log is retained)
POST/api/v1/workspaces/{id}/deletion-rules/{ruleId}/dry-runStart a non-destructive run
POST/api/v1/workspaces/{id}/deletion-rules/{ruleId}/runStart a live run
GET/api/v1/workspaces/{id}/deletion-rules/{ruleId}/runsList a rule’s runs
GET/api/v1/workspaces/{id}/deletion-runsList the workspace deletion log
GET/api/v1/workspaces/{id}/deletion-runs/{runId}Get one run with per-target detail

Reads require deletion_rules.read, writes deletion_rules.write, and both run endpoints deletion_rules.execute.

Every endpoint additionally requires the workspace to have the Deletion Rules feature enabled by a platform administrator; otherwise they answer 403 deletion rules are not enabled for this workspace. See Availability.

Eligibility and safety refusals — an ineligible target, an empty filter, a column that cannot be cleared, a pinned join that has since drifted — answer 400 with the specific reason in error. Read it: it names the target and says what is wrong with it, which is the only place that information exists.

Create Deletion Rule

POST /api/v1/workspaces/{id}/deletion-rules

filter_tree is required and must carry at least one condition — a rule may not match every record by default. dry_run defaults to true and enabled to false, so omitting them creates an observe-only rule.

{ "parent_model_id": "770e8400-e29b-41d4-a716-446655440000", "name": "Erase opted-out EU customers", "description": "Fulfils standing right-to-erasure requests for EU opt-outs.", "filter_tree": { "type": "and", "children": [ { "type": "condition", "condition_type": "property", "field": "region", "operator": "equals", "value": "EU" }, { "type": "condition", "condition_type": "property", "field": "erasure_requested", "operator": "equals", "value": true } ] }, "targets": [ { "model_id": "770e8400-e29b-41d4-a716-446655440000", "action": "delete_rows" }, { "model_id": "881e8400-e29b-41d4-a716-446655440000", "action": "null_columns", "columns": ["shipping_address", "phone"] } ], "schedule": "0 3 * * *", "dry_run": true, "enabled": false }

Deletion Rule Object

FieldTypeDescription
idstring (UUID)Unique identifier
workspace_idstring (UUID)Owning workspace
parent_model_idstring (UUID)Model defining the entity the rule erases
namestringDisplay name (unique per workspace)
descriptionstringDescription
filter_treeobjectMatch criteria (same format as audience filters)
targetsarrayTarget selections — see below
schedulestringCron expression, optionally CRON_TZ=-prefixed. Empty means manual only
enabledbooleanRequired for any live deletion
dry_runbooleanObserve mode: every run reports and mutates nothing
last_run_atstring (ISO 8601) or nullWhen the most recent run started
last_run_statusstringStatus of the most recent run
created_bystring (UUID)Account that created the rule
created_atstring (ISO 8601)Creation timestamp
updated_atstring (ISO 8601)Last update timestamp

Deletion Target Object

FieldTypeDescription
model_idstring (UUID)Target model. Must be the parent model or directly related to it, on the same warehouse, and backed by a warehouse table
actionstringdelete_rows (physical DELETE) or null_columns (UPDATE … = NULL)
columnsarray of stringRequired for null_columns. May not include the join key to the parent model or the target’s primary key

Trigger a Run

POST /api/v1/workspaces/{id}/deletion-rules/{ruleId}/run POST /api/v1/workspaces/{id}/deletion-rules/{ruleId}/dry-run

Both return 202 Accepted with the opened run in running state — the deletion continues past the request, so poll the run log to follow it. /dry-run never mutates, whatever the rule’s own dry_run value. /run returns 400 when the rule is disabled.

Deletion Run Object

FieldTypeDescription
idstring (UUID)Unique identifier
rule_idstring (UUID) or nullSource rule. null once the rule has been deleted
workspace_idstring (UUID)Owning workspace
rule_namestringRule name snapshotted at run time
rule_snapshotobjectParent model, filter tree, targets and schedule as they were at run time
trigger_typestringmanual or schedule
modestringdry_run or execute
statusstringrunning, completed, partial (some targets failed), or failed
matched_countintegerRecords matched by the filter
records_affectedintegerRecords affected across all targets. In a dry run, records that would be
error_messagestringRun-level failure detail
initiated_bystring (UUID) or nullAccount that started the run
initiated_by_emailstringEmail snapshotted at run time, so the log stays attributable
started_atstring (ISO 8601)Start timestamp
completed_atstring (ISO 8601) or nullCompletion timestamp
targetsarrayPer-target outcomes — see below

Deletion Run Target Object

FieldTypeDescription
model_namestringTarget model name at run time
physical_tablestringFully qualified warehouse table
actionstringdelete_rows or null_columns
target_columnsarray of stringPhysical columns cleared
records_affectedintegerRecords affected. 0 on failure
statusstringcompleted, failed, or skipped
error_messagestringFailure detail for this target
statementstringThe statement executed — or, in a dry run, the statement that would be
executed_atstring (ISO 8601)When this target was processed
Last updated on