Send Consistent Updates (Read-Your-Own-Writes)
This feature enables immediate use of newly created data for permission checks. It works by routing data changes requests through the PDP and waiting them to be applied before responding.
Requires PDP version 0.5.1 or above.
Example: Create a User then Check Permissions
- Python
 - Node.js
 - Go
 - Java
 
from permit import Permit
# Initialize SDK with proxy_facts_via_pdp enabled
permit = Permit(
    token="<your-api-key>",
    pdp="http://localhost:7766",
    proxy_facts_via_pdp=True
)
async def create_and_check():
    # Create user
    user = await permit.api.users.create({
        "key": "user123",
        "email": "user@example.com"
    })
    
    # Check for permissions right after
    allowed = await permit.check(user.key, "read", "document")
    print(f"Permission granted: {allowed}")
With proxy_facts_via_pdp enabled, the API call waits until the user data is fully synced to the PDP before returning, ensuring the permission check succeeds immediately after.
import { Permit } from "permit";
// Initialize SDK with proxy_facts_via_pdp enabled
const permit = new Permit({
  token: "<your-api-key>",
  pdp: "http://localhost:7766",
  proxyFactsViaPdp: true
});
async function createAndCheck() {
  // Create user
  const user = await permit.api.users.create({
    key: "user123",
    email: "user@example.com"
  });
  
  // Check for permissions right after
  const allowed = await permit.check(user.key, "read", "document");
  console.log(`Permission granted: ${allowed}`);
}
With proxyFactsViaPdp enabled, the API call waits until the user data is fully synced to the PDP before returning, allowing immediate permission checks.
package main
import (
	"context"
	"fmt"
	"github.com/permitio/permit-golang/pkg/config"
	"github.com/permitio/permit-golang/pkg/models"
	"github.com/permitio/permit-golang/pkg/permit"
)
func main() {
	ctx := context.Background()
	
	// Initialize SDK with proxy_facts_via_pdp enabled
	permitConfig := config.NewConfigBuilder("<YOUR_API_KEY>").
		WithPdpUrl("http://localhost:7766").
		WithProxyFactsViaPdp().
		Build()
	permit := permit.New(permitConfig)
	// Create user
	newUser := models.NewUserCreate("user123")
	newUser.Email = "user@example.com"
	user, _ := permit.Api.Users.CreateUser(ctx, *newUser)
    // Check for permissions right after
	allowed, _ := permit.Check(user.Key, "read", "document")
	fmt.Printf("Permission granted: %v\n", allowed)
}
By enabling WithProxyFactsViaPdp, the API call waits until the user data is fully synced to the PDP before returning, making the permission check reliable.
import io.permit.sdk.Permit;
import io.permit.sdk.PermitConfig;
import io.permit.sdk.api.models.UserCreate;
public class Example {
    public static void main(String[] args) {
        // Initialize SDK with proxy_facts_via_pdp enabled
        PermitConfig config = new PermitConfig.Builder("<your-api-key>")
            .withPdpAddress("http://localhost:7766")
            .withProxyFactsViaPdp(true)
            .build();
            
        Permit permit = new Permit(config);
        // Create user
        UserCreate userCreate = new UserCreate.Builder("user123")
            .withEmail("user@example.com")
            .build();
        
        permit.api.users.create(userCreate);
        // Check for permissions right after
        boolean allowed = permit.check("user123", "read", "document");
        System.out.println("Permission granted: " + allowed);
    }
}
With withProxyFactsViaPdp set to true, when creating or updating a user the API call waits until the data is available in the PDP, ensuring the permission check works correctly right away.
Configuration Options
The timeout parameter specifies the maximum waiting time for data synchronization:
0: No waiting - respond immediately- Positive value (e.g., 
10): Wait up to specified seconds - Negative value (e.g., 
-1): Wait indefinitely 
The timeout_policy parameter defines behavior when timeout occurs:
ignore: Respond immediately when data update did not apply within the timeout periodfail: Respond with 424 status code when data update did not apply within the timeout period
The timeout_policy parameter is available in PDP v0.8.0 and above.
PDP Configuration
Default values for proxy facts can be set in the PDP using environment variables:
PDP_LOCAL_FACTS_WAIT_TIMEOUT: Default timeout in seconds to wait for facts to sync (default:10)PDP_LOCAL_FACTS_TIMEOUT_POLICY: Default policy on timeout, eitherignoreorfail(default:ignore)
SDK Configuration
- Python
 - Node.js
 - Go
 - Java
 
