> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mandate.md/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Get Mandate running in under 5 minutes. Choose your path: Claude Code plugin, OpenClaw, TypeScript SDK, or CLI.

## Choose your integration

Pick the path that matches how you build:

<CardGroup cols={2}>
  <Card title="Claude Code" icon="terminal" href="#claude-code-plugin">
    One command. Auto-intercepts all wallet transactions.
  </Card>

  <Card title="OpenClaw" icon="plug" href="#openclaw-plugin">
    Install from ClawHub. Three tools, safety-net hook.
  </Card>

  <Card title="TypeScript SDK" icon="code" href="#typescript-sdk">
    Full control. MandateClient + MandateWallet.
  </Card>

  <Card title="CLI" icon="square-terminal" href="#cli">
    Validate from scripts, CI, or MCP server mode.
  </Card>

  <Card title="Python / Any Language" icon="globe" href="#python--any-language">
    REST API. Works with Python, Go, Rust, or any HTTP client.
  </Card>
</CardGroup>

***

## Claude Code Plugin

The fastest path. Two commands, zero code changes. The plugin intercepts all wallet transactions Claude executes and validates them against your policy.

**Step 1:** Add the marketplace and install the plugin:

```bash theme={null}
/plugin marketplace add SwiftAdviser/claude-mandate-plugin
/plugin install mandate@mandate
```

**Step 2:** Register your agent:

```bash theme={null}
npx @mandate.md/cli login --name "my-claude-agent"
```

