> ## 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.

# Changelog

> Everything that's shipped (and what's coming next).

Tally is in active development. This page logs notable changes — new endpoints, new SDK methods, behavior changes, deprecations — so you can track what's safe to depend on and what's recently moved.

Entries are reverse-chronological. Significant breaking changes will get their own callout; minor improvements roll up into the date entry.

***

## 2026-05-29 — Developers tab + billing hardening

A small follow-up week to the go-live release. The dashboard's developer surfaces are now under one tab, and three billing edge cases that could double-bill or unexpectedly downgrade a paid account are fixed.

### Changed

* **Developers tab.** [API keys](/api-keys) and [webhooks](/webhooks) are now consolidated under a single **Developers** entry in the dashboard sidebar — matching the Stripe / Vercel / Clerk layout. Both views are stacked as sections on `/developers`; the webhook detail page moves to `/developers/webhooks/{id}`. The old `/api-keys`, `/webhooks`, and `/webhooks/{id}` URLs redirect, so existing bookmarks and the onboarding checklist still work.

### Fixed

* **Duplicate subscriptions on upgrade.** Upgrading from Pro to Scale via the account page could mint a second subscription on top of the existing one (so the account paid both plans in parallel). Checkout now rejects with `409` if the customer already has an active subscription, and the account page only shows upgrade buttons to Developer-plan accounts. Paid plans switch in place via **Manage billing** (Stripe Customer Portal). See the [account tab notes](/accounts).
* **Cancelling one subscription no longer downgrades a still-paying account.** If an account ended up with two subscriptions and one was cancelled, the cancellation webhook used to drop the whole account back to Developer. It now checks for any other active subscription on the same customer and keeps the surviving plan.
* **Stale Stripe customer IDs self-heal.** Accounts that carried a sandbox Stripe customer ID into live mode were hitting `500`s when opening Checkout. The checkout flow now detects a missing or deleted customer, clears the stored ID, and provisions a fresh one transparently — no user-visible error.

***

## 2026-05-27 — Out of public preview · plan tiers + Stripe billing

Tally is no longer framed as a public preview. The status pill, legal pages, and docs now describe the product as **live on Base**, full stop. There's no functional regression in this entry — same SDK, same dashboard, same APIs — but plan enforcement, the account tab, and the Stripe billing surface all land in this release.

### Added

* **Plan-tier enforcement.** `accounts.plan` (Developer / Pro / Scale / Enterprise) now drives the wallet, agent, and monthly sponsored-transaction caps directly from `src/lib/plan-limits.ts`. The pricing page imports the same module, so marketing copy and enforcement can't drift.
* **Sponsored-transaction monthly cap.** Hard block at the plan's monthly allowance — Free 1,000 / Pro 50,000 / Scale unlimited — counted across live-mode outbound sends, reset on the 1st of each UTC calendar month. Returns `plan_cap_exceeded` (HTTP 403) from `POST /v1/payments`.
* **Agent limit enforcement.** Matches the existing wallet cap. New agent creation 400s with `validation_failed` once the cap is reached; the dashboard's "New agent" button now also greys out at the cap with an upgrade tooltip.
* **Account tab.** New `Account` nav item on the dashboard. Profile (display name, email, member-since), plan + usage meters (wallets, agents, sponsored sends), account settings (account name, intended use), and a "Danger zone" delete-account flow with type-to-confirm + live-mode USDC balance gate.
* **Stripe billing.** `/api/stripe/checkout`, `/api/stripe/portal`, `/api/stripe/webhook`. Yearly billing is offered alongside monthly for Pro and Scale (\~17% saving). The webhook syncs `account.plan` / `planRenewsAt` / `planCancelAt` on `customer.subscription.{created,updated,deleted}`. Deleting an account also cancels the active Stripe subscription.

### Changed

* **Pricing page.** Replaced the "100 / 25,000 / 250,000 transactions per month" framing with sponsored-transaction allowances: **1,000 / 50,000 / Unlimited**. Wallets are now stated as "X per mode (test + live)" to match enforcement. Added a monthly/yearly billing toggle.
* **Wallet cap.** No longer a hardcoded constant; reads the user's plan. Same 3-per-mode default on Developer, but Pro/Scale/Enterprise now actually unlock more.
* **Gas sponsorship caps simplified.** The preview-era per-wallet and per-account daily $1 dollar caps are removed — they conflicted with paid-plan usage (Pro at 50,000 sponsored sends/mo averages ~$8/day in gas) and were redundant with the new monthly hard block. Per-API-key rate limiting (30/min on payments) still prevents single-key abuse. The app-wide circuit breaker stays as catastrophe insurance; its default is now $500/day (was $10) and is env-overridable via `GAS_CAP_APP_DAILY_USD`.
* **Landing page.** The status pill reads simply **"Live on Base"**. Hero and closing-CTA copy dropped "Free during public preview".
* **Legal pages.** Terms and Privacy keep their risk disclaimers but no longer characterize the product as a public preview. Waitlist references removed from the Privacy Policy.
* **Docs.** The introductory `Note` no longer calls Tally a public preview.

