# Use Openfort with CLI

The Openfort CLI lets you manage blockchain wallets, access-control policies, gas sponsorship, transaction intents, and other Openfort resources directly from the terminal. It supports both EVM and Solana chains.

<Cards>
  <Card title="Installation" description="Install the Openfort CLI" to="#installation" icon="lucide:download" />

  <Card title="Authenticate" description="Connect to your Openfort dashboard" to="#authenticate" icon="lucide:log-in" />

  <Card title="Example Flow" description="Quick walkthrough for an EVM transaction" to="#example-send-a-sponsored-transaction" icon="lucide:zap" />

  <Card title="Wallets Reference" description="Manage EVM & Solana wallets" to="#accounts-wallets" icon="lucide:wallet" />

  <Card title="Policies & Sponsorship" description="Set up gasless transactions" to="#policies" icon="lucide:fuel" />

  <Card title="Transactions" description="Manage and send transactions" to="#transactions" icon="lucide:send" />
</Cards>

<details>
  <summary>Key Concepts</summary>

  Before using the CLI, it helps to understand the core resource model:

  * **EOA (Externally Owned Account)** — A standard EVM backend wallet created with `accounts evm create`. This is the base key pair you sign with.
  * **Delegated Account** — An EOA upgraded to a smart account via EIP-7702 (`accounts evm update`). Delegated accounts support account abstraction (gasless transactions). Each delegated account is chain-specific and has its own `acc_` ID separate from the EOA.
  * **Policy** — A rule set that governs which operations are allowed (e.g., sponsoring gas on a specific chain).
  * **Sponsorship** — Links a policy to a gas payment strategy (e.g., `pay_for_user`), enabling gasless transactions.
  * **Transaction Intent** — A record of a desired on-chain action. Created via the API, it may require signing before broadcast.

  **Sending Transactions: Two Approaches**

  There are two ways to send transactions. Choose based on your use case:

  | Approach | Command | Best for |
  | :--- | :--- | :--- |
  | **Sponsored (recommended)** | `openfort accounts evm send-transaction` | Gasless transactions. Handles everything automatically: finds or creates a delegated account, signs EIP-7702 authorization, creates the transaction intent, signs and submits it. Pass an **EOA** account ID. |
  | **Manual (advanced)** | `openfort transactions create` + `openfort transactions sign` | When you need fine-grained control over each step, external signing, or non-backend wallets. Requires a **delegated** account ID. You must handle signing separately. |

  :::tip
  For most use cases, use `openfort accounts evm send-transaction`. It wraps the entire delegation and signing flow into a single command. The `openfort transactions` commands are for advanced scenarios where you need to separate transaction creation from signing.
  :::
</details>

## Installation

```bash
npm install -g @openfort/cli
```

After installation, the `openfort` command is available globally.

## Authenticate

```bash
openfort login
```

This opens your browser to the Openfort dashboard. After you authorize, the CLI stores your API key, publishable key, and project ID in a local credentials file at `~/.config/openfort/credentials` (or `$XDG_CONFIG_HOME/openfort/credentials` if set).

:::tip
All commands except `login` require authentication. The CLI reads your credentials automatically from the stored file. After logging in, run `openfort backend-wallet setup` to set up signing keys.
:::

## Example: Send a Sponsored Transaction

This walkthrough creates a backend wallet and sends a gasless transaction on Base Sepolia (chain ID 84532).

:::steps
### Authenticate

```bash
openfort login
```

### Generate wallet keys

```bash
openfort backend-wallet setup
```

### Create a backend wallet

```bash
openfort accounts evm create
# Returns: acc_<your-eoa-id>
```

### Register the target smart contract

```bash
openfort contracts create \
  --name "My Token" \
  --address 0xbabe0001489722187FbaF0689C47B2f5E97545C5 \
  --chainId 84532
```

### Create a policy and sponsorship for gas

```bash
# Create a policy that allows sponsoring transactions on Base Sepolia
openfort policies create \
  --scope project \
  --rules '[{"action":"accept","operation":"sponsorEvmTransaction","criteria":[{"type":"evmNetwork","operator":"in","chainIds":[84532]}]}]'
# Returns: ply_<your-policy-id>

# Create a sponsorship linked to the policy
openfort sponsorship create \
  --policyId ply_<your-policy-id> \
  --strategy pay_for_user \
  --name "Base Sepolia Gas" \
  --chainId 84532
# Returns: pol_<your-sponsorship-id>
```

