About Processing Policies
What is a processing policy?
Processing policies are used to define how the ledger processes certain operations, easing the customization of ledger by the users according to their needs. They have schema processing and define a specific structure of policy rules contained in values.
POST /v2/policies
{
...,
data: {
handle: '...',
schema: 'processing',
record: 'anchor',
filter: { ... },
values: [ ... ]
}
}Currently, processing policies support anchor forwarding through aspect values. This allows you to delegate anchor operations (create, read, update, drop, sign, query) to a Bridge while the ledger remains the public API surface and enforces authorization.
At root level, the processing policy must specify:
record- Required, must beanchor(processing policies currently only support anchor records)filter- Record must match the filter for the policy to apply, optional, if not defined policy applies to all recordsvalues- Array of aspect values that define forwarding behavior
POST /v2/policies
{
...,
"data": {
"handle": "anchor-forwarding-alias-directory",
"schema": "processing",
"record": "anchor",
"filter": { "data.schema": "alias" },
"values": [ ... ]
}
}Processing policies are exposed on the same endpoint as other policies (/v2/policies) with the distinction that the schema property is equal to processing. The schema defines the structure of the values array in the policy.
Processing aspects
Processing policies use aspect values to define anchor forwarding behavior. Each aspect value specifies an action to forward and how to forward it.
Basic structure
POST /v2/policies
{
...,
"data": {
"handle": "forward-anchors-to-directory",
"schema": "processing",
"record": "anchor",
"values": [{
"schema": "aspect",
"action": "read",
"invoke": {
"bridge": "alias-directory-bridge"
},
"config": {
"strategy": "fallback"
}
}]
}
}Aspect value fields
Each aspect value in the values array has the following structure:
schema(required): Must be"aspect"to indicate this is an aspect-based processing ruleaction(required): Defines which anchor operation to forward. Valid values:read- Get a single anchor by luid or handlequery- Get multiple anchors with filters (findAll)create- Create new anchorsupdate- Update existing anchorsdrop- Delete anchorssign- Add proofs to anchors
invoke(required): Defines where to forward the requestbridge(required): The handle of the Bridge that should receive forwarded requests
config(optional): Forwarding behavior configurationstrategy(required if config is present): How to handle the forwarding. Valid values:proxy- Forward the request without persisting locally (proxy-only)fallback- Return local data when present; otherwise call the Bridge (only for read/query)validate- Validate locally first, forward to Bridge, then persist locally (only for create/update/drop/sign)
Strategy constraints
The validation rules ensure strategies are used appropriately:
- Read and query actions can only use
proxyorfallbackstrategies (notvalidate) - Write actions (create, update, drop, sign) can only use
proxyorvalidatestrategies (notfallback)
// ✅ Valid: read action with fallback strategy
{
"schema": "aspect",
"action": "read",
"invoke": { "bridge": "my-bridge" },
"config": { "strategy": "fallback" }
}
// ❌ Invalid: read action cannot use validate strategy
{
"schema": "aspect",
"action": "read",
"invoke": { "bridge": "my-bridge" },
"config": { "strategy": "validate" } // Error!
}
// ✅ Valid: create action with validate strategy
{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "my-bridge" },
"config": { "strategy": "validate" }
}
// ❌ Invalid: create action cannot use fallback strategy
{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "my-bridge" },
"config": { "strategy": "fallback" } // Error!
}Forwarding strategies explained
Proxy strategy
The proxy strategy forwards requests directly to the Bridge without storing data locally. The ledger acts as a pure proxy.
- Behavior: Forward request → Return Bridge response
- Use case: When the Bridge is the source of truth and local storage is not needed
- Valid for: All actions (read, query, create, update, drop, sign)
POST /v2/policies
{
...,
"data": {
"handle": "proxy-all-anchors",
"schema": "processing",
"record": "anchor",
"values": [{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "external-alias-directory" },
"config": { "strategy": "proxy" }
}]
}
}Fallback strategy
The fallback strategy returns local data when available, only calling the Bridge if local data is not found.
- Behavior: Check local DB → If found, return local data → If not found, call Bridge
- Use case: When local caching is desired but Bridge is the ultimate source
- Valid for: Only read and query actions
POST /v2/policies
{
...,
"data": {
"handle": "fallback-anchor-reads",
"schema": "processing",
"record": "anchor",
"values": [
{
"schema": "aspect",
"action": "read",
"invoke": { "bridge": "alias-directory" },
"config": { "strategy": "fallback" }
},
{
"schema": "aspect",
"action": "query",
"invoke": { "bridge": "alias-directory" },
"config": { "strategy": "fallback" }
}
]
}
}Validate strategy
The validate strategy ensures the operation would succeed locally before forwarding, then persists locally only if the Bridge succeeds.
- Behavior: Validate locally (without commit) → Forward to Bridge → If Bridge succeeds, persist locally
- Use case: When both ledger and Bridge need to maintain consistent state
- Valid for: Only write actions (create, update, drop, sign)
POST /v2/policies
{
...,
"data": {
"handle": "validate-anchor-writes",
"schema": "processing",
"record": "anchor",
"values": [
{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "alias-directory" },
"config": { "strategy": "validate" }
},
{
"schema": "aspect",
"action": "update",
"invoke": { "bridge": "alias-directory" },
"config": { "strategy": "validate" }
}
]
}
}Filtering forwarded operations
You can use the filter field to apply processing policies only to anchors that match specific criteria. The filter uses standard ledger filtering with mongo-compatible expressions.
Example: Forward only alias-type anchors
POST /v2/policies
{
...,
"data": {
"handle": "forward-alias-anchors",
"schema": "processing",
"record": "anchor",
"filter": {
"data.schema": "alias"
},
"values": [
{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "alias-directory-bridge" },
"config": { "strategy": "validate" }
},
{
"schema": "aspect",
"action": "read",
"invoke": { "bridge": "alias-directory-bridge" },
"config": { "strategy": "fallback" }
}
]
}
}Example: Forward based on request headers
You can also filter based on request metadata:
POST /v2/policies
{
...,
"data": {
"handle": "forward-by-client",
"schema": "processing",
"record": "anchor",
"filter": {
"_request.headers.x-client-type": "mobile-app"
},
"values": [{
"schema": "aspect",
"action": "read",
"invoke": { "bridge": "mobile-optimized-directory" },
"config": { "strategy": "proxy" }
}]
}
}Multiple actions in one policy
You can define multiple aspect values in a single policy to forward different actions with different strategies and/or bridges:
POST /v2/policies
{
...,
"data": {
"handle": "comprehensive-anchor-forwarding",
"schema": "processing",
"record": "anchor",
"values": [
{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "alias-directory" },
"config": { "strategy": "validate" }
},
{
"schema": "aspect",
"action": "update",
"invoke": { "bridge": "alias-directory" },
"config": { "strategy": "validate" }
},
{
"schema": "aspect",
"action": "drop",
"invoke": { "bridge": "alias-directory" },
"config": { "strategy": "validate" }
},
{
"schema": "aspect",
"action": "read",
"invoke": { "bridge": "alias-book-bridge" },
"config": { "strategy": "fallback" }
},
{
"schema": "aspect",
"action": "query",
"invoke": { "bridge": "alias-book-bridge" },
"config": { "strategy": "fallback" }
},
{
"schema": "aspect",
"action": "sign",
"invoke": { "bridge": "alias-directory" },
"config": { "strategy": "validate" }
}
]
}
}Bridge requirements
When forwarding to a Bridge, the Bridge must expose the same API surface as the ledger for anchors. For detailed information about Bridge requirements, error handling, and communication flow, see Anchor Forwarding.
Required Bridge endpoints
POST /v2/anchors(for create action)PUT /v2/anchors/:id(for update action)DELETE /v2/anchors/:id(for drop action)GET /v2/anchors/:id(for read action)POST /v2/anchors/:id/proofs(for sign action)GET /v2/anchors(for query action, with filters)
What the ledger forwards
- Request body/query params: Forwarded unchanged
- Headers: Custom client headers are forwarded except forbidden ones. The original
Authorizationis moved tox-forwarded-authorization - Ledger authorization: The ledger adds its own Bearer JWT in
Authorization, signed by the ledger
For complete details on error handling, validation, proofs, and security considerations, refer to the Anchor Forwarding documentation.
Processing policies evaluation
When evaluating processing policies for anchor operations:
- Policy matching: The ledger checks if there are any processing policies that match the anchor by
recordandfilter - Action matching: Among matching policies, the ledger looks for aspect values that match the specific action being performed
- First match wins: If multiple policies define the same action for a matching anchor, the first matching policy's aspect value is used
- No match behavior: If no processing policy matches, the operation proceeds normally without forwarding
Unlike access or status policies which have a restrictive nature, processing policies are purely operational. If no processing policy matches, the operation simply executes locally without forwarding.
Migrating from configuration-based forwarding
If you're currently using ledger configuration for anchor forwarding (e.g., forward.anchor.create, forward.anchor.read), processing policies provide a more flexible alternative:
Old approach (configuration)
{
"forward.anchor.create": "MyBridgeHandle",
"forward.anchor.update": "MyBridgeHandle",
"forward.anchor.drop": "MyBridgeHandle",
"forward.anchor.sign": "MyBridgeHandle",
"forward.anchor.get": "MyBridgeHandle",
"forward.anchor.findAll": "MyBridgeHandle",
"forward.anchor.strategy": "validate",
"forward.anchor.get.strategy": "fallback"
}New approach (processing policy)
POST /v2/policies
{
...,
"data": {
"handle": "anchor-forwarding",
"schema": "processing",
"record": "anchor",
"values": [
{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "MyBridgeHandle" },
"config": { "strategy": "validate" }
},
{
"schema": "aspect",
"action": "update",
"invoke": { "bridge": "MyBridgeHandle" },
"config": { "strategy": "validate" }
},
{
"schema": "aspect",
"action": "drop",
"invoke": { "bridge": "MyBridgeHandle" },
"config": { "strategy": "validate" }
},
{
"schema": "aspect",
"action": "sign",
"invoke": { "bridge": "MyBridgeHandle" },
"config": { "strategy": "validate" }
},
{
"schema": "aspect",
"action": "read",
"invoke": { "bridge": "MyBridgeHandle" },
"config": { "strategy": "fallback" }
},
{
"schema": "aspect",
"action": "query",
"invoke": { "bridge": "MyBridgeHandle" },
"config": { "strategy": "fallback" }
}
]
}
}Benefits of processing policies
- Conditional forwarding: Use filters to forward only specific anchors (by schema, labels, or any field)
- Multiple Bridges: Different filters can forward to different Bridges
- Dynamic updates: Policies can be updated without restarting the ledger
- Access control: Policies have their own access rules defining who can create/modify them
- Versioning: Policies are signed records with full audit history
Common patterns
Pattern 1: Dedicated Bridge per anchor schema
Forward different anchor schemas to specialized Bridges:
// Policy 1: Forward alias-type anchors
POST /v2/policies
{
"data": {
"handle": "forward-alias-anchors",
"schema": "processing",
"record": "anchor",
"filter": { "data.schema": "alias" },
"values": [{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "alias-directory-bridge" },
"config": { "strategy": "validate" }
}]
}
}
// Policy 2: Forward payment-type anchors
POST /v2/policies
{
"data": {
"handle": "forward-payment-anchors",
"schema": "processing",
"record": "anchor",
"filter": { "data.schema": "payment" },
"values": [{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "payment-directory-bridge" },
"config": { "strategy": "validate" }
}]
}
}Pattern 2: Read-heavy with fallback caching
Use fallback strategy for reads while validating writes:
POST /v2/policies
{
"data": {
"handle": "cached-reads-validated-writes",
"schema": "processing",
"record": "anchor",
"values": [
// Writes go to Bridge with local validation
{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "master-directory" },
"config": { "strategy": "validate" }
},
// Reads use local cache with Bridge fallback
{
"schema": "aspect",
"action": "read",
"invoke": { "bridge": "master-directory" },
"config": { "strategy": "fallback" }
},
{
"schema": "aspect",
"action": "query",
"invoke": { "bridge": "master-directory" },
"config": { "strategy": "fallback" }
}
]
}
}Pattern 3: Pure proxy for external system
Let the Bridge be the complete source of truth:
POST /v2/policies
{
"data": {
"handle": "external-alias-directory-proxy",
"schema": "processing",
"record": "anchor",
"filter": { "data.schema": "external-alias" },
"values": [
{
"schema": "aspect",
"action": "create",
"invoke": { "bridge": "external-directory" },
"config": { "strategy": "proxy" }
},
{
"schema": "aspect",
"action": "read",
"invoke": { "bridge": "external-directory" },
"config": { "strategy": "proxy" }
},
{
"schema": "aspect",
"action": "update",
"invoke": { "bridge": "external-directory" },
"config": { "strategy": "proxy" }
},
{
"schema": "aspect",
"action": "query",
"invoke": { "bridge": "external-directory" },
"config": { "strategy": "proxy" }
}
]
}
}