Skip to Content

Roles

A role is a named set of permissions. Zeotap ships three built-in roles and lets you create custom ones with any combination of permissions.

A role is not held by a person — it is held by a grant, which gives one group one role on one workspace. Your permissions in a workspace are the union of the roles every group you belong to holds there. Custom roles belong to the organization, so a role is written once and can be granted in every workspace in it.

The Built-in Roles

RolePermissionsWho it is for
Owner119 of 120The person responsible for the workspace itself. The only role that can delete it.
Admin118 of 120 — everything but workspace.deleteTeam leads, data engineers, platform administrators.
Member49 of 120 — read across the platformAnalysts and marketers who work in the platform without configuring it.

Owner

Owner carries every permission but demo.seed, which no built-in role holds. workspace.delete is what separates Owner from Admin; in day-to-day work the two roles are identical.

Admin

Admin runs the platform: warehouses and destinations, models and audiences, events, journeys, identity graphs, loaders, governance policies, members, groups and custom roles. An Admin cannot delete the workspace.

Member

Member is a read role. A Member can open every part of the platform and see what is configured, what ran and what it produced, but the actions that create, change, delete or trigger something belong to Owner and Admin.

Three things a Member can do beyond reading: converse with the AI agent (agent.write), open the live event debugger (events.debug), and manage tags (tags.write).

Five reads belong to Owner and Admin: the workspace audit log (workspace_audit.read), workspace-wide agent token spend (agent.usage.read), and the three warehouse-infrastructure reads — warehouse_users.read, execution_environments.read and cdp_working_datasets.read, which are a platform or security owner’s concern. Grant any of them to a custom role where a workspace wants a Member to see them.

If your analysts need to build models or audiences themselves, that is a custom role — not a change to Member.

Custom Roles

A custom role is a name, a description and a list of permission keys. Nothing is implied or inherited: the role allows exactly the keys you list.

Creating a Custom Role

Organization settings → Roles, with the three system roles and a custom role as columns over the permission list

Via the UI

  1. Go to Organization settings → Roles
  2. Create a role and give it a name and description
  3. Tick the permissions it should carry — they are grouped by category
  4. Save

Via the API

curl -X POST "$API_BASE_URL/api/v1/organizations/$ORG_ID/roles" \ -H "Authorization: Bearer $API_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Marketing Analyst", "description": "Builds audiences over existing models", "permissions": [ "models.read", "audiences.read", "audiences.write", "traits.read", "traits.write", "audience_syncs.read", "destinations.read", "syncs.read" ] }'

POST returns 201 with the created role. roles.write is required, and Owner and Admin are the built-in roles that carry it.

Three Roles Worth Building

RolePermissions to grantWhat it gets you
Data engineersources.read, sources.write, connections.read, connections.write, models.read, models.write, loaders.read, loaders.write, warehouse_users.read, warehouse_users.write, warehouse_users.rotate, warehouse_users.delete, execution_environments.read, execution_environments.write, execution_environments.deleteOwns the warehouse side without touching destinations or governance
Marketing analystaudiences.read, audiences.write, traits.read, traits.write, splits.read, splits.write, priority_lists.read, priority_lists.write, models.read, destinations.read, syncs.readBuilds and segments without changing the pipeline underneath
Sync operatorsyncs.read, syncs.trigger, stores.read, stores.trigger, deletion_rules.read, deletion_rules.execute, models.read, destinations.readRuns and re-runs the pipeline without being able to redefine it

Every entry in a role’s permissions array is matched against the catalog exactly, so list the individual keys a category expands to. GET /api/v1/organizations/{orgId}/roles returns the role with the permissions it ended up carrying, which is the quickest way to confirm one reads as you intended.

The separate trigger and execute permissions are what make the third one possible — running a sync is grantable without granting the ability to change what the sync does.

Editing a Custom Role

Permission changes take effect on the member’s next request. Built-in roles cannot be edited.

curl -X PUT "$API_BASE_URL/api/v1/organizations/$ORG_ID/roles/$ROLE_ID" \ -H "Authorization: Bearer $API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "Marketing Analyst", "description": "…", "permissions": ["models.read", "audiences.read", "audiences.write"]}'

The permissions array replaces the role’s current set rather than adding to it.

Deleting a Custom Role

curl -X DELETE "$API_BASE_URL/api/v1/organizations/$ORG_ID/roles/$ROLE_ID" \ -H "Authorization: Bearer $API_TOKEN"

Deleting a role first moves every grant holding it to the built-in Member role, then deletes the role. The reassignment is committed before the delete is issued, so if the delete fails the reassignment stands and the role is still there — re-issue the delete.

This is what stands between a role delete and a silent revocation: the foreign key from a grant to its role is ON DELETE CASCADE, so an unguarded delete would remove the grants instead of the role, taking a whole group’s access to a workspace with no error anywhere.

Rules

  • Role names are unique within an organization, compared without regard to case — “Analysts” and “analysts” collide
  • owner, admin and member are reserved and cannot be used as custom role names
  • Built-in roles cannot be edited or deleted. They belong to no organization, which is what makes the same three ids usable from every one of them
  • Custom roles belong to one organization, and can be granted in any of its workspaces

Granting a Role

A role reaches a person through a grant, so changing what somebody can do means changing the grant their group holds — or moving them to a different group.

Via the UI

A workspace’s Workspace settings → Groups tab (Workspace settings is the last item under Governance in the sidebar) lists the groups that reach it, each with an inline roles picker and, for organization administrators, Revoke. From the other end, Organization settings → Groups puts the organization’s groups down the left and the selected one’s workspaces and roles on the right.

Via the API

curl -X PUT "$API_BASE_URL/api/v1/organizations/$ORG_ID/groups/$GROUP_ID/workspaces/$WORKSPACE_ID" \ -H "Authorization: Bearer $API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"role_id": "00000000-0000-0000-0000-000000000002"}'

role_id accepts any built-in or custom role id, or null — which attaches the group to the workspace and grants it nothing. The built-in ids are stable:

RoleID
Owner00000000-0000-0000-0000-000000000001
Admin00000000-0000-0000-0000-000000000002
Member00000000-0000-0000-0000-000000000003

Granting requires organization administration. The change takes effect on that group’s members’ next request, and is recorded in the workspace audit log under the workspace it affects.

Roles and Access Policies

A role decides which actions a member can take. Access policies decide which rows they see, and are assigned through groups.

Holders of Owner or Admin who are in no group carrying an access policy read every row. Once such a person is assigned a policy through a group, that policy applies to them like anyone else.

Next Steps

Last updated on