### Send a gasless transaction

Use `accounts evm send-transaction` with the **EOA** account ID. The command auto-delegates the account via EIP-7702, signs, and broadcasts:

```bash
openfort accounts evm send-transaction acc_<your-eoa-id> \
  --chainId 84532 \
  --interactions '[{"to":"0xbabe0001489722187FbaF0689C47B2f5E97545C5","data":"0x40c10f19000000000000000000000000<your-address-hex>0000000000000000000000000000000000000000000000000de0b6b3a7640000","value":"0"}]' \
  --policy pol_<your-sponsorship-id>
```

### Verify the transaction

```bash
openfort transactions get <tin-id>
```
:::

## Backend Wallet Key Setup

Before you can create wallets, sign data, or send transactions, you need to generate and register backend wallet signing keys (ECDSA P-256):

```bash
openfort backend-wallet setup
```

This generates an ECDSA P-256 key pair, registers it with Openfort, and saves the keys to your credentials file. You can also rotate or revoke keys:

```bash
openfort backend-wallet rotate
openfort backend-wallet revoke
```

## Accounts (Embedded Wallets)

Manage backend wallets on both EVM and Solana chains.

### List all accounts

```bash
openfort accounts list
openfort accounts list --chainType EVM --custody Developer --limit 10
```

| Option | Description |
| :--- | :--- |
| `--limit`, `-l` | Max number of results |
| `--skip` | Number of results to skip |
| `--chainType` | Filter by chain type: `EVM` or `SVM` |
| `--custody` | Filter by custody model: `Developer` or `User` |

### EVM Wallets

```bash
# Create a new EVM backend wallet (EOA)
openfort accounts evm create

# List EOA wallets
openfort accounts evm list --limit 5

# List delegated (smart) accounts
openfort accounts evm list-delegated --limit 5

# List smart accounts
openfort accounts evm list-smart --limit 5

# Get wallet details
openfort accounts evm get <id>

# Sign data with an EOA
openfort accounts evm sign <id> --data 0x1234abcd

# Import an existing private key
openfort accounts evm import --privateKey 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

# Export a private key
openfort accounts evm export <id>

# Delete a wallet
openfort accounts evm delete <id>
```

#### Upgrading to a Delegated Account (EIP-7702)

Upgrade an EOA to a delegated smart account on a specific chain. This registers the delegation with Openfort — the on-chain EIP-7702 delegation happens automatically on the first transaction.

```bash
openfort accounts evm update <eoa-id> \
  --chainId 84532 \
  --implementationType CaliburV9
```

:::info
The `--implementationType` specifies the smart account implementation. Availability varies by chain. The delegated account receives a new `acc_` ID which you can retrieve with `accounts evm list-delegated`.
:::

#### Sending a Sponsored Transaction

This is the **recommended** way to send transactions. Pass an **EOA** account ID — the command automatically handles delegation, EIP-7702 authorization signing, transaction intent creation, and submission:

```bash
openfort accounts evm send-transaction <eoa-id> \
  --chainId 84532 \
  --interactions '[{"to":"0x...","data":"0x...","value":"0"}]' \
  --policy pol_abc123
```

The `--policy` flag references a sponsorship ID (starts with `pol_`) that covers gas fees. Without it, the account's own native tokens are used.

### Solana Wallets

```bash
# Create a new Solana backend wallet
openfort accounts solana create

# List Solana wallets
openfort accounts solana list

# Get wallet details
openfort accounts solana get <id>

# Sign data
openfort accounts solana sign <id> --data SGVsbG8gV29ybGQ=

# Import / Export
openfort accounts solana import --privateKey <base58-key>
openfort accounts solana export <id>

# Delete a wallet
openfort accounts solana delete <id>

# Transfer SOL (--token defaults to "sol", --cluster defaults to mainnet-beta)
openfort accounts solana transfer <id> \
  --to FDx9mf... \
  --amount 1000000 \
  --cluster devnet

# Transfer USDC
openfort accounts solana transfer <id> \
  --to FDx9mf... \
  --amount 500 \
  --token usdc \
  --cluster mainnet-beta

# Transfer SPL token by mint address
openfort accounts solana transfer <id> \
  --to FDx9mf... \
  --amount 500 \
  --token <mint-address> \
  --cluster mainnet-beta
```