# SDK-level configuration (applies to all operations)
permit = Permit(
    token="<your-api-key>",
    pdp="http://localhost:7766",
    proxy_facts_via_pdp=True,
    facts_sync_timeout=10,           # Optional: Uses PDP default if not specified
    facts_sync_timeout_policy="ignore" # Optional: Uses PDP default if not specified
)
# All operations will use the SDK-level settings
user = await permit.api.users.create({ /* user data */ })
// SDK-level configuration (applies to all operations)
const permit = new Permit({
  token: "<your-api-key>",
  pdp: "http://localhost:7766",
  proxyFactsViaPdp: true,
  factsSyncTimeout: 10,           // Optional: Uses PDP default if not specified
  factsSyncTimeoutPolicy: "ignore" // Optional: Uses PDP default if not specified
});
// All operations will use the SDK-level settings
const user = await permit.api.users.create({ /* user data */ });
// SDK-level configuration (applies to all operations)
permitConfig := config.NewConfigBuilder("<YOUR_API_KEY>").
    WithPdpUrl("http://localhost:7766").
    WithProxyFactsViaPdp().
    WithFactsSyncTimeout(10).             // Optional: Uses PDP default if not specified
    WithFactsSyncTimeoutPolicy("ignore"). // Optional: Uses PDP default if not specified
    Build()
permit := permit.New(permitConfig)
// All operations will use the SDK-level settings
user, _ := permit.Api.Users.CreateUser(ctx, *newUser)
// SDK-level configuration (applies to all operations)
PermitConfig config = new PermitConfig.Builder("<your-api-key>")
    .withPdpAddress("http://localhost:7766")
    .withProxyFactsViaPdp(true)
    .withFactsSyncTimeout(10)           // Optional: Uses PDP default if not specified
    .withFactsSyncTimeoutPolicy("ignore") // Optional: Uses PDP default if not specified
    .build();
Permit permit = new Permit(config);
// All operations will use the SDK-level settings
permit.api.users.create(userCreate);
Operation-Specific Configuration
- Python
 - Node.js
 - Go
 
# SDK initialization with proxy_facts_via_pdp enabled
permit = Permit(
    token="<your-api-key>",
    pdp="http://localhost:7766",
    proxy_facts_via_pdp=True
)
# Override the default timeout for a specific operation
with permit.wait_for_sync(timeout=15) as p:
    user = await p.api.users.create({ /* user data */ })
// SDK initialization with proxy_facts_via_pdp enabled
const permit = new Permit({
  token: "<your-api-key>",
  pdp: "http://localhost:7766",
  proxyFactsViaPdp: true
});
// Override the default timeout for a specific operation
const user = await permit.api.users.waitForSync(15).create({ /* user data */ });
// SDK initialization with proxy_facts_via_pdp enabled
permitConfig := config.NewConfigBuilder("<YOUR_API_KEY>").
    WithPdpUrl("http://localhost:7766").
    WithProxyFactsViaPdp().
    Build()
permit := permit.New(permitConfig)
// Override the default timeout for a specific operation
user, _ := permit.Api.Users.WaitForSync(15).CreateUser(ctx, *newUser)
Direct API Usage
To call the PDP's Local Facts API directly:
POST /facts/...
Headers:
X-Wait-timeout: 10
X-Timeout-policy: ignore
You can use Proxy Facts to make requests to the Permit API by simply updating the URL path:
Change:
https://api.permit.io/v2/facts/{proj}/{env}/...
To:
http://localhost:7766/facts/...
The routes and schema are the same as the Permit API facts routes.
For example, the those routes are related and share the same schema:
curl -X POST http://localhost:7766/facts/users \
     -H "Authorization: Bearer <your-api-key>" \
     -H "Content-Type: application/json" \
     -d '{
           "key": "user123",
           "email": "user@example.com"
         }'
curl -X POST https://api.permit.io/v2/facts/default/prod/users \
     -H "Authorization: Bearer <your-api-key>" \
     -H "Content-Type: application/json" \
     -d '{
           "key": "user123",
           "email": "user@example.com"
         }'
Supported APIs
# Users
POST /facts/users
PUT /facts/users/{user_id}
PATCH /facts/users/{user_id}
# Tenants
POST /facts/tenants
# Role Assignments
POST /facts/users/{user_id}/roles
POST /facts/role_assignments
# Resource Instances
POST /facts/resource_instances
PATCH /facts/resource_instances/{instance_id}
# Relationship Tuples
POST /facts/relationship_tuples
When using the User APIs (POST /facts/users, PUT /facts/users/{user_id}, PATCH /facts/users/{user_id}), the role_assignments attribute will not be awaited in the request.
To ensure role assignments are properly synchronized, we recommend using a separate Role Assignment API request after creating or updating the user.
APIs not listed above are forwarded to the Permit API without waiting for synchronization.
Contact us in our Slack community for additional API or SDK support.
Best Practices
Performance Considerations
When using proxy facts, be aware of these performance implications:
- Increased API Latency: API requests will take longer then direct calls to the Permit API, as they wait for data synchronization
 - Faster Sync Times: Despite increased request latency, data updates are typically received faster compared to data updates via the Permit API
 - CPU Usage: PDP CPU usage may increase with high traffic to proxy facts endpoints
 - Unsupported APIs: Unsupported APIs are still routed through the PDP to the Permit API, which can result in higher latency
 
Deployment Recommendations
This feature works best in the following deployment scenarios:
Recommended: Deploy PDPs as a Centralized PDP or as a PDP Sidecar to your application. This ensures the same PDP instance handles both data creation and permission checks.
Less Optimal: Using a PDP Cluster with load balancing, permission checks may be routed to PDPs that haven't received the data update yet.