Skip to main content

Grammar

The grammar has been designed for flexibility and expressiveness. We currently support the following operations:

Operator precedence

If you use both && and || in a condition, use parentheses. The policy engine gives && and || the same precedence and groups them from left to right (many programming languages group && first).
For example, suppose that you want to match any transaction to address <A>, OR a zero-value transaction to address <B>. The following condition does not match these transactions.
The policy engine evaluates this condition as (eth.tx.to == '<A>' || eth.tx.to == '<B>') && eth.tx.value == 0. As a result, the condition matches only zero-value transactions. A non-zero transaction to <A> does not match.To match the transactions that you want, use parentheses:
The policy engine groups operators in this order, from first to last:
  • The policy engine groups comparisons before && and ||. For example, a == 1 && b == 2 means (a == 1) && (b == 2).
  • ! and - apply only to the single operand immediately after them, so !x == y means (!x) == y. To negate a larger expression, use parentheses: !(x == y).
  • The policy engine always evaluates both operands of && and ||, even when the left operand already decides the result. See Policy evaluation.

Keywords

Keywords are reserved words that are dynamically interchanged for real values at evaluation time. Each field supports a different set of keywords.

Consensus

Condition

Time

The optional top-level time field gates when a policy is active. See Time-based policies for the authoring guide, and Time expressions below for the Timestamp and CronSpan reference.The <tz> argument of CronSpan is an IANA time zone name (e.g. America/New_York) — see the IANA time zone list for the full set of names.

Types

The language is strongly typed which makes policies easy to author and maintain.

Primitive

Struct

The ContractArgument type, used in documentation for ABI and IDL arguments represents an enum indicating this type could be any one of the string, number, array or struct types listed in our Primitives section.

Nested structs

Time expressions

Two functions are available when authoring the top-level time field. This section is the reference for their signatures and constraints; see Time-based policies for the model behind them and worked examples.

Timestamp

Timestamp('<rfc3339>') constructs a timestamp from an RFC 3339 string. Timestamps must have a zero UTC offset: the evaluator parses RFC 3339 and accepts any literal whose offset is zero — Z, z, +00:00, or -00:00. Non-zero offsets (e.g. -05:00) are rejected.timestamp values support the comparison operators (<, >, <=, >=, ==, !=), so they can be compared against time.now to bound when a policy is active:

CronSpan

CronSpan('<cron>', '<duration>', '<tz>') returns true when time.now falls inside any window opened by the schedule. See Active time spans for the fire-plus-duration model and its daylight-saving behavior.Cron expressions use a strict 5-field subset: minute hour day-of-month month day-of-week, where day-of-week is numeric 0-6 and 0 is Sunday. Numeric fields, ranges (1-5), lists (1,3,5), and * are supported. The following are not supported: step values (*/n), macros (@daily, @hourly), month and day names (JAN, MON), and a seconds field.Day-of-month and day-of-week are OR’d, not AND’d: when both fields are restricted, the cron fires when either matches, and this subset has no modifier to force AND semantics. This can broaden the window in which a policy is active — see Active time spans for details.Durations use a custom whole-number format composed of days, hours, and minutes (d, h, m) — for example 8h, 90m, or 1d12h. Fractional values and a seconds component are not allowed, and the total duration must be greater than zero and no more than 7 days.The <tz> argument accepts any IANA time zone name — see the IANA time zone list for the full set of names.

Activity breakdown

Activity resources and actions

Valid activity.resource values are AUTH, AUTH_PROXY, CONFIG, CREDENTIAL, FIAT_TRANSACTION, INVITATION, MFA_POLICY, ON_RAMP_CREDENTIALS, ORGANIZATION, OTP, PAYMENT_METHOD, POLICY, PRIVATE_KEY, RECOVERY, SESSION_PROFILE, SMART_CONTRACT_INTERFACE, SPONSORSHIP, SUBSCRIPTION, TVC_APP, TVC_DEPLOYMENT, TVC_OPERATOR, TVC_QUORUM_KEY, USER, WALLET, and WEBHOOK_ENDPOINT.Valid activity.action values are CREATE, UPDATE, DELETE, SIGN, EXPORT, IMPORT, VERIFY, and ENCRYPT.

Activity types by resource and action

** In the Activity breakdown table above, ** marks legacy features deprecated in the latest SDKs. This note applies only to that table.

Activity kinds

