> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Policy JSON reference

> Target signing requests and define conditions, personal limits, and conditional approval requirements

This reference covers JSON authoring beyond the Developer Portal forms. Use [Author policies with JSON](/v3/cli/permissions) to validate and publish a definition on beta, or work with Para to review a configuration.

## Policy structure

| Field                  | Purpose                                                                            |
| ---------------------- | ---------------------------------------------------------------------------------- |
| `id`                   | Logical policy identity, retained across versions.                                 |
| `schemaVersion`        | `permissions.policy.v1`.                                                           |
| `version`              | Immutable numeric version string; start with `"1"` and increment for replacements. |
| `selector`             | Signing requests this policy can apply to.                                         |
| `rules`                | Conditions and their effects; rule IDs must be unique.                             |
| `metadata.productMode` | `guardrail` for app-owned wallets or `delegation` for user-owned Requests.         |
| `metadata.description` | Human-readable purpose shown when requesting consent.                              |
| `metadata.label`       | Optional display label.                                                            |
| `metadata.annotations` | Optional authoring metadata; it does not replace executable conditions.            |

Partner and application scope come from the authenticated authoring context. Do not copy internal `layer`, `partnerId`, or `appId` fields from a resolved policy into CLI input. Activation dates belong to the saved record, not the definition.

## Selectors

All provided selector fields must match. An omitted field does not add a restriction, subject to the legacy EVM behavior described below.

| Field          | Accepted value                                                                           |
| -------------- | ---------------------------------------------------------------------------------------- |
| `walletId`     | One wallet ID. Omit for matching wallets in the policy's application scope.              |
| `walletType`   | `EVM`, `SOLANA`, `COSMOS`, `STELLAR`, or `SUI`.                                          |
| `chainId`      | A string or an array of distinct strings. An array matches any listed chain.             |
| `requestRoute` | A supported signing route, such as `evm.sign_transaction` or `solana.sign_transaction`.  |
| `requestType`  | The matching normalized request type, such as `evm_transaction` or `solana_transaction`. |

```json theme={null}
{
  "walletId": "YOUR_WALLET_ID",
  "walletType": "EVM",
  "chainId": ["1", "8453"],
  "requestRoute": "evm.sign_transaction",
  "requestType": "evm_transaction"
}
```

This selects that wallet's EVM transactions on Ethereum or Base. It does not authorize another wallet or every signing method on those networks. `userId` and `actorId` are not supported fields in partner-authored CLI selectors. Use `walletId` to target a wallet.

### Wallet families and routes

| Wallet family | Transaction route          | Request type          |
| ------------- | -------------------------- | --------------------- |
| EVM           | `evm.sign_transaction`     | `evm_transaction`     |
| Solana        | `solana.sign_transaction`  | `solana_transaction`  |
| Cosmos        | `cosmos.sign_transaction`  | `cosmos_transaction`  |
| Stellar       | `stellar.sign_transaction` | `stellar_transaction` |
| Sui           | `sui.sign_transaction`     | `sui_transaction`     |

The authoring language also includes `evm.sign_raw`, `evm.sign_typed_data`, `evm.sign_authorization`, `evm.sign_message`, and `smart_account.user_operation`. Use `para keys permissions catalog KEY_ID --json` to inspect supported facts and operators before targeting a route.

<Warning>
  Set the signing scope explicitly for non-EVM policies. Legacy definitions without an explicit signing scope retain EVM behavior; an empty selector is not a portable “all wallet types” policy.
</Warning>

Use separate definitions when chain families need different routes, assets, or facts. A `chainId` array is useful for compatible networks; it does not convert amounts or combine balances between networks.

## Conditions

| Kind        | Meaning                                                        |
| ----------- | -------------------------------------------------------------- |
| `compare`   | Compare a supported fact with a value.                         |
| `aggregate` | Compare projected spending over a fixed window with an amount. |
| `all`       | Every condition in `of` must match.                            |
| `any`       | At least one condition in `of` must match.                     |
| `not`       | Negate the single condition in `of`.                           |

Comparison operators are `eq`, `ne`, `lt`, `lte`, `gt`, `gte`, and `in`; each fact supports a defined subset. Common facts include `request.classification`, `request.to`, `request.value.baseUnits`, `request.value.asset`, `request.token.value.baseUnits`, `request.contract.address`, `request.method`, and route-specific target or argument facts. A fact available on one signing route is not necessarily available on another.

### Combine AND and OR conditions

This condition requires a native transfer, one of two recipients, and an amount at most the limit:

```json theme={null}
{
  "kind": "all",
  "of": [
    { "kind": "compare", "fact": "request.classification", "op": "eq", "value": "native_transfer" },
    {
      "kind": "any",
      "of": [
        { "kind": "compare", "fact": "request.to", "op": "eq", "value": "0x1111111111111111111111111111111111111111" },
        { "kind": "compare", "fact": "request.to", "op": "eq", "value": "0x2222222222222222222222222222222222222222" }
      ]
    },
    { "kind": "compare", "fact": "request.value.baseUnits", "op": "lte", "value": "10000000000000000" }
  ]
}
```

Place this condition inside a rule's `when`. For an EVM Request, an `allow` rule can grant matching transfers after consent. For a Guardrail, express the condition that should be denied or require approval. An `allow` rule does not turn an app-owned wallet's default into an allowlist.

### Amounts and spending windows

Amounts are canonical non-negative integer strings in the asset's base units. They are not floating-point token amounts or fiat values. For example, `10000000` means 0.01 SOL in a SOL transfer but a different quantity for an asset with different decimals.

An EVM native-spend condition can limit cumulative usage rather than just one transaction:

```json theme={null}
{
  "kind": "aggregate",
  "fact": "wallet.spend.native",
  "op": "lte",
  "value": "1000000000000000000",
  "window": "24h"
}
```