## Smart Contracts

Register and manage smart contracts for use in transactions and policies. When you register a contract by address, Openfort automatically fetches and stores its ABI if the contract is verified on-chain.

```bash
# List contracts
openfort contracts list --limit 10

# Register a contract (ABI auto-fetched if verified on-chain)
openfort contracts create \
  --name USDC \
  --address 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 \
  --chainId 137

# Register with explicit ABI
openfort contracts create \
  --name "My Contract" \
  --address 0x... \
  --chainId 137 \
  --abi '[{"type":"function","name":"transfer",...}]'

# Get contract details
openfort contracts get <id>

# Update a contract
openfort contracts update <id> --name "USDC v2" --chainId 137 --address 0x... --abi '[{"type":"function","name":"transfer",...}]'

# Delete a contract
openfort contracts delete <id>
```

| Option | Description |
| :--- | :--- |
| `--name` | Human-readable contract name |
| `--address` | Contract address on-chain |
| `--chainId` | Chain ID where the contract is deployed |
| `--abi` | Contract ABI as a JSON string (optional — auto-fetched for verified contracts) |

## Policies

Create access-control policies that govern which transactions are allowed or sponsored.

```bash
# List policies
openfort policies list --scope project --enabled true

# Create a policy to sponsor transactions on a chain
openfort policies create \
  --scope project \
  --description "Sponsor transactions on Base Sepolia" \
  --priority 1 \
  --rules '[{"action":"accept","operation":"sponsorEvmTransaction","criteria":[{"type":"evmNetwork","operator":"in","chainIds":[84532]}]}]'

# Get / Update / Delete
openfort policies get <id>
openfort policies update <id> --enabled false
openfort policies delete <id>

# Evaluate a policy (pre-flight check)
openfort policies evaluate --operation sponsorEvmTransaction --accountId acc_abc123
```

| Option | Description |
| :--- | :--- |
| `--scope` | Policy scope: `project`, `account`, or `transaction` |
| `--description` | Human-readable description |
| `--priority` | Priority order (higher = evaluated first) |
| `--rules` | JSON array of policy rules |
| `--enabled` | Enable or disable the policy |

## Gas Sponsorship

Set up gas gas sponsorship so your users don't pay for transactions. A sponsorship links a policy to a payment strategy.

```bash
# List sponsorships
openfort sponsorship list --enabled true

# Create a sponsorship linked to a policy
openfort sponsorship create \
  --policyId ply_abc123 \
  --name "Base Sepolia Gas Sponsor" \
  --strategy pay_for_user \
  --chainId 84532

# Get details
openfort sponsorship get <id>

# Update
openfort sponsorship update <id> --name "Updated Sponsor" --strategy pay_for_user --policyId ply_abc123

# Enable / Disable
openfort sponsorship enable <id>
openfort sponsorship disable <id>

# Delete
openfort sponsorship delete <id>
```

| Strategy | Description |
| :--- | :--- |
| `pay_for_user` | Fully sponsor the user's gas fees (default) |
| `charge_custom_tokens` | Charge the user in custom tokens |
| `fixed_rate` | Charge a fixed rate |

:::info
After creating a sponsorship, you receive a `pol_` ID. Pass this as `--policy` to `send-transaction` or `transactions create` to enable gas sponsorship.
:::

## Transactions

Transaction intents represent desired on-chain actions. There are two levels of commands:

### Recommended: `accounts evm send-transaction`

For **sponsored/gasless transactions**, use `accounts evm send-transaction` with an **EOA** account ID. It handles the full lifecycle automatically:

1. Finds or creates a delegated account for the EOA on the target chain
2. Signs the EIP-7702 authorization (if this is the first transaction)
3. Creates the transaction intent
4. Signs and submits the transaction

```bash
openfort accounts evm send-transaction <eoa-id> \
  --chainId 84532 \
  --interactions '[{"to":"0x...","data":"0x...","value":"0"}]' \
  --policy pol_abc123
```