activity.kind groups all versions of an activity under one version-agnostic value. The table below lists each kind and the activity types it matches.
The kinds for root quorum activities can be matched by MFA policy conditions and session profile scopes, but a policy can’t allow those activities.
Prefer activity.kind over activity.type when you want a policy to apply across all versions of an activity. activity.type targets one exact version and will not match newer versions introduced later.

Choosing between type, kind, and resource + action

There are three ways to target activities in a policy condition. Pick based on how broad you want the match to be:
Rule of thumb: use activity.kind to target a single activity (version-agnostic), and activity.resource + activity.action to target a broad category. Reach for activity.type only when you deliberately need one exact version.

Evaluation errors and short-circuiting

A policy condition causes an evaluation error when it uses a keyword or field that the activity does not populate. For example, eth.eip_7702_authorization on ACTIVITY_TYPE_SIGN_TRANSACTION_V2, or an activity parameter that the activity does not expose.If a policy’s condition causes an evaluation error, the policy is skipped:
  • An ALLOW policy with an error does not allow the activity.
  • A DENY policy with an error does not deny the activity, so another ALLOW policy can still allow it.

Short-circuiting

Note that our policy engine does not short-circuit during evaluation. Specifically, the policy engine evaluates every clause of a condition, because && and || do not short-circuit. If any clause causes an error, the entire policy will error, even if another passes.For example, suppose you have a policy with the condition as wallet.id == '<WALLET_ID>' || private_key.id == '<PRIVATE_KEY_ID>'. This will, by construction, always cause an error, because a signing activity can use a wallet or a private key, but not both: when you sign with a private key, the wallet.id clause causes an error. When you sign with a wallet, the private_key.id clause causes an error. Short-circuiting in this scenario means that if the first clause passes, the second clause would not be evaluated, thereby preventing such an error — our policy engine does not behave in this way.

Example: one policy for two activities

This policy tries to allow two things: signing Type 2 transactions, and signing EIP-7702 authorizations for one trusted delegate contract:
This policy never allows either activity:
  • For ACTIVITY_TYPE_SIGN_TRANSACTION_V2, the policy engine also evaluates eth.eip_7702_authorization.address, which this activity does not populate.
  • For ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2, the policy engine also evaluates eth.tx.type, which this activity does not populate.
In both cases, the condition causes an evaluation error and the policy is skipped. We recommend writing one policy for each activity instead:

Guidelines

  • Keep related clauses for one activity, such as the address and chain_id limits of one allowlist, in one policy joined with &&.
  • Do not join clauses for different activities with ||. Write a separate policy for each activity.
  • A DENY policy that uses a keyword that only some activities populate has no effect on the other activities. For example, a DENY policy with the condition eth.eip_7702_authorization.chain_id == 0 does not deny anything that ACTIVITY_TYPE_SIGN_RAW_PAYLOADS signs.

Appendix

Activity parameters

The activity.params field exposes specific request parameters based on the activity type. An activity may have API request parameters without exposing them through activity.params; only the fields listed below are available to policy conditions.Absence from this table does not mean that an activity is unsupported or cannot be targeted with activity.type, activity.kind, or activity.resource and activity.action. It means that the policy evaluator exposes no request fields for that activity. Attempting to access an unavailable field produces a MissingField evaluation error. See Evaluation errors and short-circuiting for more details. To request an additional policy-exposed parameter, contact help@turnkey.com.
For swap and earn policies, prefer activity.kind (for example CREATE_SWAP_QUOTE, EXECUTE_SWAP, EARN_DEPOSIT) when you want version-stable conditions. Use activity.type when you must pin a specific API version—for example, destination_address is available on ACTIVITY_TYPE_CREATE_SWAP_QUOTE_V2 and ACTIVITY_TYPE_EXECUTE_SWAP_V3, not on the earlier quote or execute activity types. Swap and Earn numeric params (input_amount, slippage_bps, assets, client_fee_bps, and similar) compare as uint values; empty or non-decimal strings fail evaluation with a parse error rather than matching a cap as zero. Earn amount_value stays a string because withdrawals may use the literal MAX. See the Swaps and Earn policy examples for allowlists, sponsorship controls, slippage caps, and administrative Earn rules.

Examples

To deny signing raw payloads with the NO_OP hash function (except for EIP-712):
To allow a user to delete only themselves:

Root quorum activities

