Skip to main content
Unkey Resource Names, or URNs, identify public Unkey resources in a stable, parseable format. URNs are used anywhere Unkey needs to refer to the same resource across product surfaces, audit logs, permission checks, traces, and internal events. This document defines the v1 resource-name contract. Future versions can add path shapes or change parsing rules, but v1 URNs must keep the behavior defined here. A permission attaches an action to a URN, but the URN itself names only the resource. The Go implementation lives in pkg/urn.

Format

A URN has four colon-separated fields.
unkey:v1:{workspace_id}:{resource_path}
Each field has a fixed meaning.
FieldDescription
unkeyFixed prefix for every Unkey Resource Name.
v1Resource-name grammar version.
{workspace_id}Workspace that owns the resource.
{resource_path}Canonical path to the resource inside the workspace.
For example:
unkey:v1:ws_123:projects/proj_123
unkey:v1:ws_123:projects/proj_123/apps/app_456
unkey:v1:ws_123:projects/proj_123/apps/app_456/environments/env_789/deployments/d_abc
The workspace ID is part of the URN even when the caller already has workspace context. Audit logs, background jobs, and support tools must be able to copy a URN and identify the owning workspace without extra state.

Path rules

Resource paths are part of the contract. Code that creates, parses, or matches URNs must follow these rules.
  • Concrete resource URNs must use the full canonical path from the catalog.
  • Collection segments are plural, for example keyspaces, keys, and projects.
  • ID segments use the existing public Unkey ID for that resource.
  • : is reserved for top-level URN fields and must not appear in a resource path.
  • # is reserved for permissions and must not appear in a URN.
  • A resource path must not start or end with /.
Concrete URNs identify one resource. Resource-name patterns identify a set of resources and are part of the v1 URN grammar. Callers that need one exact resource, such as audit logs and authorization requests, must use concrete URNs. Stored authorization grants can use patterns.

Resource-name patterns