### Removed

* **Mainnet waitlist.** The `MainnetWaitlistForm`, `/api/waitlist`, the welcome email helper, and the `waitlist_entries` table are all gone. Tally is live; there's nothing to wait for.

### Migration required

Run `pnpm db:migrate` (or `npm run db:migrate`) to apply `20260527000000_plan_billing_and_user_display_name`. It adds the `Plan` and `BillingCycle` enums, the plan/Stripe columns on `accounts`, `users.display_name`, `accounts.deleted_at`, and drops `waitlist_entries`.

***

## 2026-05-22 — `@tallyforagents/mcp-server` (MCP integration)

### Added

* **`@tallyforagents/mcp-server@0.1.0`** — local stdio Model Context Protocol server. Any MCP-aware AI agent (Claude Desktop, Cursor, Hermes, Cline, Goose) can now get a Tally wallet with four lines of config and zero code changes. Exposes four tools: `pay_x402_service` (any URL, auto-pay on 402), `pay_direct` (send USDC to an address), `list_recent_payments`, `get_wallet_info` (caps + dashboard URL when no permission yet). Identity defaults to an auto-upserted `mcp-default` agent; overridable via `TALLY_AGENT_ID`. See the [MCP server reference](/sdk/mcp-server) and the [Connect via MCP guide](/guides/connect-via-mcp).

***

## 2026-05-22 — `tally.x402.fetch()` helper

### Added

* **`tally.x402.fetch(url, opts)`** (SDK 0.3.0) — call any HTTP service that uses the x402 protocol. The SDK handles the full 402 dance for you: initial fetch → parse `accepts[]` terms → `tally.payments.create()` → retry with the tx hash in the `X-Payment` header. Returns `{ response, payment }` — the post-payment response plus a receipt for the payment Tally made on your behalf (or `null` if no payment was needed). Supports per-call `max_amount_usdc` cap, `idempotency_key`, custom `memo`, `method`/`headers`/`body` pass-through. See [SDK x402](/sdk/x402).
* **`@tallyforagents/sdk@0.3.0` on npm** — adds the `x402` resource. Additive, non-breaking.

### Changed

* **`paying-weather-agent` example** — refactored to use `tally.x402.fetch()` instead of the hand-rolled 402 dance. Same UX, \~70 fewer lines in `tools.ts`.

***

## 2026-05-22 — SDK on npm, onboarding checklist, x402 example

First week of post-launch shipping. The TypeScript SDK is now on npm, the dashboard guides you through first-run setup, and there's a runnable x402-paying agent example.

### Added