There are a select few activities that are not governed by policies, but rather by an organization’s root quorum. These activities are: ACTIVITY_TYPE_UPDATE_ROOT_QUORUM, ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE, ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE, ACTIVITY_TYPE_UPDATE_ORGANIZATION_NAME. For example, if a policy is added that allows a specific non-root user to perform ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE activities, these requests will still fail as they are subject specifically to root quorum.Policies can’t allow these activities, but MFA policy conditions and session profile scopes still apply to them. Both can reference:
  • activity.type and activity.kind
  • activity.resource, which is ORGANIZATION
  • activity.action, which is UPDATE
These activities have no activity.params. A condition that references activity.params.* can’t be evaluated for them: an MFA policy that uses one is skipped, and a session profile scope that uses one denies the request.A session profile scope only narrows what a session can do. A request whose scope matches still needs root quorum approval.

Activities that target a root user

Users outside the root quorum can’t modify users in the root quorum. If a non-root user submits any of the activities below against a root quorum user, the request is denied before any policy is evaluated, so no policy can allow it:
  • ACTIVITY_TYPE_CREATE_AUTHENTICATORS_V2, ACTIVITY_TYPE_DELETE_AUTHENTICATORS
  • ACTIVITY_TYPE_CREATE_API_KEYS, ACTIVITY_TYPE_CREATE_API_KEYS_V2, ACTIVITY_TYPE_DELETE_API_KEYS
  • ACTIVITY_TYPE_CREATE_OAUTH_PROVIDERS, ACTIVITY_TYPE_CREATE_OAUTH_PROVIDERS_V2, ACTIVITY_TYPE_DELETE_OAUTH_PROVIDERS
  • ACTIVITY_TYPE_UPDATE_USER, ACTIVITY_TYPE_UPDATE_USER_NAME, ACTIVITY_TYPE_UPDATE_USER_EMAIL, ACTIVITY_TYPE_UPDATE_USER_PHONE_NUMBER
  • ACTIVITY_TYPE_DELETE_USERS, when any of the users being deleted is a root user
The request fails with a permission error and no policy evaluations are recorded. For example, a non-root recovery user cannot add a passkey to a root user, even with a policy that allows CREATE_AUTHENTICATORS.

Activities a user can perform on themselves

A user can manage their own authenticators, API keys and MFA policies without a policy granting it. When no policy reaches a decision, the engine allows the activities below as long as the user submitting the request is targeting themselves.
  • ACTIVITY_TYPE_CREATE_AUTHENTICATORS_V2, ACTIVITY_TYPE_DELETE_AUTHENTICATORS
  • ACTIVITY_TYPE_CREATE_API_KEYS_V2, ACTIVITY_TYPE_DELETE_API_KEYS
  • ACTIVITY_TYPE_RECOVER_USER
  • ACTIVITY_TYPE_CREATE_MFA_POLICY, ACTIVITY_TYPE_UPDATE_MFA_POLICY, ACTIVITY_TYPE_DELETE_MFA_POLICY
  • ACTIVITY_TYPE_CREATE_READ_ONLY_SESSION, for any requesting user, since it only creates a session for that user
Note that this self-targeting behavior applies only under the following conditions:
  • No policy produced a decision. For non-root users an explicit allow or deny stands, so a policy that denies ACTIVITY_TYPE_CREATE_API_KEYS_V2 denies it for the user’s own keys too.
  • The request targets the organization it is submitted to. A parent organization user acting on a sub-organization user is not allowed by default and needs a policy.
  • The requesting user’s MFA policy, if any, is satisfied. Otherwise the activity requires additional authenticators before it runs.
  • The request did not already meet the root quorum. A request that does is allowed before policies are evaluated, so root users rarely need the allowance. A root user below the threshold can still act on their own credentials through it. For anything else, a root user below the threshold acts alone only when a policy allows it. Any other outcome for a root user, including an explicit deny, becomes a request for quorum approval rather than a denial.
This default is what lets a scoped recovery session enroll a passkey for only the authenticated user. A policy condition or session profile scope can pin the target of CREATE_AUTHENTICATORS_V2 and the API key activities to a fixed user with activity.params.user_id, but neither can refer to the user submitting the request. The approvers and credentials keywords identify the requester and are not available in a condition or scope, and a consensus expression cannot read activity.params. A session scoped only to the activity kind therefore adds authenticators to the session holder alone, as long as no policy allows the activity for other users and the request does not meet the root quorum.
Wallet and private key import activities and ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION must always target the requesting user. A request for another user is denied before policies are evaluated, and no policy can allow it.

