Andy
03/23/2026, 2:09 PM/fact) instead of schema-based ones, which makes sense conceptually.
That said, we’re trying to better understand the limits and expected usage patterns so we don’t run into this again.
A few things we’d really appreciate clarity on:
• Even though the documented limit for schema endpoints is 1,000 req/min, we still hit a block - are there additional practical limits or safeguards around schema mutations we should be aware of?
• If we switch to fact-based endpoints, what level of throughput or usage is considered “safe” before hitting similar limits?
• Are there recommended patterns or best practices for handling high-frequency updates (e.g. lots of role/permission changes)?
• Has anyone in the community dealt with similar scaling concerns, and how did you approach it?
Our main goal is to make sure we design this correctly going forward and avoid unexpected disruptions, especially since our use case may involve fairly heavy API usage.Ask Inkeep
03/23/2026, 2:09 PMAsk Inkeep
03/23/2026, 2:09 PM/v2/facts/*) , the limit is *3,000 requests per minute*. For schema requests (/v2/schema/*) , the limit is *1,000 requests per minute*. For bulk requests, the limit is *100 requests per 10 minutes*. (1)
Regarding your schema mutation issue, you're correct that moving to fact-based endpoints is the right approach. Schema endpoints should be used for defining your authorization model (resources, roles, actions) , while fact endpoints handle runtime data (users, tenants, role assignments, relationship tuples) .
For high-frequency updates with facts, you have a couple of options:
*Bulk operations*: If you need to perform multiple permission checks at once, you can use the bulkCheck() function to validate multiple permission requests in a single call rather than making individual calls. (2)
*Consistent updates*: When creating or updating data that you need to immediately use for permission checks, you can enable proxy_facts_via_pdp in your SDK configuration. This routes data changes through the PDP and waits for them to be applied before responding, ensuring immediate consistency. (3)
For example in Python:
permit = Permit(
token="<your-api-key>",
pdp="<http://localhost:7766>",
proxy_facts_via_pdp=True
)
The key architectural shift is: use schema endpoints sparingly (only when your authorization model changes) , and use fact endpoints for all runtime data operations like role assignments, user creation, and relationship management. This keeps you well within the 3,000 req/min limit for facts versus the 1,000 req/min for schema.
To help investigate your specific case further, could you share:
1. Which Workspace / Project / Env you are using
2. What calls you are performing (as SDK code or CURL)
3. Which PDP version you are running
4. Relevant logs from your PDP
This will help the engineering team provide more specific guidance for your use case.Ask Inkeep
03/23/2026, 2:09 PMOr Weis
03/23/2026, 2:16 PMAndy
03/23/2026, 2:18 PMOr Weis
03/23/2026, 2:21 PMAndy
03/23/2026, 2:27 PMOr Weis
03/23/2026, 2:40 PMAndy
03/23/2026, 2:46 PMAndy
03/25/2026, 11:59 AMuser → group (external identity) → document
with a more direct ReBAC approach.
Issue encountered
Our use case requires late binding between internal users and external identities (e.g. Google Drive users that may not exist in our system yet). Concretely:
• We sync permissions like:
• external_identity (mdi-123) → viewer → document
•
• When a user signs up, we want:
• user:real-123 → inherits access from external_identity:mdi-123
•
However, we ran into the following constraints:
1. 1. We cannot create relations pointing to the built-in user type (attempts return 404)
2. 2. Derived roles appear to only support resource → resource propagation (as shown in the Google Drive example), not subject → subject → resource
3. 3. The official Google Drive example only models:
user → role → resource
resource → resource (hierarchy)
and does not cover identity mapping or inheritance across subjects
Because of this, we were unable to model:
user → external_identity → document
purely with facts + derived roles.
What we tried as alternatives
• Attempted to model member_of-style relations → blocked by user relation limitation
• Attempted custom Rego to resolve identity inheritance → technically possible, but seems to bypass the intended ReBAC model and complicates evaluation
Clarification needed
Given these constraints, we’re trying to understand the intended pattern for this type of use case.
Specifically:
Is it correct that Permit’s ReBAC model does not support subject-to-subject inheritance (e.g. user inheriting from external identity) without using Groups?
1. If so, what is the recommended way to model late-binding external identities at scale?
2. Treat external identities as users in Permit and resolve them at query time?
3. Materialize permissions onto real users during sync/signup?
4. Continue using Groups despite the scale concerns?
5. When you suggested using “resource instances + relationship tuples (facts)”, how would that approach handle identity mapping without Groups?
Context
Our requirements:
• External identities exist before users sign up
• Large permission sets (10k+ identities, 5k–10k assignments per sync)
• Near real-time sync from providers
• Users should immediately see pre-existing permissions on signup
Our original Groups-based approach satisfies these functionally, but we’re trying to move away from it based on your guidance.Or Weis
03/25/2026, 12:29 PM1. 1. We cannot create relations pointing to the built-intype (attempts return 404)user
2. 2. Derived roles appear to only support resource → resource propagation (as shown in the Google Drive example), not subject → subject → resource
3. 3. The official Google Drive example only models:Usually this is solved by creating a resource instance to represent the user (e.g.
user-profile), at the moment users (aka identities) are not automatically created as resource instances.
You can see an example of this pattern here.
@Ask Inkeep can elaborateAsk Inkeep
03/25/2026, 12:29 PMAsk Inkeep
03/25/2026, 12:29 PMuser type directly in relationships. (1)
Solution: User Profile Pattern for Late-Binding Identities
The pattern Or mentioned involves creating a *resource to represent user profiles* (e.g., member or user_profile) , which allows you to:
1. Create resource instances for external identities *before* users sign up
2. Establish relationships between these profile instances and documents
3. Link real users to their profile instances when they sign up
Implementation Approach
*Step 1: Define Resources and Relations*
Create a member resource (representing user profiles) with relations to your documents: (2)
curl <https://api.permit.io/v2/schema/$permit_project/$permit_env/resources/file/relations> \
-X POST \
-H "Authorization: Bearer $permit_sdk_api_key" \
-H "Content-Type: application/json" \
-d '{
"key": "parent",
"name": "Parent",
"subject_resource": "folder"
}'
(3)
*Step 2: Create Resource Instances for External Identities*
When syncing from Google Drive/Dropbox, create member instances for external identities: (4)
await permit.api.resource_instances.create({
key: "mdi-123",
resource: "member",
tenant: "default",
attributes: {
external_provider: "google_drive",
external_id: "<mailto:alice@example.com|alice@example.com>"
}
}) ;
*Step 3: Assign Roles to External Identity Instances*
Grant the external identity instance access to documents: (3)
await permit.api.role_assignments.assign({
user: "mdi-123",
role: "viewer",
resource_instance: "file:document123",
tenant: "default"
}) ;
*Step 4: Create Relationship Tuples*
Establish relationships between resources: (4)
await permit.api.relationship_tuples.create({
subject: "folder:finance",
relation: "parent",
object: "file:2023_report",
tenant: "default"
}) ;
*Step 5: Link Real Users on Signup*
When a user signs up and links their Google account, create a relationship between the real user and their member profile instance. You can assign the user the owner role on their member profile: (3)
await permit.api.role_assignments.assign({
user: "real-user-123",
role: "owner",
resource_instance: "member:mdi-123"
}) ;
*Step 6: Set Up Role Derivations*
Configure role derivations so that ownership of a member profile grants inherited permissions: (2)
curl <https://api.permit.io/v2/schema/$permit_project/$permit_env/resources/file/roles/viewer> \
-X PATCH \
-H "Authorization: Bearer $permit_sdk_api_key" \
-H "Content-Type: application/json" \
-d '{
"granted_to": {
"users_with_role": [
{
"linked_by_relation": "owner",
"on_resource": "member",
"role": "viewer"
}
]
}
}'
(3)
Key Benefits of This Approach
• *Fact-based operations*: All instance creation and role assignments use /v2/facts/* endpoints (3,000 req/min limit) (4)
• *No schema mutations*: Resource and relation definitions are set once; everything else is runtime data (2)
• *Late binding*: External identities exist as resource instances before users sign up (1) Ask Inkeep
03/25/2026, 12:30 PMAndy
03/25/2026, 2:09 PMuser → user profile (external identity) → document
• Derived roles now correctly propagate document permissions to the user once they link their external identity
This works well for our late-binding users scenario.
We now have a new use case and want to check the recommended approach:
• We want to model groups of external identities.
• Desired access chain:
user → external identity → group of external identities → document
• Goal: A user linked to an external identity should inherit access if any identity in the group has access to the document.
My questions:
1. Is it possible to model this multi-layer chain purely with derived roles, or does Permit only support a single resource → resource propagation?
2. If derived roles don’t support this, is the recommended approach to:
3. Flatten permissions (assign each identity in the group directly to the document), or
4. Use a custom Rego policy to evaluate group membership dynamically?
5. Are there any other patterns in Permit that support this type of “intermediate resource layer” while keeping late-binding users and facts-based assignments?
@Ask Inkeep @Or WeisAsk Inkeep
03/25/2026, 2:09 PMAsk Inkeep
03/25/2026, 2:09 PMuser → external identity → group → document can be implemented using *relationship tuples and role derivations* at each layer. (1) (2)
Here's the recommended approach:
*Step 1: Define the Resource Relations*
Create relations between your resources to establish the hierarchy: (1)
# Identity → Group relation
curl <https://api.permit.io/v2/schema/$permit_project/$permit_env/resources/identity/relations> \
-X POST \
-H "Authorization: Bearer $permit_sdk_api_key" \
-H "Content-Type: application/json" \
-d '{
"key": "member_of",
"name": "Member Of",
"subject_resource": "identity_group"
}'
# Group → Document relation
curl <https://api.permit.io/v2/schema/$permit_project/$permit_env/resources/file/relations> \
-X POST \
-H "Authorization: Bearer $permit_sdk_api_key" \
-H "Content-Type: application/json" \
-d '{
"key": "shared_with",
"name": "Shared With",
"subject_resource": "identity_group"
}'
*Step 2: Configure Role Derivations*
Role derivations allow permissions to propagate through the relationship chain. You can configure derivations so that:
1. A user with owner role on an identity inherits roles from that identity
2. An identity with member role on an identity_group inherits roles from that group
3. An identity_group with viewer role on a file grants access to the document
The derivation mechanism works by following the relationships you've defined. (1) (2)
*Step 3: Create Resource Instances and Relationships*
When syncing permissions, create the relationship tuples as facts:
# Link identity to group
await permit.api.relationship_tuples.create({
subject: "identity_group:engineering",
relation: "member_of",
object: "identity:mdi-123",
tenant: "default"
}) ;
(2)
# Grant group access to document
await permit.api.role_assignments.assign({
user: "identity_group:engineering",
role: "viewer",
resource_instance: "file:document123",
tenant: "default"
}) ;
*Answering Your Specific Questions*
1. *Multi-layer chains with derived roles*: Yes, Permit supports chaining multiple resource relationships through role derivations. The system evaluates the entire relationship graph to determine permissions. (1) (2)
2. *Alternative approaches*: While flattening permissions or custom Rego are options, the *recommended pattern is to use relationship tuples with role derivations* as this keeps everything fact-based and avoids schema mutations. (1)
3. *Intermediate resource layers*: The relationship-based model inherently supports intermediate layers. Each resource in the chain (identity → group → document) is a resource instance with relationships defined as facts.Ask Inkeep
03/25/2026, 2:09 PMAsk Inkeep
03/25/2026, 2:10 PM