> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://www.openfort.io/api/mcp` to find what you need.
>
> **Have feedback?** Use `submit_feedback` on the same MCP server.

# Backend wallet policies

Policies let you control which signing operations your backend wallets can perform.
Define rules based on value limits, address allowlists, network restrictions, calldata constraints, and more — the policy engine evaluates every signing request before it executes.

## Operations a rule can cover

Each rule pairs one `operation` with an `action` of `accept` or `reject` and a list of `criteria` that must all match. Rules are evaluated in order and the first match wins.

| Chain | Operations |
| :--- | :--- |
| Ethereum | `signEvmTransaction`, `sendEvmTransaction`, `signEvmMessage`, `signEvmTypedData`, `signEvmHash` |
| Solana | `signSolTransaction`, `sendSolTransaction`, `signSolMessage` |

:::warning
The engine fails closed. Once your project has its first policy, any signing operation that doesn't match a rule is rejected — including operations you never wrote a rule for.
:::

## Scope a policy to one wallet

`scope: 'project'` applies to every backend wallet in the project. `scope: 'account'` applies to a single wallet and requires its `accountId`. Higher `priority` values are evaluated first.

```ts
const account = await openfort.accounts.evm.backend.create()

const policy = await openfort.policies.create({
  scope: 'account',
  accountId: account.id,
  description: 'Payouts to the treasury only',
  priority: 10,
  rules: [
    {
      action: 'accept',
      operation: 'signEvmTransaction',
      criteria: [
        {
          type: 'evmAddress',
          operator: 'in',
          addresses: ['0x000000000000000000000000000000000000dEaD'],
        },
      ],
    },
  ],
})
```

To review what applies to one wallet, filter the list: `openfort.policies.list({ scope: ['account'], accountId: account.id })`.

## Test a rule before signing

`openfort.policies.evaluate()` returns the decision without performing the operation. Pass `accountId` to include that wallet's account-scoped policies — omit it and only project-scoped policies are considered.

```ts
const result = await openfort.policies.evaluate({
  operation: 'signEvmTransaction',
  accountId: account.id,
  payload: {
    chainId: 1,
    to: '0x1234567890abcdef1234567890abcdef12345678',
    value: '2000000000000000000', // 2 ETH
  },
})

console.log(result.allowed)          // false
console.log(result.reason)           // why the engine decided that
console.log(result.matchedPolicyId)  // "ply_..." when a rule matched
console.log(result.matchedRuleId)    // "plr_..." when a rule matched
```

:::info
Policy endpoints authenticate with your secret key and require the `policies:read` scope to list or read, and `policies:write` to create, update, or delete.
:::

For full documentation on policy structure, evaluation logic, criteria types, and examples, see the [policies reference](https://www.openfort.io/docs/configuration/policies).

* [Policies overview](https://www.openfort.io/docs/configuration/policies) — How policies work, scopes, evaluation algorithm, managing policies, and getting started.
* [Rules reference](https://www.openfort.io/docs/configuration/policies/rules-reference) — Policy structure, allowlist vs denylist patterns, pre-flight evaluation, and limits.
* [Ethereum rules](https://www.openfort.io/docs/configuration/policies/ethereum-rules) — Operations and criteria for Ethereum transaction signing, message signing, and typed data.
* [Solana rules](https://www.openfort.io/docs/configuration/policies/solana-rules) — Operations and criteria for Solana transaction signing and message signing.