Ethereum

Our Ethereum policy language (accessible via eth.tx) allows for the granular governance of signing Ethereum (EVM-compatible) transactions. Our policy engine exposes a fairly standard set of properties belonging to a transaction.See the Ethereum policy examples for sample scenarios.
The policy engine’s int type is limited to 128 bits (i128). Ethereum smart contracts support signed integers up to 256 bits (int256), but values exceeding the 128-bit signed range cannot be used in policy conditions.

EIP-712

Our policy engine supports EIP-712 typed data signing (accessible via eth.eip_712). When defining policies for EIP-712 messages, please ensure that all hex-encoded strings (e.g. addresses, function selectors, bytes) are lowercase. The policy engine expects lowercase hex strings to conform to Ethereum’s standard convention. Using uppercase hex strings may result in errors or policy rejection. Note that EIP-712 messages passed in as transactions will be normalized to lowercase.

EIP-7702

eth.eip_7702_authorization is an EIP-7702 authorization that the signing key signs as a message. It does not describe the authorization list of a Type 4 transaction. Policies on transactions use eth.tx (see Type 4 transactions). The policy engine populates eth.eip_7702_authorization only for these activities:
  • ACTIVITY_TYPE_SIGN_RAW_PAYLOAD and ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2. The policy engine reads the payload as an authorization for all encodings, so an ALLOW policy must also contain activity.params.encoding == 'PAYLOAD_ENCODING_EIP7702_AUTHORIZATION'. Without this check, the policy also allows EIP-712 typed data, such as a token permit, that contains address, chainId, and nonce fields.
  • ACTIVITY_TYPE_ETH_SEND_TRANSACTION and ACTIVITY_TYPE_ETH_SEND_TRANSACTION_V2, when Turnkey builds an authorization to its gas delegate contract. This occurs for sponsored transactions and for non-sponsored ACTIVITY_TYPE_ETH_SEND_TRANSACTION_V2 requests with more than one call, when the account is not yet delegated. A request without an authorization causes an evaluation error, so do not require eth.eip_7702_authorization in ALLOW policies for these activities.
  • ACTIVITY_TYPE_ETH_UNDELEGATE_7702.
For all other activities, the keyword causes an evaluation error. See Evaluation errors and short-circuiting for more details. There is no plural eth.eip_7702_authorizations keyword — if you attempt to create a policy with it, it’ll get rejected.
ACTIVITY_TYPE_SIGN_RAW_PAYLOADS does not populate eth.eip_7702_authorization for any encoding. If an ALLOW policy for this activity does not limit activity.params.encoding, the key can sign authorizations for any contract. Deny batch signing of EIP-7702 authorizations blocks only PAYLOAD_ENCODING_EIP7702_AUTHORIZATION. The key can still sign authorizations as hexadecimal or UTF-8 payloads (see below). If a key must not sign authorizations, allow this activity only with activity.params.encoding == 'PAYLOAD_ENCODING_EIP712'.
What a signed authorization allows
Anyone who has a signed authorization can send it in a Type 4 transaction from any account, with no other signature from the key. The network gets the delegated account from the authorization signature, not from the sender. After that, calls to the account run the code at address until another authorization replaces it. If that code does not verify the caller, anyone can move the funds of the account. Write the ALLOW policy as an allowlist:
  • address: Only delegate contracts that you trust, with == or in. A list of bad contracts in a DENY policy does not work, because an attacker can deploy a new contract.
  • chain_id: The chains that you use. An authorization with chain_id 0 is valid on all EVM chains.
  • nonce: An authorization is usable only when the account nonce is equal to its nonce, so an authorization with a future nonce stays usable until the account nonce is more than its nonce.