### Advanced: `transactions` commands

For **fine-grained control** or external signing workflows, use the `transactions` commands directly. These work with **delegated** account IDs (obtained from `accounts evm update` or `accounts evm list-delegated`).

```bash
# Create a transaction intent (returns a signableHash in nextAction)
openfort transactions create \
  --account <delegated-acc-id> \
  --chainId 84532 \
  --interactions '[{"to":"0x...","data":"0x...","value":"0"}]' \
  --policy pol_abc123

# Sign the signableHash with the EOA
openfort accounts evm sign <eoa-id> --data <signableHash>

# Submit the signature to broadcast
openfort transactions sign <tin-id> --signature <hex-signature>
```

:::warning
When using `transactions create` with a newly delegated account, you may need to pass `--signedAuthorization` with a signed EIP-7702 authorization for the first transaction. Without it, the on-chain delegation won't be established and the transaction will fail with a signature error. Use `accounts evm send-transaction` to avoid this complexity.
:::

### Other transaction commands

```bash
# List transactions
openfort transactions list --limit 20

# Get transaction details and status
openfort transactions get <tin-id>

# Estimate gas cost before sending
openfort transactions estimate \
  --account <acc-id> \
  --chainId 84532 \
  --interactions '[{"to":"0x...","data":"0x...","value":"0"}]' \
  --policy pol_abc123

# Sign with optimistic return (don't wait for on-chain confirmation)
openfort transactions sign <tin-id> --signature 0x... --optimistic true
```

## Sessions

Manage session keys that let users sign transactions for a limited time without repeated approvals.

```bash
# List sessions
openfort sessions list --player pla_abc123

# Create a session key
openfort sessions create \
  --address 0x... \
  --chainId 137 \
  --validAfter 1700000000 \
  --validUntil 1700086400 \
  --player pla_abc123 \
  --account acc_abc123 \
  --limit 100 \
  --policy pol_abc123 \
  --whitelist '["con_abc123"]'

# Get session details
openfort sessions get <id>

# Sign a session
openfort sessions sign <id> --signature 0x...

# Sign a session with optimistic return (don't wait for on-chain confirmation)
openfort sessions sign <id> --signature 0x... --optimistic true

# Revoke sessions
openfort sessions revoke --address 0x... --chainId 137 --player pla_abc123 --policy pol_abc123
```

## Users

View and manage users in your project.

```bash
# List users
openfort users list --email user@example.com --name "John" --limit 10

# Get user details
openfort users get <id>

# Delete a user
openfort users delete <id>
```

## Paymasters

Configure ERC-4337 paymaster contracts.

```bash
# Create a paymaster
openfort paymasters create --address 0x... --name "My Paymaster" --url https://paymaster.example.com

# Get / Update / Delete
openfort paymasters get <id>
openfort paymasters update <id> --address 0x... --name "Updated Paymaster" --url https://paymaster.example.com
openfort paymasters delete <id>
```

| Option | Required | Description |
| :--- | :--- | :--- |
| `--address` | Yes | Paymaster contract address |
| `--name` | No | Human-readable paymaster name |
| `--url` | No | Paymaster service URL |

:::info
When updating a paymaster, `--address` is always required even if you only want to change other fields.
:::

## Subscriptions (Webhooks)

Subscribe to Openfort events and configure webhook triggers.

```bash
# List subscriptions
openfort subscriptions list

# Create a subscription with a webhook trigger
openfort subscriptions create \
  --topic transaction_intent.successful \
  --triggers '[{"type":"webhook","target":"https://myapp.com/webhooks"}]'

# Get / Delete
openfort subscriptions get <id>
openfort subscriptions delete <id>
```

### Managing Triggers

```bash
# List triggers for a subscription
openfort subscriptions triggers list <subscriptionId>

# Add a trigger
openfort subscriptions triggers create <subscriptionId> \
  --target https://myapp.com/webhooks \
  --type webhook

# Add an email trigger
openfort subscriptions triggers create <subscriptionId> \
  --target alerts@myapp.com \
  --type email

# Get / Delete a trigger
openfort subscriptions triggers get <subscriptionId> <triggerId>
openfort subscriptions triggers delete <subscriptionId> <triggerId>
```

### Available Topics

