# Create a stablecoin payroll system

Automate payments to contractors, employees, or users. Use Openfort's backend wallets and batch transactions to execute programmable payouts efficiently.

## Prerequisites

* [Node.js](https://nodejs.org/) (v18+)
* An [Openfort](https://dashboard.openfort.io/) account with a project created

## Install the Openfort CLI

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

## Teach your agent to use Openfort

Register the CLI as an MCP server so your agent can call Openfort tools directly:

```bash
openfort mcp add
```

Or, if your agent supports skills:

:::code-group

```bash [Claude Code]
claude -p "Read https://github.com/openfort-xyz/agent-skills and set up Openfort CLI"
```

```bash [Amp]
amp --execute "Read https://github.com/openfort-xyz/agent-skills and set up Openfort CLI"
```

```bash [Codex CLI]
codex exec "Read https://github.com/openfort-xyz/agent-skills and set up Openfort CLI"
```

:::

## Walkthrough

::::steps

### 1. Set up backend wallet signing

Generate the signing keys so your backend wallet can authorize transactions:

> **Prompt your agent**: "Run `backend-wallet setup` to generate and register the ECDSA P-256 signing keys for this project."

### 2. Create a backend wallet

Provision the treasury wallet that will disburse payroll:

> **Prompt your agent**: "Use `accounts evm create` to create a new EVM backend wallet. This will be our payroll treasury account."

This returns an account ID (`acc_...`) and an EOA address. Fund this address with USDC on your target chain.

### 3. Set up the Node.js SDK

Initialize the Openfort Node SDK for programmatic payouts:

> **Prompt your agent**: "Install `@openfort/openfort-node` into this project. Initialize the SDK with both the secret key and wallet secret."

```ts
import Openfort from '@openfort/openfort-node';

const openfort = new Openfort(process.env.OPENFORT_SECRET_KEY, {
  walletSecret: process.env.OPENFORT_WALLET_SECRET,
});
```

| Environment variable | Description |
|---|---|
| `OPENFORT_SECRET_KEY` | Your API secret key (`sk_test_...` or `sk_live_...`) |
| `OPENFORT_WALLET_SECRET` | Wallet encryption secret (you create this) |

### 4. Configure gas sponsorship

Create a policy and fee sponsorship so payroll transactions are gasless:

> **Prompt your agent**: "Create a project-scoped policy using `policies create` with a rule that accepts `sponsorEvmTransaction` operations. Then create a fee sponsorship linked to that policy using `sponsorship create`."

Without this, batch transactions will fail — `sendTransaction` requires a fee sponsorship to cover gas.

### 5. Batch payroll transfers

Write the payroll disbursement script. The SDK's `sendTransaction` method handles the full flow: it auto-upgrades the wallet to an EIP-7702 Delegated Account (required for batching), creates the transaction intent, signs it, and submits it.

> **Prompt your agent**: "Write a TypeScript function that takes an array of `{ address: string, amount: number }` payees and uses `openfort.accounts.evm.backend.sendTransaction()` to batch multiple USDC `transfer` calls into a single transaction from our treasury wallet. Each interaction should ABI-encode an ERC-20 `transfer(address, uint256)` call to the USDC contract. Use `viem` to encode the calldata."

```ts
import { encodeFunctionData } from 'viem';

const USDC_ADDRESS = '0x...'; // USDC contract on your chain
const TREASURY_ACCOUNT = 'acc_...'; // from Step 2

const interactions = payees.map(({ address, amount }) => ({
  to: USDC_ADDRESS,
  data: encodeFunctionData({
    abi: [{ name: 'transfer', type: 'function', inputs: [{ name: 'to', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ name: '', type: 'bool' }] }],
    functionName: 'transfer',
    args: [address, BigInt(amount * 1e6)], // USDC has 6 decimals
  }),
  value: '0',
}));

const result = await openfort.accounts.evm.backend.sendTransaction({
  account: TREASURY_ACCOUNT,
  chainId: 84532, // Base Sepolia for testing
  interactions,
});
```

To execute payroll directly from the CLI instead:

> **Prompt your agent**: "Use `accounts evm send-transaction` with the treasury account ID, chain ID `84532`, and an interactions array containing ABI-encoded USDC `transfer` calls for each payee. Use the policy from Step 4 for gas sponsorship."

::::

## Pregenerate employee wallets (optional)

If you want employees to have Openfort embedded wallets ready before they sign up, you can pregenerate wallets by email:

> **Prompt your agent**: "Run `embedded-wallet setup` to generate Shield API keys. Then write a script using the Openfort Node SDK that calls `openfort.accounts.evm.embedded.pregenerate()` with each employee's email and the Shield credentials to reserve their wallet addresses."

This requires additional credentials:

| Parameter | Description |
|---|---|
| `shieldApiKey` | Shield API key (from `embedded-wallet setup`) |
| `shieldApiSecret` | Shield API secret |
| `encryptionShare` | Shield encryption share |

Once pregenerated, fund these addresses and employees will have access when they log in.

## Next steps

* [Backend wallets setup](/docs/products/server/setup)
* [Gasless transactions on EVM](/docs/products/server/evm/gasless-transactions)
* [Pregenerate wallets](/docs/products/embedded-wallet/server/pregenerate-wallets)
* [Policies overview](/docs/configuration/policies)