The policy engine gives address in the EIP-55 checksummed (mixed-case) form, and the comparison is case-sensitive. Write each address in your policy in the checksummed form. An address in another case never matches, so an ALLOW policy does not allow the authorization and a DENY policy does not deny it.Raw payload signing with other encodings can also sign an authorization. A PAYLOAD_ENCODING_HEXADECIMAL payload can be the authorization hash (HASH_FUNCTION_NO_OP) or the authorization message (HASH_FUNCTION_KECCAK256). A PAYLOAD_ENCODING_TEXT_UTF8 payload can be the authorization hash if the delegate address makes that hash valid UTF-8. These payloads do not parse as authorizations, so eth.eip_7702_authorization causes an evaluation error, and a limit on activity.params.hash_function does not stop this. An ALLOW policy that permits these encodings can sign authorizations.If a key must not sign authorizations, allow raw payload signing only with activity.params.encoding == 'PAYLOAD_ENCODING_EIP712'. Do not deny encodings one at a time. This also blocks signMessage in @turnkey/viem and @turnkey/ethers, which signs PAYLOAD_ENCODING_HEXADECIMAL payloads with HASH_FUNCTION_NO_OP. No policy can stop a key that signs these payloads from signing an authorization. If you need both, use separate keys. To let a key sign only the authorizations that your policy allows, also allow PAYLOAD_ENCODING_EIP7702_AUTHORIZATION, but only for ACTIVITY_TYPE_SIGN_RAW_PAYLOAD and ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2. Also, ACTIVITY_TYPE_ETH_SEND_TRANSACTION(_V2) requests that include an authorization sign one to the Turnkey gas delegate contract, and ACTIVITY_TYPE_ETH_UNDELEGATE_7702 signs one to the zero address.For examples, see Allow signing of EIP-7702 authorizations.
Type 4 transactions
ACTIVITY_TYPE_SIGN_TRANSACTION_V2 does not populate eth.eip_7702_authorization, and the policy engine does not expose the authorization list of a Type 4 transaction. Signing a Type 4 transaction does not delegate the signer, because each entry in the list has its own signature from its authority, over a different message format. To control Type 4 transactions, use eth.tx.type. For more information, see EIP-7702 (type 4) support.

Solana

Similarly, our Solana policy language (accessible via solana.tx) allows for control over signing Solana transactions. Note that there are some fundamental differences between the architecture of the two types of transactions, hence the resulting differences in policy structure.Notably, within our policy engine, a Solana transaction contains a list of Transfers, currently corresponding to native SOL transfers. Each transfer within a transaction is considered a separate entity. Each entity represents only top-level transfers that directly invoke supported System Program transfer instructions and do not include transfers performed indirectly inside other programs, or via unsupported System Program instructions.Similarly, the policy engine exposes solana.tx.spl_transfers, which contains only top-level SPL transfers using the supported Token and Token-2022 instructions Transfer, TransferChecked, and TransferCheckedWithFee. SPL transfers performed indirectly inside other programs or via unsupported Token and Token-2022 instructions are not detected and do not appear in this list.Here are some approaches you might take to govern transfers:
  • All transfers need to match the policy condition. Useful for allowlists (example)
  • Just one transfer needs to match the policy condition. Useful for blocklists (example)
  • Only match if there is a single transfer in the transaction, and that transfer meets the criteria (example). This is the most secure approach, and thus most restrictive.

Solana V1 config

See Solana transactions for wire-format requirements. solana.tx.version returns the wire version of unsignedTransaction as a case-sensitive string: LEGACY, V0, or V1. Sponsorship preserves this version. It is independent of the Turnkey activity version.The following fields expose the V1 transaction config in unsignedTransaction, before sponsorship fills missing values:priority_fee_lamports is a total priority fee, not a per-CU price. It excludes base fees and rent. An explicit zero remains zero in the policy value. An absent resource limit is unavailable, rather than zero or a runtime default. For legacy/V0 transactions, access to any of these four fields produces a FieldNotUsed evaluation error.
The policy engine does not short-circuit && or ||. A condition such as solana.tx.version == 'V1' && solana.tx.priority_fee_lamports <= 1000 still evaluates the fee field for legacy/V0 and produces an error. Use separate, fully scoped allow policies for the transaction versions you accept. See Evaluation errors and short-circuiting for more details.

Account address lookups

V0 transactions can reference onchain address lookup tables for account addresses. Legacy and V1 transactions have no ALTs; their address_table_lookups lists are empty. Turnkey surfaces any account address pulled from a lookup table as the literal string ADDRESS_TABLE_LOOKUP in Solana address fields (account_keys, instruction accounts, transfers, and spl_transfers). The solana.tx.address_table_lookups array indicates when lookups are present, but the specific addresses are not resolved. If you rely on allowlists or denylists of addresses, add a guard for this placeholder (for example, require solana.tx.address_table_lookups.count == 0 before comparing addresses, or explicitly deny when ADDRESS_TABLE_LOOKUP appears with something like solana.tx.transfers.any(t, t.to == 'ADDRESS_TABLE_LOOKUP')) so that dynamic lookups cannot bypass or unexpectedly fail your policy. See the address table lookup examples for examples on how to enforce this.