| Topic | Description |
| :--- | :--- |
| `transaction_intent.broadcast` | Transaction was broadcast to the network |
| `transaction_intent.successful` | Transaction completed successfully |
| `transaction_intent.cancelled` | Transaction was cancelled |
| `transaction_intent.failed` | Transaction failed |
| `balance.project` | Project balance changed |
| `balance.contract` | Contract balance changed |
| `balance.dev_account` | Developer account balance changed |
| `user.created` | A new user was created |
| `user.updated` | A user was updated |
| `user.deleted` | A user was deleted |
| `account.created` | A new account was created |
| `test` | Test event for verifying webhooks |

## Logs

Inspect API request, webhook, and subscription logs to debug a failing integration. Only mutating calls (POST/PUT/PATCH/DELETE) are recorded, and secrets in bodies are masked before storage.

```bash
# Project API request logs — what calls were made and how they responded
openfort logs list
openfort logs list --limit 20 --method POST

# Webhook delivery logs
openfort logs webhook

# Triggered subscription logs
openfort logs subscriptions --status failed --limit 20
```

## Embedded Wallet Keys (Shield)

Set up Shield encryption keys for embedded wallets:

```bash
openfort embedded-wallet setup --project pro_abc123
```

This registers encryption keys with the Shield service and stores `SHIELD_PUBLISHABLE_KEY`, `SHIELD_SECRET_KEY`, and `SHIELD_ENCRYPTION_SHARE` in your credentials file.

## Message Utilities

Hash messages using keccak256:

```bash
openfort message hash "Hello World"
```

## Integrations

The CLI includes built-in integration commands:

```bash
# Generate shell completion script (bash, zsh, fish, nushell)
openfort completions

# Register the CLI as an MCP (Model Context Protocol) server
openfort mcp add

# Sync skill files to AI agents
openfort skills add
```

## Configuration

### Credentials File

The CLI stores credentials at:

* **Linux/macOS**: `~/.config/openfort/credentials` (or `$XDG_CONFIG_HOME/openfort/credentials`)
* **Windows**: `%APPDATA%/openfort/credentials`

The file contains key-value pairs:

```text
OPENFORT_API_KEY=sk_test_...
OPENFORT_PUBLISHABLE_KEY=pk_test_...
OPENFORT_PROJECT_ID=pro_...
OPENFORT_WALLET_SECRET=...
OPENFORT_WALLET_KEY_ID=...
OPENFORT_WALLET_PUBLIC_KEY=...
```

### Environment Variables

You can override credentials via environment variables:

| Variable | Description |
| :--- | :--- |
| `OPENFORT_API_KEY` | Secret API key (required for all commands except `login`) |
| `OPENFORT_WALLET_SECRET` | Wallet encryption secret (required for wallet operations) |
| `OPENFORT_PUBLISHABLE_KEY` | Publishable key for client-side operations |
| `OPENFORT_BASE_URL` | Custom API base URL (default: `https://api.openfort.io`) |

## Global Options

Every command supports the following global options:

| Option | Description |
| :--- | :--- |
| `--format <toon\|json\|yaml\|md\|jsonl>` | Output format (default: `toon`) |
| `--filter-output <keys>` | Filter output by key paths (e.g. `foo,bar.baz,a[0,3]`) |
| `--verbose` | Show full output envelope |
| `--schema` | Show JSON Schema for the command |
| `--llms`, `--llms-full` | Print LLM-readable manifest |
| `--mcp` | Start as MCP stdio server |
| `--token-count` | Print token count of output instead of the output itself |
| `--token-limit <n>` | Limit output to n tokens |
| `--token-offset <n>` | Skip first n tokens of output |

:::tip
Use `--format json` to get machine-readable output for scripting and automation. Use `--filter-output` to extract specific fields from the response.
:::

## Learn more

<Cards>
  <Card title="Building with AI" description="Expose the CLI to AI agents via MCP" to="/docs/overview/building-with-ai" icon="lucide:bot" />

  <Card title="Openfort Dashboard" description="Manage your project visually" to="https://dashboard.openfort.io" icon="lucide:layout-dashboard" />

  <Card title="API Reference" description="View detailed API documentation" to="/docs/api-reference" icon="lucide:book-open" />
</Cards>