* **`@tallyforagents/sdk@0.1.0` on npm** — install with `npm i @tallyforagents/sdk`. No more monorepo-only consumption. See [installation](/sdk/installation).
* **`account_slug` on the agent response** (SDK 0.1.1) — `tally.agents.upsert/list/get()` now include the account's slug, so SDK callers can render dashboard deep-links when guiding the user through a permission grant. Used by the `paying-weather-agent` example to surface the exact "go grant a permission here" URL when the agent has no active wallets yet.
* **`tally.wallets` SDK resource** (Phase 1 of the SDK gap batch) — `tally.wallets.list()` returns every wallet in the API key's account + mode; `tally.wallets.create({ display_name, role_label? })` provisions a new Privy server wallet programmatically (no dashboard click needed). SDK-created wallets are owned by the account's oldest `owner`-role member so future signer changes behave identically to dashboard-created ones. See [SDK wallets](/sdk/wallets) for the full reference. Ships unpublished; next SDK release will bundle it with the rest of the gap-batch resources.
* **`tally.payments.list()` + `tally.permissions.list()` with auto-pagination** (Phase 2 of the SDK gap batch) — Stripe-style `AsyncResourcePage` so callers can `for await (const p of tally.payments.list({ status: "confirmed" })) { ... }` and the SDK transparently pages through. `.toArray(n)` for a bounded read; `.firstPage()` / `.pageAfter(cursor)` for manual paging. Payments list takes `status`/`direction`/`agent_id`/`wallet`/`q` filters; permissions list returns each grant with today's usage + remaining-daily-allowance so agent code can preflight a payment without re-fetching the policy. See [SDK payments](/sdk/payments) and [SDK permissions](/sdk/permissions).
* **`tally.agents.delete()` + `tally.webhooks.list/create/revoke()`** (Phase 3 of the SDK gap batch) — closes out the SDK gap batch's mutating + webhook surfaces. `agents.delete(id)` is a soft-delete (resurrect-on-re-upsert) that 409s with `code: "has_active_grants"` if the agent still has non-revoked permissions — explicit consent ordering. `webhooks.list/create/revoke` round out the resource API alongside the existing `verifySignature`; `create()` returns the plaintext signing secret exactly once. Standalone `verifySignature` export retained for non-class consumers. Schema migration `20260523000000_agent_soft_delete` adds `agents.deleted_at`. See [SDK agents](/sdk/agents) and [SDK webhooks](/sdk/webhooks).
* **`@tallyforagents/sdk@0.2.0` on npm** — SDK gap batch wrapped. New resources: `tally.wallets.*`, `tally.payments.list()`, `tally.permissions.list()`, `tally.agents.delete()`, `tally.webhooks.list/create/revoke()`. Stripe-style `AsyncResourcePage` for paginated lists. Auto-warning to stderr when the API key is in a rotation grace window — server attaches `Tally-Rotation-Grace-Until` on every authenticated /v1 response; client surfaces it once per process. Additive, non-breaking across the board.
* **Onboarding checklist** — the account overview now walks you through the first-run steps (fund a wallet, register an agent, grant a permission, send a payment) and ticks rows off as they complete. Inbound deposits flip the "Fund your wallet" step the moment they land. Each step also has a manual mark-complete escape hatch if you've done it out of band.
* **x402 paying-agent example** — a runnable Claude/GPT agent that autonomously pays for an HTTP 402-gated weather endpoint via Tally. Hosted demo endpoint included — the example points at it by default, so you can run it end-to-end without standing up your own server. Full walkthrough: [Build an x402-paying agent](/guides/paying-x402-agent). Source at [`pkohler95/tally-examples`](https://github.com/pkohler95/tally-examples).
* **`agent.wallets` on the agent response** — `tally.agents.get()` and friends now return the spendable wallets attached to each agent, so you can show "this agent can pay from" without a second call. See [SDK agents](/sdk/agents).
* **Welcome email** — first-time sign-ins now receive a branded welcome email pointing at the docs and dashboard.
* **Terms of Service and Privacy Policy** — live at [/terms](https://www.tallyforagents.com/terms) and [/privacy](https://www.tallyforagents.com/privacy). Voltaire Technologies LLC is the named operating entity.
* **Support email** — reach the team at [support@tallyforagents.com](mailto:support@tallyforagents.com), now surfaced across the dashboard and marketing site.

### Changed

* **Grant-permission defaults** — the grant flow now defaults to **$10 per transaction** and **$100 daily cap**, and the daily cap is required (no more accidentally-unbounded permissions). Tune up or down as needed before signing.
* **Wallet cards** — click any wallet address on the wallets list to copy it. No more selecting and copying by hand.
* **Agent detail page** — the **← All agents** back-link moved to the top of the page so you don't have to scroll to navigate back.

### Fixed

* **First sign-in race condition** — concurrent requests during initial account provisioning no longer occasionally fail; the first sign-in is now serialized.
* **Permission names with long agent slugs** — permission creation no longer fails for agents with longer names; the underlying policy name is now capped at 50 characters automatically.
* **Onboarding "Fund your wallet"** — inbound USDC deposits now flip the step to complete on the same render, instead of needing a refresh.
* **Decimal entry in the grant + edit dialogs** — `.1` and `.3` (no leading zero) now validate cleanly; previously they were rejected as "must be a positive USDC amount." Both `0.1` and `.1` parse identically.
* **Daily cap allows the exact-at-cap payment** — the daily-cap check now uses fixed-point arithmetic (BigInt micro-USDC), so a payment that brings the day total to exactly the configured cap is allowed. Previously, floating-point addition (`0.2 + 0.1 → 0.30000000000000004`) was wrongly rejecting at-cap payments.
* **`insufficient_balance` is now a 403 with a typed code** — payments that fail because the wallet is out of USDC return a `forbidden`-typed response with `code: "insufficient_balance"`, not a generic 500. Use the existing `AuthenticationError` class in the SDK; branch on `err.code`. See [error codes](/api/errors#codes-on-post-v1-payments).

### Coming next

Same roadmap as [2026-05-18](#2026-05-18-public-preview-launch) — programmatic wallet and permission management in the SDK, webhook secret rotation, and live mode opt-in. No timing promises.

***

## 2026-05-18 — Public preview launch

The initial docs site and TypeScript SDK v0 go live alongside the dashboard at [tallyforagents.com](https://www.tallyforagents.com). The product is end-to-end functional on Base Sepolia (testnet); live mode is partially built and ships later.

### Added

* **Dashboard** — sign-in flow with auto-provisioned account and test-mode wallet on first login; full operational surface at `/{slug}/overview` with balance charts, top wallets, top agents, recent activity.
* **Wallets** — Privy server wallets owned by the account; auto-provisioned on sign-in; additional wallets creatable from the dashboard.
* **Agents** — register stable identifiers per autonomous unit you run; per-agent attribution and analytics; status reflects active vs no-permissions.
* **Permissions** — passkey-signed policies bounding what each agent can do (per-tx max, daily cap, recipient allowlist, contract allowlist, expiry). Policy enforcement happens inside Privy's secure enclave.
* **Payments via SDK** — `tally.payments.create()` for outbound USDC transfers with two-layer enforcement (Tally pre-check + Privy enclave). Idempotency keys, structured error codes, lazy chain refresh via `tally.payments.get()`.
* **Webhooks** — six event types (`payment.created`, `payment.confirmed`, `payment.failed`, `inbound.received`, `permission.granted`, `permission.revoked`) with HMAC-SHA256 signatures (`t=…,v1=…`), exponential retry schedule (1m → 5m → 15m → 1h → 6h, 6 attempts), 10-second per-attempt timeout, manual replay from the dashboard.
* **API key rotation** — 24-hour grace window when rotating; old key keeps authenticating while you roll the fleet. Distinct from hard revoke (immediate). Leaked-key scanner watches public commits.
* **Agent permission rotation** — swap a permission's signing key while keeping policy bounds identical; in-place policy edits for changing terms without rotation.
* **Test mode and live mode partitioning** — Stripe-style separation by API key prefix (`tly_test_…` / `tly_live_…`). Test mode is fully functional on Base Sepolia today; live mode opt-in lands later.
* **TypeScript SDK** — `@tallyforagents/sdk` with `agents.upsert/list/get`, `payments.create/get`, `webhooks.verifySignature`. Typed exception hierarchy (`AuthenticationError`, `NotFoundError`, `ValidationError`, `RateLimitError`, `ConflictError`, `TallyError`).
* **REST API at `/v1/*`** — 5 endpoints (`POST /v1/agents`, `GET /v1/agents`, `GET /v1/agents/{id}`, `POST /v1/payments`, `GET /v1/payments/{id}`). Bearer-token auth, mode encoded in key prefix, per-key rate limits (60/min default, 30/min on payments).
* **Documentation surface** — Get Started, Concepts, Guides, API reference, SDK reference, Ops. Everything grounded in the actual implementation; gaps explicitly flagged.

### Coming next

Tracked in `BUILD_LOG.md` (the "SDK gaps queued from the docs rewrite" section). Highlights:

* `tally.wallets.list()` / `tally.wallets.create()` — programmatic wallet management.
* `tally.permissions.list({ agent_id? })` — inspect active permissions and remaining allowance from code.
* `tally.permissions.revoke()` / `tally.permissions.update()` — server-prepare → user-confirm flows, since revocation needs the wallet owner's passkey.
* `tally.payments.list({ filters? })` — filterable payment history.
* `tally.agents.delete()` — soft-delete with 409 on agents that have active permissions.
* `tally.webhooks.list()` / `create()` / `revoke()` — endpoint management.
* Webhook secret rotation with 24h grace window (parity with API key rotation).
* Live mode opt-in flow and Base mainnet support.
* ERC-4337 smart-wallet upgrade path (server wallet becomes the signer; trust model carries forward).

### Known caveats

* **Idempotency is forgiving.** Reusing an `idempotency_key` with a different payload returns the original payment without revalidating — make sure your key derivation is tied to the payload, not just the operation.
* **Live mode isn't wired up yet.** `getDashboardMode()` is hardcoded to `"test"` and no `tly_live_` keys are issued. Test mode is fully functional.
* **`@tallyforagents/sdk` is internal-only today.** It's not yet published to npm; consume it from the monorepo for now. *(Resolved 2026-05-22 — SDK is now on npm as `@tallyforagents/sdk@0.1.0`.)*

***

## How to read this changelog

* **Added** — new endpoints, SDK methods, dashboard features, webhook event types.
* **Changed** — behavior shifts in existing surfaces. If the change could break working code, it'll be called out as a breaking change.
* **Fixed** — bug fixes worth mentioning (silent fixes don't make the log).
* **Deprecated** — surfaces that still work but will be removed. Each deprecation entry includes a target removal date.
* **Coming next** — things on the immediate roadmap. No promises on timing; included so you can plan around them.

Subscribe to releases on [GitHub](https://github.com/pkohler95/tally-v2/releases) to be notified when entries land.
