para keys permissions commands check a Guardrail or Request policy written as JSON against your API key and move it from draft to active to retired. The same commands run in a terminal or in a CI job.
You author and test policies on your beta API key. The CLI cannot change production policies: once a policy works on beta, you ask Para to review it and apply it to your production key.
Before you start
Every command acts on one API key in your selected organization and project, so set that context first.1
Install the CLI and sign in
Install the CLI, then sign in with your developer account.
2
Select the organization and project
3
Find your beta key
KEY_ID. The Developer Portal shows this key as the Development key. If the project has a single beta key, you can leave KEY_ID out.The CLI uses beta keys unless you changed its default. If
PARA_ENVIRONMENT, a .pararc file, or defaultEnvironment selects prod, add --environment beta to the commands on this page.Inspect the key
Read what the key already has before you change it.state returns every policy record on the key, and catalog returns the policy language the key accepts.
--json, state prints a summary: the state name, whether Permissions is enabled, and how many policies are active and in draft. The JSON lists every record in policies, plus activePolicies (active records whose time window is open now) and draftPolicies. Each record has these fields:
catalog returns the condition kinds, effects, selector scopes, and facts the key accepts, with the operators each fact allows. Without --json, it prints only the catalog versions and the number of facts.
Write the policy
A policy file holds one JSON object.metadata.productMode sets its kind: "guardrail" for app-owned wallets, or "delegation" for a Request on user-owned wallets. Write amounts as strings in the chain’s base units, such as wei or lamports, and use integer strings for version, starting at "1", because replace expects the next integer.
- Guardrail
- Request
This Guardrail limits SOL transfers from the app-owned Solana wallets on the key. It blocks any transfer above 2 SOL, and any transfer that would take a wallet past 10 SOL in one UTC day.A Guardrail rule can
guardrail.json
deny or require_approval. Without a walletId in the selector, the policy covers every app-owned Solana wallet on the key.Para also accepts a Guardrail allow whose only action is raw_signature, but a Guardrail never needs it: app-owned wallets already sign raw signatures by default. Raw signatures carry no network a selector can name, so a policy that sets chainId, like this one, never matches them. To deny raw signatures or require approval for them, write a Guardrail without chainId.Validate, create, and activate
A new policy goes through three commands. It affects signing only after the last one.1
Validate
validate checks the policy against the key without saving anything. It covers the schema, the rules allowed for the policy’s kind, the facts and actions available for its wallet type, and any wallets or users the selector names. An invalid policy prints each error with its JSON path and exits with code 10. A valid policy prints a warning for each active policy of the same kind whose selector overlaps it, because both policies can apply to the same requests.Two policy features must be enabled for the key before you use them: approval requirements (approvalRequirement on a rule) and adjustable parameters. If the policy uses one that is not enabled, validation fails with permissions_v2_extension_unavailable. Contact Para to enable it.2
Create a draft
create validates the file again, saves it as a draft, and prints the new recordId with the activate command to run next. A draft does not affect signing. The key holds one Guardrail draft and one Request draft at a time, so activate or archive a draft before you create another of the same kind.3
Activate
activate asks for confirmation, makes the draft active, and turns on Permissions for the key. It works only while the draft’s time window is open. If another version of the same policy id is active, that version becomes superseded. Activation can also invalidate open approval cases. Read state to confirm the result.Test on beta
A valid policy can still miss your intent. On beta, send at least one request that each rule should stop and one it should let through, using the same wallets and flows as your app. Exercise a Guardrail by signing from an app-owned wallet on your backend, and a Request by having a test user grant consent in your app first. Each platform’s guide covers the details: REST API, Node & Server, React & Web, and React Native.Update a policy
replace publishes the next version of a policy from an edited file. Use it to change rules, conditions, or the time window of a draft or active policy.
id, selector, and metadata.productMode of the record it replaces, and sets version to one more than the highest version of that policy, for example "2" after "1". To cover different wallets or networks, create a separate policy instead. Without --effective-from or --effective-until, the new version keeps the current time window.
To stage a change instead,
create the next version as a draft and activate it when you are ready. Activation supersedes the active version with the same id.
Replacing an active policy can invalidate open approval cases.
Deactivate and archive
Deactivate a policy to stop enforcing it, and archive records you no longer need. The Developer Portal calls these actions turning a permission off and deleting it.deactivate moves an active record to inactive. An inactive record cannot be activated again, so to restore the policy, create it with the next version, activate that draft, and archive the old record. archive retires a draft, inactive, or superseded record; deactivate an active record before you archive it. Both commands ask for confirmation unless you pass --yes. deactivate can also invalidate open approval cases.
Open approval cases
When a rule requires approval, the signing request opens an approval case and waits for reviewers. An approval case is open while it ispending, and after it completes until it is used to sign or expires. Para refuses a change that would invalidate open cases until you confirm it. A confirmed change ends those cases as invalidated, and their requests need a new attempt.
In the CLI, replace, activate, and deactivate run this check:
With
--yes --json, the error looks like this:
--force only when the requests behind those cases can be sent again under the new policies. create and archive never touch approval cases, so they have no --force flag.
Schedule with time windows
A time window limits when an active policy applies. Set it with--effective-from and --effective-until on create or replace; activate takes no window flags.
create saves it, so you can activate it right away. The policy stops applying after 23:59:59 UTC on December 31, 2026.
activate works only while the draft’s window is open. Before a later --effective-from arrives, activate exits with code 10 and reports policy_record_activation_window_inactive. To start a policy at a set time, create the draft in advance and run activate at or after its start, for example from a scheduled CI job. Until you activate or archive that draft, the key cannot hold another draft of the same kind.
- Write timestamps in UTC as ISO 8601 ending in
Z, with optional milliseconds, such as2026-11-01T00:00:00.000Z. Offsets such as+01:00are rejected. --effective-untilmust be later than--effective-from. The window includes both ends.- Without
--effective-from,createopens the window when it saves the draft. Without--effective-until, the window has no end. - On
replace, each flag you leave out keeps the current record’s value.
effectiveUntil no longer applies, and the Developer Portal shows it as Expired. Because replace needs both windows open, you cannot replace an expired policy. Create the next version with a current window and activate it instead.
Run in CI and scripts
The commands run without prompts once they have everything they need. Pin the environment, organization, project, and key, pass--yes to the commands that ask for confirmation, and add --json to read results.
replace,activate,deactivate, andarchiverequire--yeswith--json.--yesdoes not confirm changes that invalidate open approval cases. Ifreplace,activate, ordeactivatewould invalidate them, the command makes no change and exits with code10, withPERMISSIONS_V2_APPROVAL_CASES_AFFECTEDin the--jsonoutput. Pass--forceonly in jobs that are meant to invalidate them.- Pass the key ID. With
--json, the CLI cannot ask which key to use when the project has more than one beta key. --file -reads the policy from a pipe. The CLI refuses stdin from an interactive terminal.- Every command uses the developer session that
para loginstores.para auth statusfails early when that session is missing or expired.
JSON output
JSON output
With
--json, each command writes one JSON document to stdout.Exit codes
Exit codes
Go to production
The CLI writes only to beta keys.create, replace, activate, deactivate, and archive stop with PERMISSIONS_BETA_KEY_REQUIRED when the key is not a beta key, including with --environment prod. state, catalog, and validate work on any key, so you can read the policies on your production key from the CLI.
Publishing to production goes through a review. Once your policies work on beta, request a production review from your Production key in the Developer Portal, and Para applies the reviewed policies to production. Follow Go to production for your platform: REST API, Node & Server, React & Web, or React Native.