Claim at the printed URL, then set policies at [app.mandate.md](https://app.mandate.md).

The plugin gates every financial tool call. No valid Mandate token, no transaction.

* Agent calls `mandate validate` with action + reason
* If allowed: plugin records a 15-minute token, transaction proceeds
* If blocked: agent gets counter-evidence explaining why, stops voluntarily
* If no validation attempted: plugin blocks the tool call entirely
* Auto-scan on startup finds unprotected wallet calls in your project
* Works with any wallet: Bankr, MCP payment tools, direct RPC, custom CLIs

**GitHub:** [SwiftAdviser/claude-mandate-plugin](https://github.com/SwiftAdviser/claude-mandate-plugin)

<Card title="Full Claude Code guide" icon="arrow-right" href="/integrations/claude-code">
  Two-phase enforcement, gate triggers, token TTLs, and advanced configuration.
</Card>

***

## OpenClaw Plugin

Install from [ClawHub](https://clawhub.ai/swiftadviser/mandate) or npm. Your agent gets three Mandate tools automatically.

```bash theme={null}
openclaw plugin install @mandate.md/mandate-openclaw-plugin
```

The plugin adds these tools to your agent:

| Tool               | What it does                     |
| ------------------ | -------------------------------- |
| `mandate_register` | Register agent, get runtime key  |
| `mandate_validate` | Check transaction against policy |
| `mandate_status`   | Poll intent state                |

A safety-net hook blocks any financial tool call that skips `mandate_validate`.

**GitHub:** [SwiftAdviser/mandate-openclaw-plugin](https://github.com/SwiftAdviser/mandate-openclaw-plugin)
**ClawHub:** [clawhub.ai/swiftadviser/mandate](https://clawhub.ai/swiftadviser/mandate)

<Card title="Full OpenClaw guide" icon="arrow-right" href="/integrations/openclaw">
  Tool parameters, safety-net hook details, and configuration options.
</Card>

***

## TypeScript SDK

For custom agents. Full control over the validate, sign, broadcast flow.

### Install

<Tabs>
  <Tab title="bun">
    ```bash theme={null}
    bun add @mandate.md/sdk
    ```
  </Tab>

  <Tab title="npm">
    ```bash theme={null}
    npm install @mandate.md/sdk
    ```
  </Tab>
</Tabs>

### Register your agent

```typescript theme={null}
import { MandateClient } from '@mandate.md/sdk';

const { runtimeKey, claimUrl } = await MandateClient.register({
  name: 'my-trading-agent',
  evmAddress: '0xYourAgentWalletAddress',
  chainId: 84532, // Base Sepolia
});

// Save runtimeKey securely. Share claimUrl with the wallet owner.
```

<Warning>
  Store the `runtimeKey` in your `.env` file (`MANDATE_RUNTIME_KEY=mndt_test_...`). Never commit it to git. Share the `claimUrl` with the wallet owner to link the agent to the dashboard.
</Warning>

### Test validation (no wallet needed)

You can test the policy engine without a private key or wallet. This is the fastest way to verify your setup works.

```typescript theme={null}
// validate-test.ts — Run: bun run validate-test.ts
import { MandateClient, PolicyBlockedError, ApprovalRequiredError } from '@mandate.md/sdk';

const client = new MandateClient({
  runtimeKey: process.env.MANDATE_RUNTIME_KEY!,
});

try {
  const result = await client.validate({
    action: 'transfer',
    amount: '50',
    to: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
    token: 'USDC',
    reason: 'Payment for API access - invoice #1234',
  });
  console.log('Allowed:', result.allowed);
  console.log('Intent ID:', result.intentId);
} catch (err) {
  if (err instanceof PolicyBlockedError) {
    console.log('Blocked:', err.blockReason, err.declineMessage);
  } else if (err instanceof ApprovalRequiredError) {
    console.log('Needs approval:', err.intentId);
    const status = await client.waitForApproval(err.intentId);
    console.log('Decision:', status.status);
  }
}
```

```
Expected output:
  Allowed: true
  Intent ID: a1b2c3d4-...
```

### Execute the transfer

`MandateWallet` handles the full flow: validate, sign locally, broadcast, confirm. Your private key never leaves your machine.

<Note>
  `validate()` accepts amounts in USD (e.g., `'50'` means \$50). `wallet.transfer()` accepts raw token units (e.g., `'5000000'` means 5 USDC, because USDC has 6 decimals). The policy engine always evaluates in USD.
</Note>

```typescript theme={null}
import { MandateWallet } from '@mandate.md/sdk';

const wallet = new MandateWallet({
  runtimeKey: process.env.MANDATE_RUNTIME_KEY!,
  privateKey: process.env.AGENT_PRIVATE_KEY! as `0x${string}`,
  chainId: 84532,
});

const { txHash, intentId } = await wallet.transfer(
  '0xRecipientAddress',
  '5000000', // 5 USDC (6 decimals)
  '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
  { reason: 'Paying vendor for March services' },
);

console.log('Transaction:', txHash);
console.log('Intent ID:', intentId);
```

```
Expected output:
  Transaction: 0x7a8b9c...
  Intent ID: e5f6g7h8-...
```

<Accordion title="Complete runnable example (register + validate + transfer)">
  ```typescript theme={null}
  // quickstart.ts — Run: bun run quickstart.ts
  // Prerequisites: bun add @mandate.md/sdk viem
  // Set MANDATE_RUNTIME_KEY and AGENT_PRIVATE_KEY in .env

  import { MandateWallet, MandateClient, USDC, CHAIN_ID } from '@mandate.md/sdk';

  const RECIPIENT = '0x0000000000000000000000000000000000000001' as `0x${string}`;

  async function main() {
    // Step 1: Register (skip if you already have a runtimeKey)
    let runtimeKey = process.env.MANDATE_RUNTIME_KEY;

    if (!runtimeKey) {
      console.log('No runtimeKey found. Registering new agent...');
      const reg = await MandateClient.register({
        name: 'QuickstartAgent',
        evmAddress: '0xYourWalletAddress' as `0x${string}`,
        chainId: CHAIN_ID.BASE_SEPOLIA,
      });
      runtimeKey = reg.runtimeKey;
      console.log(`Registered! runtimeKey: ${runtimeKey}`);
      console.log(`Claim URL: ${reg.claimUrl}`);
      console.log('Save runtimeKey to .env as MANDATE_RUNTIME_KEY');
    }

    // Step 2: Create MandateWallet
    const wallet = new MandateWallet({
      runtimeKey,
      privateKey: process.env.AGENT_PRIVATE_KEY as `0x${string}`,
      chainId: CHAIN_ID.BASE_SEPOLIA,
    });

    // Step 3: Transfer with policy enforcement
    try {
      const { txHash, intentId, status } = await wallet.transfer(
        RECIPIENT,
        '1000000', // 1 USDC (6 decimals)
        USDC.BASE_SEPOLIA,
      );
      console.log('Transfer successful!');
      console.log('  txHash:', txHash);
      console.log('  intentId:', intentId);
      console.log('  status:', status.status);
    } catch (err: unknown) {
      if (err && typeof err === 'object' && 'blockReason' in err) {
        console.error('Blocked:', (err as { blockReason: string }).blockReason);
      } else {
        throw err;
      }
    }
  }

  main().catch(console.error);
  ```
</Accordion>

**npm:** [@mandate.md/sdk](https://www.npmjs.com/package/@mandate.md/sdk)

***

## CLI

Run directly with `npx`. No install needed.

### Register

```bash theme={null}
npx @mandate.md/cli login --name "my-agent"
```

### Validate

```bash theme={null}
npx @mandate.md/cli validate \
  --action transfer \
  --amount 50 \
  --to 0x036CbD53842c5426634e7929541eC2318f3dCF7e \
  --token USDC \
  --reason "Payment for API access"
```

### Scan your codebase

Find unprotected wallet calls before they reach production:

```bash theme={null}
npx @mandate.md/cli scan ./src
```

The scanner detects `sendTransaction`, `transfer`, `approve`, and other financial calls missing Mandate validation. Exit code 1 if any found. Use it in CI.

### MCP server mode

Turn the CLI into an MCP server for AI assistants:

```bash theme={null}
npx @mandate.md/cli --mcp
```

**npm:** [@mandate.md/cli](https://www.npmjs.com/package/@mandate.md/cli)

<Card title="Full CLI reference" icon="arrow-right" href="/cli/overview">
  All 10 commands, flags, credential storage, and MCP configuration.
</Card>

***

## Python / Any Language

No SDK needed. Call the REST API directly with any HTTP client.

### Register

```python theme={null}
import requests

resp = requests.post("https://app.mandate.md/api/agents/register", json={
    "name": "my-python-agent",
    "evmAddress": "0xYourAgentWalletAddress",
    "chainId": 84532,
})
data = resp.json()
runtime_key = data["runtimeKey"]
print(f"Runtime key: {runtime_key}")
print(f"Claim URL: {data['claimUrl']}")
# Save runtime_key to .env
```

### Validate

```python theme={null}
import os, requests

headers = {
    "Authorization": f"Bearer {os.environ['MANDATE_RUNTIME_KEY']}",
    "Content-Type": "application/json",
}

resp = requests.post("https://app.mandate.md/api/validate", headers=headers, json={
    "action": "transfer",
    "amount": "50",
    "to": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
    "token": "USDC",
    "reason": "Payment for API access - invoice #1234",
})

data = resp.json()
if resp.status_code == 200 and data.get("allowed"):
    print(f"Allowed. Intent: {data['intentId']}")
elif resp.status_code == 422:
    print(f"Blocked: {data['blockReason']} - {data.get('blockDetail')}")
elif resp.status_code == 202:
    print(f"Needs approval. Intent: {data['intentId']}")
```

```
Expected output:
  Allowed. Intent: a1b2c3d4-...
```

This pattern works with Python, Go, Rust, Ruby, or any language with an HTTP client. See the [REST API reference](/api-reference/overview) for all endpoints.

***

## Default policy

After registration, every agent starts with:

| Rule                  | Default |
| --------------------- | ------- |
| Per-transaction limit | \$100   |
| Daily limit           | \$1,000 |
| Address restrictions  | None    |
| Approval required     | No      |
| Schedule              | 24/7    |

Customize in the [Dashboard](https://app.mandate.md) policy builder.

## What happens under the hood

1. **Validate.** Your agent sends action + reason to Mandate. The policy engine runs 14 checks.
2. **Sign locally.** After validation passes, the agent signs with its own key. Mandate never sees it.
3. **Broadcast.** Signed transaction goes to the chain.
4. **Verify.** Mandate confirms the on-chain tx matches what was validated. Mismatch trips the circuit breaker.

## Resources

| Resource            | Link                                                                                                                   |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Dashboard           | [app.mandate.md](https://app.mandate.md)                                                                               |
| Documentation       | [docs.mandate.md](https://docs.mandate.md)                                                                             |
| SDK (npm)           | [@mandate.md/sdk](https://www.npmjs.com/package/@mandate.md/sdk)                                                       |
| CLI (npm)           | [@mandate.md/cli](https://www.npmjs.com/package/@mandate.md/cli)                                                       |
| Claude Code Plugin  | [GitHub](https://github.com/SwiftAdviser/claude-mandate-plugin)                                                        |
| OpenClaw Plugin     | [ClawHub](https://clawhub.ai/swiftadviser/mandate) / [GitHub](https://github.com/SwiftAdviser/mandate-openclaw-plugin) |
| Skill (SKILL.md)    | [GitHub](https://github.com/SwiftAdviser/mandate-skill)                                                                |
| Developer Community | [Telegram](https://t.me/mandate_md_chat)                                                                               |

## Next Steps

<CardGroup cols={2}>
  <Card title="How It Works" icon="diagram-project" href="/how-it-works">
    Validation flow, intent lifecycle, and state machine.
  </Card>

  <Card title="Handle Errors" icon="triangle-exclamation" href="/guides/handle-errors">
    PolicyBlockedError, CircuitBreakerError, and 12 block reason codes.
  </Card>

  <Card title="Handle Approvals" icon="clock" href="/guides/handle-approvals">
    Wait for human approval with polling, timeouts, and callbacks.
  </Card>

  <Card title="All Integrations" icon="plug" href="/integrations/overview">
    GOAT SDK, AgentKit, ElizaOS, GAME, ACP, MCP Server, and more.
  </Card>
</CardGroup>
