Skip to main content
Tally gives your AI agent a USDC wallet with spending limits only you control. There are two ways to start — pick the one that fits what you’re doing:

Connect your agent

Hermes, OpenClaw, Claude, or any MCP agent. No code, no API key — you approve in a browser and it’s connected. Start here if you already have an agent.

Build with the SDK

You’re writing your own code against Tally. Use an API key and the TypeScript SDK.
Both end in the same place: an agent that spends USDC from a wallet you funded, capped by limits only you can change, with every payment attributed in your dashboard.

Option 1: Connect your agent

Recommended — for agents like Hermes and OpenClaw. You won’t write code or paste an API key — your agent connects through a browser approval, the way you’d connect any app to a service.
1

Create a Tally account

Sign in at tallyforagents.com (free). Your first sign-in auto-provisions your workspace and wallets.
2

Hand your agent the connect prompt

Paste this to your agent (Hermes, OpenClaw, Claude Code, …). It connects the agent with Tally’s device flow — no localhost, no key — and then has it fetch /skill.md so it actually knows how to use the wallet (balance, limits, payments), instead of holding a token it doesn’t know what to do with:
Connect yourself to Tally using its OAuth Device Flow so you can hold and spend
USDC on my behalf. Tally base URL: https://app.tallyforagents.com

1. Register a client (once):
   POST /oauth/register
   JSON: {"client_name":"My Agent","redirect_uris":["http://127.0.0.1/cb"],"scope":"wallet:read wallet:transfer x402:pay"}
   Save the returned client_id.

2. Start the device flow:
   POST /oauth/device_authorization
   form body: client_id=<client_id>&scope=wallet:read wallet:transfer x402:pay
   It returns verification_uri_complete, device_code, and interval.

3. Show me ONE line, then wait — do not show the raw code:
   "Click here to connect Tally and approve: <verification_uri_complete>"

4. After I tell you I've approved, poll for the token:
   POST /oauth/token
   form body: grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=<device_code>&client_id=<client_id>
   - {"error":"authorization_pending"} → wait <interval> seconds, then retry.
   - {"error":"slow_down"} → wait a few extra seconds, then retry.
   - When you receive an access_token, stop polling and save it.

5. Fetch https://app.tallyforagents.com/skill.md and follow it as your guide for
   every Tally action — checking balance, spending limits, payments, and history.
   Use the access_token as your Bearer credential (not an API key).

6. Confirm: GET /v1/me with header Authorization: Bearer <access_token>, and tell
   me the workspace, mode, and wallet limits it returns.

From now on, for anything money- or wallet-related, use the Tally REST endpoints
from that skill — don't invent endpoints.
3

Approve in your browser

Your agent shows you one link. Open it, pick the workspace, mode (test), and an agent name (e.g. hermes), and click Authorize. The agent appears in your dashboard the moment you approve. Tell your agent you’ve approved so it finishes connecting.
4

Fund a wallet and grant the agent permission

  1. Wallets → Main Wallet → copy its address → get test USDC from Circle’s faucet (Base Sepolia).
  2. Agents → your agent → Grant permission → pick the wallet, set a per-transaction cap (10 USDC is fine), and sign with your passkey.
This is the non-custodial step: your agent can only ever spend what you authorize here, and you can revoke it any time.
5

Ask your agent to pay

Now ask it to make a payment — e.g. “send 0.50 USDC to 0x…”, or “pay the demo weather API at https://app.tallyforagents.com/api/demo/x402-weather.” It uses the connection you just authorized, and the payment lands in your dashboard’s Transactions tab, attributed to the agent.
Other hosts (Claude Desktop’s automatic popup, the stdio server), the full prompt variants, and troubleshooting live in Connect a remote agent.

Option 2: Build with the SDK

For when you’re writing your own code against Tally (a backend, a script, an automation). Here you use a long-lived API key and the TypeScript SDK.
1

Generate a test API key

From the dashboard, go to API keys → New key. Pick test mode. Copy the key — it’s shown exactly once — and put it in your .env.local:
TALLY_API_KEY=tly_test_…
If your key doesn’t start with tly_test_, you’re not in test mode. Switch via the sidebar mode badge and try again.
2

Fund your test wallet

Your account was auto-provisioned with a “Main Wallet” on Base Sepolia. Go to Wallets, click into Main Wallet, and copy its address. Get Base Sepolia USDC from Circle’s faucet — paste the address, request USDC. It arrives in seconds; refresh the wallet page to see the balance.
3

Install the SDK

npm install @tallyforagents/sdk
4

Register an agent

import { Tally } from "@tallyforagents/sdk";

const tally = new Tally({ apiKey: process.env.TALLY_API_KEY! });

const agent = await tally.agents.upsert({ id: "quickstart-bot" });
console.log(agent.status);
// → "no_permissions"
upsert is idempotent — safe to run on every deploy. The agent exists now, but has no authority to spend yet.
5

Grant the agent permission

This step is dashboard-driven — by design, every grant requires a passkey signature from the wallet owner.
  1. In the dashboard, go to Agents and click into quickstart-bot.
  2. Click Grant permission.
  3. Pick Main Wallet, set the per-transaction max to something small (10 USDC), and sign with your passkey when prompted.
Refresh the agent page — you should see one active grant on Main Wallet.
6

Send your first payment

const payment = await tally.payments.create({
  agent_id: "quickstart-bot",
  wallet: "0xYOUR_WALLET_ADDRESS",
  to: "0xRECIPIENT_ADDRESS",
  amount_usdc: "1.00",
  memo: "quickstart test",
});

console.log(payment.status, payment.tx_hash);
// → "pending" 0xabc...
payments.create() returns as soon as Privy accepts the signed RPC — typically a second or two. Send to another wallet on your account, back to the faucet, or any Base Sepolia address you control.
7

Confirm it landed

let p = await tally.payments.get(payment.id);

while (p.status === "pending") {
  await new Promise((r) => setTimeout(r, 2_000));
  p = await tally.payments.get(p.id);
}

console.log(p.status); // → "confirmed" or "failed"
Open the dashboard’s Transactions tab — your payment is the top row, attributed to quickstart-bot. Every step here is the same path you’ll use in production — just with a tly_live_… key and Base mainnet instead of Sepolia.

Where to go next