Validate conditions against a beta API key, shown as Development in the Developer Portal. Policies reach production only through a production review: select Request production review on your production key.
Condition kinds
Leaf conditions read one fact. Group conditions combine other conditions, so one rule can express AND, OR and NOT logic.- compare
- aggregate
- all, any, not
Operators
Each fact supports the operators its value type allows. The fact tables list them per fact.ne does not match a missing fact. A rule that reads a fact the request does not provide is indeterminate, whatever the operator.Values and encodings
Each value must have the fact’s type. A wrong type fails validation withvalue_type_mismatch.
Amounts are base units: wei and token units on EVM (1 USDC is
"1000000" with 6 decimals), lamports on Solana, the chain’s base denom on Cosmos (such as uatom), stroops on Stellar, and MIST on Sui. Token amounts use the token’s smallest unit as well: the mint’s decimals on Solana, the denom’s integer amount on Cosmos, and 7 decimals for every Stellar asset, so 1 USDC on Stellar is "10000000".
Identifiers by wallet type
Write addresses and assets in the canonical form of the policy’s wallet type, exactly as shown.
For a Stellar network other than testnet or mainnet,
<hash> is the SHA-256 hash of the network passphrase in lowercase hex. On EVM, eq, ne and in on request.token.asset and request.safe.token.asset compare the contract-address part of eip155:<chainId>:token:<contract> without regard to case. The prefix and chain ID must still match exactly.
Limits
Condition groups and leaves share these depth and count limits; metered facts also constrain window declarations.Reading the fact tables
The tables below list every fact a policy can read for each wallet type, outside Metered facts. The Actions column lists the rule actions that can read the fact. Every action in a rule’sactions must appear there, or validation fails with fact_action_unsupported. all means every action of the wallet type, including raw_signature, and - means no rule can read the fact.
The Present column says whether every request of those actions carries the fact. “May be missing” means Para provides the fact only when it can read it from the request, such as a recipient decoded from calldata. A rule that reads a missing fact is indeterminate and can deny the request; see Facts Para cannot read.
"actions": "all" covers every action of the wallet type, raw_signature included, but the validation fact check leaves raw_signature out. An "all" rule can therefore read only request.classification, the para.wallet.* facts and, on Solana, Cosmos, Stellar and Sui, request.actionFamilies. A raw signature has no request.actionFamilies, so a condition on it is indeterminate on a raw signature unless another condition in its group settles it, and Para then denies the raw signature unless another matching rule has the same or a stronger effect. See Facts Para cannot read.
A rule that names raw_signature can read only the para.wallet.* facts.
EVM
Choose facts by the signing action: EVM transaction and message actions expose different fields.
What each fact holds on EVM:
The Para client and server SDKs, including their viem, ethers and wagmi integrations, sign EIP-712 typed data and EIP-7702 authorizations as a message over their hash, so Para evaluates those requests as
sign_message. The sign_typed_data and sign_authorization actions, and the facts Para reads from typed data and authorizations, such as request.typedData.primaryType, apply only to the REST API’s sign-typed-data and sign-authorization routes, which the REST SDK calls.
Para decodes ERC-20 and NFT calls itself. For other contract calls it uses the contract’s verified ABI from a block explorer. Calls it cannot decode have the classification undecodable_contract_call and no request.method, request.args[n], request.to or request.contract.address.
A native send that carries any calldata is call_contract, not transfer_native. request.value.baseUnits is present on every EVM transaction, "0" when it attaches no value, so a native amount cap can name both actions.
request.raw.opaque is in the catalog, but no rule can read it. Para sets it only on raw signatures, and raw_signature rules read only para.wallet.* facts, so validation rejects it with fact_action_unsupported on every action.Safe payments
Therequest.safe.* facts describe the payment inside a Safe transaction. Para reads them from two kinds of request:
- An
execTransactioncall, with the actionexecute_safe_transaction. - A
SafeTxEIP-712 message sent to RESTsign-typed-data, with the actionsign_typed_data. Its domain must hold onlychainIdandverifyingContract, its message must hold exactly theSafeTxfields, and itstypesmust declare onlySafeTx, optionally with anEIP712Domainof those two fields; otherwise Para treats it as opaque. ASafeTxsigned through the Para client and server SDKs arrives assign_messageand has no Safe facts.
operationis0, a Call. A DelegateCall is never a payment.gasPriceis0, so the Safe pays no gas refund.- The inner
tois not the Safe itself. - The inner call is a plain native transfer, or one ERC-20
transferortransferFromthat sends no native value.
request.safe.to and the two facts of its payment family. The facts of the other family are not applicable.
A condition on a fact of the other family is not applicable and never matches. A rule that reads only native payment facts therefore does not apply to an ERC-20 payment, or the reverse, and the request goes on to your other rules or the default.
A zero-amount payment is still readable. Its amount conditions are evaluated as usual, so
"op": "gt", "value": "0" does not match it, and the other family stays not applicable.
Every other Safe transaction is opaque, and all of its request.safe.* facts are missing. Opaque transactions include:
- DelegateCalls and MultiSend batches.
SafeTxtyped data in another shape, such as a domain with extra fields.- Transactions with a nonzero
gasPrice. - Calls to the Safe itself, such as owner and threshold changes.
- Nested Safe calls, such as
execTransactionorapproveHashon another Safe. - Contract calls other than one ERC-20
transferortransferFrom, and calldata Para cannot decode. - An ERC-20 transfer that also sends native value.
request.safe.* fact is indeterminate on an opaque transaction and can deny it with missing-fact. An approval does not help: once another rule’s approval case completes, the approved rule no longer counts, so the indeterminate rule can still deny the signing request.
Three facts are the same for a readable payment and an opaque transaction: request.classification, request.method and request.typedData.primaryType. On execute_safe_transaction, the decoded execTransaction arguments separate DelegateCalls and gas refunds: request.args[3] is the operation and request.args[6] is the gasPrice, and both are "0" in every readable payment. No fact separates the other opaque forms, or any opaque SafeTx typed data.
To keep a sign_typed_data rule that reads Safe facts from denying other typed data, add a request.typedData.primaryType test to an all group:
request.safe.to names the inner recipient whatever native value the outer call carries. On execute_safe_transaction, constrain request.value.baseUnits as well. sign_typed_data has no request.value.* facts, so a rule that reads them cannot name both actions.
This Guardrail covers app-owned wallets that execute Safe transactions on Base. The first rule denies Safe payments to anyone except two recipients, and because it reads request.safe.to, it also denies every opaque execTransaction. It does not cover direct calls to the Safe; see Direct calls to the Safe.
The second rule denies a USDC payment that would take the Safe past 50,000 USDC in the current day. It counts only readable payments, so on its own it would not stop a MultiSend batch, a DelegateCall or a gas refund, and the first rule denies those. A payment that passes both rules falls to the Guardrail default, and the wallet signs it.
safe-payouts.json
Direct calls to the Safe
An owner wallet that calls the Safe directly, such asapproveHash(safeTxHash) to approve a payment on chain, sends a call_contract with no Safe facts, so Safe rules and Safe spend limits never see it. A rule that reads Safe facts cannot name call_contract; validation fails with fact_action_unsupported. To block these calls, deny every call_contract whose request.target is the Safe:
execTransaction stays under your Safe rules. Use require_approval instead of deny to hold these calls for review. request.target is always present and compared without case, so the rule works whether or not Para decodes the call. Do not test request.method instead: it is missing when Para cannot decode the call, so that rule would deny every contract call Para cannot decode.
Solana
Solana’s catalog separates native and token transfer facts from program targets.
On Solana, Cosmos, Stellar and Sui,
request.actionFamilies lists the kinds of action a transaction contains. request.to and the amount facts are present only when the transaction contains exactly one action; Cosmos retains request.target when MsgExecuteContract is the transaction’s only message, even if attached funds add transfer actions. Solana compute budget instructions do not count as an action. Creating the recipient’s associated token account does not count either when the transaction’s only other instruction is a TransferChecked that follows it and sends that token to the new account. Every other instruction counts, such as a Memo or wrapping SOL, so a rule that reads a recipient or amount can deny a transfer that includes one.
request.tois the recipient of a SOL transfer. For a token transfer it is the destination token account. A wallet address in your condition also matches that wallet’s associated token account for the transfer’s mint, for SPL Token and Token-2022. Another token account the wallet owns does not match.request.targetis the program the instruction calls.request.token.assetnames the mint, assolana:token:<mint>. It does not identify the cluster, so select the network in the policy’schainId.- Para reads a token transfer’s recipient, amount and mint only from a
TransferCheckedinstruction. A plainTransferorTransferCheckedWithFeehas none of these facts, and token spending limits do not count it.
solana-usdc-payouts.json
Cosmos
Cosmos facts distinguish bank sends from contract calls. The notes below describe which requests provide recipient, target and amount fields.request.tois the recipient of a bank send.request.targetis the contract a singleMsgExecuteContractcalls. Transfers have none.- A bank send is a native transfer only in the chain’s native denom, on
cosmoshub-4,noble-1,osmosis-1,celestia,dydx-mainnet-1andinjective-1. Any other denom, or any bank send on another chain, is a token transfer. - As on Solana, recipients, targets and amounts are present only for a transaction with exactly one message.
Stellar
Stellar facts cover payments and contract calls; the notes below explain operation-specific availability.request.tois the destination account of a payment.request.targetis the contract a SorobaninvokeContractcall targets.request.token.assetandrequest.value.assetinclude the network, so a condition written forstellar:testnetdoes not match on mainnet.- Recipients, targets and amounts are present only for a transaction with exactly one operation.
createAccountis atransfer_native. A path payment carriestransfer_nativewhen any of its assets is XLM andtransfer_tokenswhen any is another asset, with no recipient or amount facts, so a rule that reads an amount is indeterminate on it and spending limits do not count it.
Sui
Sui exposes native transfer and Move call facts. The notes below describe transfer families and the limits of token authoring.request.tois the recipient of a SUI transfer.request.targetis the package a Move call targets.- Sui has no
transfer_tokensaction, authorable token facts or token spending limits. Only a rule that names"all"covers Sui token transfers. With trusted coin evidence, a readableSplitCoinsfollowed byTransferObjectscan reporttoken_transferinrequest.actionFamilies; unrecognized transfers reportother. - Recipients, targets and amounts are present only for a transaction with exactly one action, such as a single transfer.
Classification values
request.classification accepts these 22 values on every wallet type. Values that a wallet type never produces never match, and a value outside this list fails validation with value_not_allowed_for_fact.
Only a rule with
"actions": "all" can read the classification of a raw signature, evm.raw_signature or raw.opaque_message. A rule that names raw_signature reads only para.wallet.* facts.
Metered facts
Metered facts read the spend Para tracks for a wallet over a time window. Use them only inaggregate conditions; a compare condition on a metered fact fails with metered_fact_window_required.
The Actions column covers all wallet types. On EVM,
wallet.spend.native is available to all seven listed actions, because any EVM transaction can send native value. On Solana, Cosmos, Stellar and Sui it is available only to transfer_native. wallet.spend.token does not apply to Sui, which has no token transfer action. safe.spend.native and safe.spend.erc20 count only Safe payments; see Safe spend.Windows
window is a positive integer followed by a unit: ms, m, h or d, such as "30m", "24h" or "7d". There is no week or month unit. The Developer Portal form writes windows in hours, "24h" for a day and "168h" for a week, and the examples on these pages follow it.
Windows are fixed buckets aligned to 1970-01-01 00:00 UTC, not rolling periods. A 24h window resets at 00:00 UTC every day, and a 168h window resets every Thursday at 00:00 UTC.
A policy can use only one window length for each metered fact. "24h" and "1d" count as the same length, but "24h" and "168h" on the same fact fail with metered_fact_window_conflict. To enforce both a daily and a weekly limit, put them in separate policies.
What the limit compares
Para compares the spend already recorded in the current window, plus spend reserved by requests still in progress, plus the current request’s amount, againstvalue. A rule with "op": "lte", "value": "1000000" therefore matches while the total after this request stays at or below 1,000,000.
What counts
Metering counts the transfer forms below, which can be narrower than a rule’s action coverage.
On
execute_safe_transaction, wallet.spend.native counts only the native value the signing wallet attaches to the outer call. The payment the Safe makes counts toward Safe spend instead.
Gas and network fees never count. On Solana and Sui, metering needs a network proven from the signed transaction; if configured proof endpoints prove no network, Para denies the request with network-unverifiable. On Cosmos, native spend counts only on the chains listed in Cosmos.
When a request has nothing to count for a condition, such as a zero-value transaction or a transfer of another token, the condition is not applicable and the rule does not match through it. Readable Solana native transfers and TransferChecked token transfers are summed by asset for metering, even when the transaction has no single recipient or amount fact. A meter whose applicable amount cannot be resolved is indeterminate.
Budgets
Each budget is kept per wallet, network, asset and window length.- A token limit with
assetcounts only that token. An EVM token limit withoutassetkeeps a separate budget for each token. wallet.spend.erc20andwallet.spend.tokenshare the same budget on EVM.- Budgets are shared across your policies and rules. Two rules that meter the same wallet, network, asset and window read the same spend.
- A selector with several networks does not pool them. A daily limit on Ethereum and Base allows that amount on each network.
- Safe spend budgets are kept per Safe instead of per wallet. See Safe spend.
When spend is recorded
Para reserves the request’s amount before signing and records the spend when the signing operation succeeds. Para can release the reservation when it knows signing did not proceed. If a dispatched call fails while the signer outcome is uncertain, the amount can remain reserved. A request adds to a budget only when a rule that meters that budget covers it: the rule that decided the request, a matchingallow rule, or a deny or require_approval rule whose other conditions match the request. A payment that falls outside a limit rule’s other conditions, such as a transfer to a recipient the rule does not name, does not count toward that limit.
Spend is reserved only for requests Para allows. A request approved through require_approval can take a budget past its limit. So can a request that went past an allow rule’s limit and was then approved, for example by the user in the review pop-up. It still counts toward that limit when the rule’s other conditions match it. If another request uses up the budget between the decision and the reservation, Para denies the request. The denial reason is windowed-spend-limit-exceeded.
Safe spend
safe.spend.native and safe.spend.erc20 count readable Safe payments, from execTransaction calls and from SafeTx messages sent to REST sign-typed-data. Wallet limits do not count these payments.
- Each budget is kept per API key, Safe, network, asset and window length. Your Guardrails and Requests share it: every
safe.spendrule with that window length reads the same spend, whichever wallet signs. - Owners who sign the same Safe transaction hash share one count. An
execTransactioncan use a counted co-signature’s credit when the payment matches, that co-signature has not already covered another execution, and Para recovers its signer from the first signature slot. A request covered by an already-counted key or this execution credit adds nothing, so the limit does not block it. safe.spend.erc20withoutassetcounts every ERC-20 payment, with a separate budget for each token.- A zero-amount native payment does not count, and neither does an ERC-20
transferFromthat pulls tokens from an address other than the Safe. The condition is not applicable to them.
Execution credit supports ECDSA signatures with
v of 27 or 28, in hex buffers with at most 32 complete 65-byte slots. Only the first complete slot is inspected. A matching signature in a later slot, another signature mode or failed signer recovery receives no credit, so the execution counts separately unless its own request count key was already counted.Reading usage
Read current spend withgetUserPolicyUsage in the client SDKs or getPartnerPolicyUsage in the REST SDK. Each meter reports the window, its reset time, and the committed, reserved and used amounts. Meters for allow rules that use lt or lte outside not and any also report the remaining amount. Each limit condition is its own meter, so when one rule has two limits on the same fact and window, the rule allows only the smaller remainingBaseUnits. See Permissions types for the response shape.
Safe meters appear only when the usage request passes safeAddress. In the client SDKs, they also need one of the user’s wallets to have made a payment request that Para metered against that Safe on that network.
User-adjustable parameters
A Request can let each user set their own amount for a limit. Add aparameter to a compare or aggregate condition, and its value becomes the default.
- Only Request policies can be personalized. A Guardrail with a parameter validates, but its default always applies.
- A user who changes their values must consent to the policy again.
- Para enables adjustable parameters per API key, so beta and production keys are enabled separately. Until it does, validating or saving a policy with a parameter fails with
permissions_v2_extension_unavailable.