Roles and permissions

Control who can do what in your Gateway organization with built-in and custom roles.

Every member of a Gateway organization holds exactly one role. Each role is a named bundle of permissions, and every privileged API endpoint requires one or more permissions to succeed. Use the built-in roles for the common case, or define custom roles to match how your team is organized.


Built-in roles

Three system roles ship with every organization. They cannot be edited or deleted.

RoleIntended forPermissions
AdminOrg owners and senior platform engineers.All 24 permissions, including user and role management.
DeveloperDay-to-day engineers building on Gateway.All permissions except manage_users, manage_roles, and manage_billing.
Read OnlyAuditors, support, observers.Every view_* permission and nothing else.

System roles are immutable. To grant a slightly different permission set, create a custom role instead.


Permissions catalog

Permissions are grouped into 13 resources. Most resources have a manage_* permission for create / update / delete and a view_* permission for read access. Logs is the one resource without a manage_* permission - visibility is the only operation.

ResourceView permissionManage permission
Users / Membersview_usersmanage_users
Rolesview_rolesmanage_roles
API keysview_api_keysmanage_api_keys
Credentialsview_credentialsmanage_credentials
Billingview_billingmanage_billing
Evalsview_evalsmanage_evals
Organization settingsview_org_settingsmanage_org_settings
Logsview_logs-
Audit trailview_audit_trail-
Guardrailsview_guardrailsmanage_guardrails
SSOview_ssomanage_sso
Routingview_routingmanage_routing
Projectsview_projectsmanage_projects

The control-plane API exposes the canonical list at GET /organizations/{org_id}/permissions, which returns both the machine codename and the human-readable display name for each.


Custom roles

Custom roles let you slice the permission set however your team needs - for example, a “Routing Editor” role that grants manage_routing + view_projects + view_api_keys and nothing else, or a “Billing Manager” role that only includes billing permissions.

ActionEndpointNotes
List rolesGET /organizations/{org_id}/rolesReturns system + custom roles.
CreatePOST /organizations/{org_id}/rolesBody: {name, permission_codenames: [...]}. Names must be unique within the org.
UpdatePATCH /organizations/{org_id}/roles/{role_id}Edit name and/or permission set. System roles return 422.
DeleteDELETE /organizations/{org_id}/roles/{role_id}Returns 409 if any member is currently assigned to the role.

All four operations require the manage_roles permission.

Deleting a role is blocked if members are assigned to it. Reassign members to a different role first, then retry the delete.


Permission Matrix UI

Open Settings → Roles in the Merge Gateway dashboard to see the permission matrix:

  • Each row is a permission, labeled with its human-readable name.
  • Each column is a role. System roles render as read-only badges (their checkboxes are non-interactive). Custom roles render as editable columns with a checkbox grid.
  • The “Create custom role” panel opens from the right of the page and shares the same matrix layout.

Behind the matrix is a feature flag named rbac. While that flag is on (the default for production orgs), permission checks are enforced server-side. When the flag is off - for example, in early-pilot organizations - the frontend bypasses all checks and returns true for every permission.


Assigning roles to users

Invitations

Org admins invite new members from Settings → Members. Each invitation:

  • Requires the inviter to hold manage_users.
  • Carries a role selection - the invitee will hold that role immediately on acceptance.
  • Expires after 7 days.
  • Writes a MEMBER_INVITED audit event on send and a MEMBER_JOINED event when accepted.

You can resend (MEMBER_INVITATION_RESENT) or revoke (MEMBER_INVITATION_REVOKED) a pending invitation from the same page. Both actions emit their own audit entries.

Role changes

To change an existing member’s role, use the role selector in the members table. The underlying call is:

$PATCH /organizations/{org_id}/members/{membership_id}?role_id={role_id}

This also requires manage_users and emits a MEMBER_ROLE_CHANGED audit event with a diff between the old and new role names.

A member always holds exactly one role at a time. There is no concept of multi-role assignment; if you need a custom permission combination for a user, create a role that has that exact combination and assign them to it.


Permission checks at the API layer

Every mutating control-plane endpoint is gated by require_permission(...). The dependency accepts one or more permission codenames; the caller’s role must hold at least one of them for the request to proceed.

For example, the blocklist endpoints declare:

  • GET /organizations/{org_id}/blocklist-rules → requires view_org_settings or manage_org_settings
  • POST /organizations/{org_id}/blocklist-rules → requires manage_org_settings

If the caller’s role doesn’t satisfy the requirement, the request fails with 403. To find the permission required for any given endpoint, check the OpenAPI reference or the endpoint’s require_permission(...) declaration in the control-plane source.


Audit trail integration

Every RBAC operation writes an entry to the audit trail:

ActionEvent
Create a custom roleROLE_CREATED
Edit a role’s name or permissionsROLE_UPDATED (with a field-level diff)
Delete a custom roleROLE_DELETED
Send an invitationMEMBER_INVITED
Accept an invitationMEMBER_JOINED
Resend an invitationMEMBER_INVITATION_RESENT
Revoke an invitationMEMBER_INVITATION_REVOKED
Change a member’s roleMEMBER_ROLE_CHANGED
Remove a memberMEMBER_REMOVED

Use the audit trail to answer “who granted this user admin?” or “when did this role lose a permission?” - the diff is captured on every UPDATE event.


FAQ

No. Each member holds exactly one role per organization. If a user belongs to multiple orgs, they have one role in each.

No. System roles are immutable so the baseline permission sets stay predictable across orgs. To customize, create a new role with the permission set you need.

The delete is rejected with 409 Conflict. Reassign affected members to a different role, then retry the delete.

No. Roles are flat permission sets. The Admin role explicitly enumerates every permission; it does not derive from any other role.

7 days. After expiry, the invitee gets a “this invitation has expired” message. The inviter can resend a fresh invitation from the same page.


Next steps