Program address lookups

Turnkey rejects Solana transactions where program addresses are resolved via address lookup tables. Program IDs must be statically defined in the transaction to enable static analysis of instructions without requiring onchain data lookups. If your transaction references a program via an address table lookup, the signing request will fail. Account addresses (non-program) can still be dynamically resolved via lookup tables as described above.See the Solana policy examples for sample scenarios.

Tron

Our Tron policy language (accessible via tron.tx) allows for policy control over signing Tron transactions. Our policy language supports the standard fields in a Tron transaction: https://developers.tron.network/docs/tron-protocol-transaction. To reference a Contract within a Transaction you should use tron.tx.contract[0].field_name in your policy where field_name is some field of the contract used in your transaction. While Tron only currently supports 1 contract per transaction this could change in the future, and we’re ready for it if it does! The policy engine currently supports the following Tron contract types:
  • TransferContract (TRX transfers)
  • TriggerSmartContract (Smart contract, including, but not limited to TRC-20, invocations)
  • DelegateResourceContract
  • UnDelegateResourceContract
  • FreezeBalanceV2Contract
  • UnfreezeBalanceV2Contract
  • AccountPermissionUpdateContract
See the Tron policy examples for sample scenarios.

Bitcoin

Our Bitcoin policy language (accessible via bitcoin.tx) allows for policy control over signing Bitcoin transactions.NOTE: While our SIGN TRANSACTION endpoint takes in a Partially Signed Bitcoin Transaction (PSBT) as required for signing context — our policy language supports only the standard fields inside a Bitcoin transaction: https://learnmeabitcoin.com/technical/transaction/#structureFor further reference on how Turnkey handles Bitcoin transactions in our policy-enabled transaction signing flow, check out this section in our Bitcoin Network Support page.See the Bitcoin policy examples for sample Bitcoin policies.

Spark

Spark-specific activities expose their request data through activity.params. The activity parameter table lists the top-level fields for all four Spark activities, and the structs below describe the nested values available to policies.Spark optional string fields evaluate to an empty string when omitted. SparkKeyDerivation supports five variants: identity, signing_leaf, deposit, static_deposit, and htlc_preimage. Only signing_leaf and static_deposit have variant-specific data, so those are the only variants with nested fields (see table below).At policy runtime, inactive variant fields evaluate to their type defaults rather than producing an evaluation error. For example, by default signing_leaf.leaf_id would an empty string, and static_deposit.index would return 0. These defaults do not indicate that the variant is active. We’d recommend checking SparkKeyDerivation.type before targeting a variant-specific field. Note: the type field is an empty string when unset, and 0 is a valid static deposit index.See the Spark policy examples for sample policies covering receiver allowlists, FROST key derivations, static deposits, and receive-only delegated access.

Tempo

Our Tempo policy language (accessible via tempo.tx) allows for policy control over signing Tempo transactions. Tempo transactions natively support batched calls — a single transaction can contain one or more calls that execute atomically. The tempo.tx.calls list gives you access to each individual call, including its destination and raw input data.The tempo.tx namespace exposes the following transaction-level fields: chain_id, from, nonce, gas_limit, max_fee_per_gas, max_priority_fee_per_gas, fee_token, valid_before, and valid_after. Each call in tempo.tx.calls exposes: to, input, and function_signature.You can also govern Tempo transactions at the activity level using activity.params.type == 'TRANSACTION_TYPE_TEMPO', combined with other fields such as specific wallets, private keys, or consensus rules.See the Tempo policy examples for sample scenarios.

Secrets

Export secrets requests expose two keywords: secret, the secret being evaluated, and request_context, the string key-value pairs the request binds to that secret. Each secret in a batch is evaluated separately, and batch export is all-or-nothing. Read both by key and compare them with strings:
  • Reading a key the request does not carry is an evaluation error. An erroring EFFECT_ALLOW policy does not allow, and an erroring EFFECT_DENY policy does not deny, so a deny policy on request_context can be skipped by omitting the key. Prefer allow policies when gating on request context.
  • An export that repeats a key within one secret’s request context is rejected before policy evaluation.
See Managed Secrets for how request context is set and signed, and the key management solutions for more policies.