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

# How Tally works

> An end-to-end tour of the model in five minutes.

If you have five minutes and want the whole picture before you dive into specifics, you're in the right place. This page walks through every primitive and how they fit together.

## The five primitives

Every interaction with Tally touches some combination of these:

1. **Account** — the top-level container. Holds wallets, agents, API keys, members, webhooks. The trust boundary for everything.
2. **Wallet** — a Privy server wallet that holds USDC. You own it via passkey; Tally never has owner-level access.
3. **Agent** — the identity you attach to autonomous units you run. Wallet-agnostic; a single agent can be authorized on many wallets.
4. **Permission** — a policy you approve with your passkey, authorizing one specific agent to spend from one specific wallet under bounded rules. The linchpin of the trust model.
5. **Payment** — a USDC transfer signed by the agent's key, validated against the permission by both Tally and Privy's enclave, broadcast to Base.

## The lifecycle, end to end

Here's what happens, in order, from your first sign-in to your agent making its first payment:

### 1. Sign in

On first sign-in to Tally's `/login` flow, Tally auto-provisions:

* A Tally **account** (named after your email).
* A test-mode **wallet** on Base Sepolia called "Main Wallet."
* An ownership membership tying you to the account.

No setup wizard, no manual provisioning. You land on `/[slug]/overview` with a wallet ready to receive USDC. See [Accounts](/accounts) for the model details.

### 2. Register an agent

From your server:

```ts theme={null}
const agent = await tally.agents.upsert({ id: "research-bot" });
console.log(agent.status); // → "no_permissions"
```

The agent exists but can't spend yet — it has no signing power on any wallet. The `status` field reflects this. See [Agents](/agents) for the ID model and patterns.

### 3. Grant the agent a permission

This is the load-bearing step. From the dashboard, pick the agent, pick a wallet, set the policy (per-transaction max, optional daily cap, optional recipient allowlist, optional expiry), and approve it with your passkey.

Under the hood:

* Tally generates a fresh P-256 keypair for this (agent, wallet) pair.
* The private key is envelope-encrypted via AWS KMS and stored.
* The public key is registered with Privy as an additional signer on the wallet, attached to the policy.
* Your passkey approval attaches the signer to the wallet on-chain.

After that, the agent has authority to spend from that wallet, bounded by the policy. See [Wallets](/wallets) for the signer/policy mechanics and [Permissions](/permissions) for the full flow.

### 4. Your agent makes a payment

From your server, when the agent needs to spend:

```ts theme={null}
const payment = await tally.payments.create({
  agent_id: "research-bot",
  wallet: "0x7a3f...",
  to: "0xC0fee...",
  amount_usdc: "4.50",
});
```

Two enforcement layers fire before the transaction touches the chain:

* **Tally pre-checks** the request against the permission — per-tx max, daily cap, recipient and contract allowlists, expiry.
* **Privy's enclave independently re-checks** the per-tx max and allowlists before signing.

A compromised Tally server can't sneak a payment past the second check, because Privy doesn't trust Tally — it trusts the policy you approved. See [Payments](/payments) for the full flow and [Permissions](/permissions) for what the policy bounds.

### 5. You react to the result

`payments.create()` returns immediately with `status: "pending"` and the broadcast `tx_hash`. To know when the payment confirms, you have two options:

* **Poll** `tally.payments.get(payment_id)` until status flips to `confirmed` or `failed`.
* **Subscribe** to `payment.confirmed` and `payment.failed` webhooks.

Webhooks are the right call for production. See [Webhooks](/webhooks).

## What this means in practice

A few properties fall out of the model that are worth holding in your head:

* **You never see private key material.** Privy holds the wallet keys; you control them through your passkey. The SDK surfaces addresses and balances, never the keys themselves.
* **Agents can't move funds without a permission.** No permission, no spend. The error from `payments.create()` is well-defined, so your code can branch on it.
* **The audit trail is immediate.** Every payment, every permission change, every revocation is logged the moment it happens — visible in the dashboard and queryable via webhooks.
* **If Tally goes away, your wallet persists.** You keep control through Privy directly. Permissions stay active or revocable. Your code stops working; the funds don't.

## Where to go from here

If you came here to evaluate Tally:

* [Wallets](/wallets) — the most-differentiated concept; this is where the trust model lives.
* [Permissions](/permissions) — the grant flow and what policies enforce.

If you came here to build:

* [Quickstart](/quickstart) — ten-minute path to a working payment.
* [Set up your account](/setup) — first-time dashboard walkthrough.

If you came here from another payments product:

* [Test mode and live mode](/test-mode) — Stripe-style partitioning; very likely familiar.
* [API keys](/api-keys) — rotation with grace window.