Cumulative spending meters currently support EVM transaction signing, not all wallet families. Use `wallet.spend.erc20` with the token contract in `asset` for supported direct ERC-20 transfers. These are fixed spending windows, not a transaction timelock or a fiat budget. The current request and outstanding reservations matter when evaluating available spend. See the [REST guide](/v3/rest/permissions#windowed-spend-limits) for metering boundaries.

## Effects and multiple active policies

| Effect             | Meaning                                                                                   |
| ------------------ | ----------------------------------------------------------------------------------------- |
| `deny`             | Prevent the matching signing request.                                                     |
| `require_approval` | Require the matching review or structured approval requirement.                           |
| `allow`            | Permit the matched operation subject to the remaining policies and authorization context. |

For matched standard rules, precedence is **deny, then require approval, then allow**. It is not first-match-wins, and adding an allow policy cannot override a denial. When standard rules provide no decision, the baseline behavior applies: app-owned signing is permitted unless restricted, while user-owned signing requires review without standing access. Missing facts that could change the decision can fail closed.

For example, a user may consent to small transfers while a separate policy denies transfers to a restricted recipient. A small transfer to that recipient is still denied. A different rule requiring approval is not bypassed merely because another rule allows the amount.

## User-adjustable amounts

Add a `parameter` to a supported upper amount condition:

```json theme={null}
{
  "kind": "compare",
  "fact": "request.value.baseUnits",
  "op": "lte",
  "value": "10000000",
  "parameter": { "id": "transfer-limit", "label": "Transfer limit" }
}
```

The containing value is the default. A policy can expose multiple parameters with unique IDs. Supported facts are `request.value.baseUnits`, `request.token.value.baseUnits`, `wallet.spend.native`, and `wallet.spend.erc20`. Use `lt`/`lte` on an `allow` rule or `gt`/`gte` on a `deny` or `require_approval` rule; parameterized conditions cannot be negated.

There are no `min` or `max` fields in this declaration. The owner chooses a valid non-negative integer amount; the default is not a ceiling. Fixed conditions remain unchanged. Personal values are separate from immutable policy definitions and do not themselves grant consent.

<Card title="Integrate consent and adjustable limits" icon="user-check" href="/v3/react/guides/permissions#adjust-personal-limits">
  Read, update, and reset personal values, or let users adjust them during Portal consent.
</Card>

## Conditional approval requirements

Attach `approvalRequirement` to a `require_approval` rule. Its `when` still determines which requests need that workflow.

```json theme={null}
{
  "id": "treasury-review",
  "effect": "require_approval",
  "when": { "kind": "compare", "fact": "request.classification", "op": "eq", "value": "native_transfer" },
  "approvalRequirement": {
    "id": "treasury-approval",
    "evidence": "authenticated_approval",
    "stages": [
      { "id": "finance", "requiredApprovals": 2, "eligibility": [{ "kind": "role", "name": "finance" }] },
      { "id": "compliance", "requiredApprovals": 1, "eligibility": [{ "kind": "role", "name": "compliance" }] },
      { "id": "owners", "requiredApprovals": "all", "eligibility": [{ "kind": "role", "name": "owner" }] }
    ]
  }
}
```

This is an ordered three-stage workflow. A numeric count expresses M-of-N participation among eligible people; `all` requires every eligible person in the stage's snapshot. For authenticated approvals, the initiating person cannot self-approve, and one person cannot supply approval in multiple stages. Provision enough distinct eligible people for the workflow to complete.

Eligibility clauses are alternatives: matching any clause qualifies a person. Eligibility can reference a role or an attribute: `{ "kind": "attribute", "name": "region", "operator": "eq", "value": "europe" }`, or `operator: "in"` with a `values` array. Assignments are trusted backend data scoped to an authorization scope, not client-supplied claims.

### Configure declared workflow settings

`configurationManagerEligibility` identifies users allowed to manage configuration. `safeKnobs` declares the settings that can change without rewriting the policy:

<Expandable title="Workflow configuration fields">
  | Kind                 | Declaration                                                                                    |
  | -------------------- | ---------------------------------------------------------------------------------------------- |
  | `required_approvals` | `id`, `stageId`, `min`, and `max`; accepts a bounded integer approval count.                   |
  | `eligible_group`     | `id`, `stageId`, `defaultOptionId`, and named `options` containing eligibility clauses.        |
  | `minimum_amount`     | `id` and `stageId`; adjusts the amount threshold of a stage already declaring `minimumAmount`. |
</Expandable>

Amount-dependent stages use `amountFact` (`request.value.baseUnits` or `request.token.value.baseUnits`) and ordered `minimumAmount` values. A configuration cannot add arbitrary stages or rewrite the rule. These settings are distinct from a user's personal spending parameters.

### Choose the evidence

`authenticated_approval` records authenticated human decisions. `transaction_signature` collects verified signatures over the case's transaction payload. Neither is wallet-owner consent, and collecting signatures is not the same as assembling or submitting an onchain multisig transaction.

A requirement supports 1–5 stages, numeric approval counts from 1–25 or `all`, and up to 10 eligibility clauses per stage. Validate the complete definition rather than relying only on these individual field limits.

<Card title="Integrate conditional approvals" icon="users" href="/v3/react/guides/conditional-approvals">
  Connect this policy to approver UI, workflow configuration, and signature collection.
</Card>

## Developer Portal authoring limits

The existing forms provide common EVM transaction actions and one authored condition per action. Their limits do not define the complete JSON language. Keep using the [visual walkthrough](/v3/general/developer-portal-permissions) for those forms, and use the [CLI](/v3/cli/permissions) for advanced definitions. Production policy publication remains managed by Para.