Resource-name patterns use the same four-field URN format as concrete resource names. The difference is in the resource path.
OperatorMeaning
*Matches exactly one complete path segment.
/**Matches the base path and every descendant below it.
The * operator must be the whole path segment. A pattern such as key_* is invalid because it would make prefix matching ambiguous. The /** operator must be the final path segment. A pattern such as projects/**/deployments/* is invalid because descendant matching has to stop at the end of the path. After a path uses * for an ID selector, descendant ID selectors must also use *. The path can still name child collections, but it can’t narrow back to a specific child. This keeps wildcard paths canonical and avoids permissions that pretend to select a child without selecting the parent that owns it. Valid:
unkey:v1:ws_123:projects/*/apps/*
unkey:v1:ws_123:projects/*/apps/*/environments/*/deployments/*
unkey:v1:ws_123:projects/proj_123/apps/*/environments/*
Invalid:
unkey:v1:ws_123:projects/*/apps/app_123
unkey:v1:ws_123:projects/proj_123/apps/*/environments/env_123
unkey:v1:ws_123:projects/proj_123/apps/*/environments/*/deployments/dep_123
For example, this pattern:
unkey:v1:ws_123:keyspaces/*/keys/*
matches this concrete URN:
unkey:v1:ws_123:keyspaces/ks_123/keys/key_456
This descendant pattern:
unkey:v1:ws_123:projects/proj_123/**
matches the project itself and every public descendant below that project. Patterns never cross workspace boundaries, including the global workspace pattern:
unkey:v1:ws_123:**
pkg/urn parses concrete names and patterns. It also decides whether one URN covers another. The permission system adds the action suffix and decides what a covered resource authorizes. It doesn’t define its own path matching.

Resource catalog

The public catalog defines every concrete resource path that can appear in a v1 URN. Implementation code must reject concrete URNs that don’t match one of these path shapes. Pattern grants must still be built from these path shapes, with * replacing complete ID segments or trailing /** covering descendants.

Team

Team resources are rooted under team.
ResourcePath
Membershipteam/memberships/{membership_id}
Invitationteam/invitations/{invitation_id}
Examples:
unkey:v1:ws_123:team/memberships/mbr_123
unkey:v1:ws_123:team/invitations/inv_456

Billing

Billing resources are rooted under billing. Workspace quota is a singleton resource because quota applies to the workspace billing state.
ResourcePath
Billing statebilling
Invoicebilling/invoices/{invoice_id}
Quotabilling/quotas
Examples:
unkey:v1:ws_123:billing
unkey:v1:ws_123:billing/invoices/inv_123
unkey:v1:ws_123:billing/quotas

Keyspaces

Key resources are rooted under the keyspace that owns the key.
ResourcePath
Keyspacekeyspaces/{keyspace_id}
Keykeyspaces/{keyspace_id}/keys/{key_id}
Examples:
unkey:v1:ws_123:keyspaces/ks_123
unkey:v1:ws_123:keyspaces/ks_123/keys/key_456

Identities

Identity resources are rooted under identities.
ResourcePath
Identityidentities/{identity_id}
Example:
unkey:v1:ws_123:identities/id_123

Rate limits

Standalone rate limiting resources are rooted under ratelimits. Overrides belong to the namespace they modify.
ResourcePath
Namespaceratelimits/namespaces/{namespace_id}
Overrideratelimits/namespaces/{namespace_id}/overrides/{override_id}
Examples:
unkey:v1:ws_123:ratelimits/namespaces/rlns_123
unkey:v1:ws_123:ratelimits/namespaces/rlns_123/overrides/rlor_456

RBAC

RBAC resources are rooted under rbac. Relationship changes, such as adding a role to a key, are audited against both affected resources rather than by creating a separate join-table URN.
ResourcePath
Rolerbac/roles/{role_id}
Permissionrbac/permissions/{permission_id}
Examples:
unkey:v1:ws_123:rbac/roles/role_123
unkey:v1:ws_123:rbac/permissions/perm_456

Deploy

Deploy resources use the full product hierarchy. A deployment belongs to one environment, which belongs to one app, which belongs to one project.
ResourcePath
Projectprojects/{project_id}
Appprojects/{project_id}/apps/{app_id}
Environmentprojects/{project_id}/apps/{app_id}/environments/{environment_id}
Deploymentprojects/{project_id}/apps/{app_id}/environments/{environment_id}/deployments/{deployment_id}
Deployment instanceprojects/{project_id}/apps/{app_id}/environments/{environment_id}/deployments/{deployment_id}/instances/{instance_id}
Domainprojects/{project_id}/apps/{app_id}/environments/{environment_id}/domains/{domain_id}
Variableprojects/{project_id}/apps/{app_id}/environments/{environment_id}/variables/{variable_id}
Examples:
unkey:v1:ws_123:projects/proj_123
unkey:v1:ws_123:projects/proj_123/apps/app_456
unkey:v1:ws_123:projects/proj_123/apps/app_456/environments/env_789
unkey:v1:ws_123:projects/proj_123/apps/app_456/environments/env_789/deployments/d_abc

Portal

Portal resources are rooted under portals. Session tokens and sessions belong to the portal that created them.
ResourcePath
Portalportals/{portal_id}
Portal session tokenportals/{portal_id}/session_tokens/{portal_session_token_id}
Portal sessionportals/{portal_id}/sessions/{portal_session_id}
Portal brandingportals/{portal_id}/branding
Examples:
unkey:v1:ws_123:portals/portal_123
unkey:v1:ws_123:portals/portal_123/sessions/ps_456

Internal resources

Runtime and implementation resources are not part of the public v1 catalog unless a product feature explicitly promotes them. This includes:
  • Frontline routes
  • Sentinels
  • Regional counters
  • ClickHouse outbox rows
  • Cache entries
  • Join-table rows
Internal systems can still log implementation IDs in metadata. They must not mint public URNs for these resources unless the catalog is updated first.

Invalid examples

These strings are invalid URNs or invalid concrete URNs.
ValueReason
urn:unkey:v1:ws_123:keyspaces/ks_123Uses the wrong prefix.
unkey:v1:ws_123Missing the resource path.
unkey:v1:ws_123:keyspaces/ks_123#read_keyspaceContains a permission action.
unkey:v1:ws_123:keyspaces/ks_*Uses * inside a path segment.
unkey:v1:ws_123:projects/**/deployments/*Uses ** before the end of the path.
unkey:v1:ws_123:projects/*/apps/app_123Selects a specific child under a wildcard parent.
unkey:v1:ws_123:keyspace/ks_123Uses an unknown path shape.