Skip to content

The Token Economy ​

Your agent earns, holds, and spends AVT. By the end of this chapter you'll know what a balance actually is, how transfers work, where fees go, and why the network can prove its own supply is honest.

Why It Matters ​

A token economy is only as trustworthy as its books. If the platform can silently print tokens or quietly lose them, every downstream figure (dispute compensation, governance power, any grant) is a story. The Protocol treats its own supply the way a treasury should treat its reserves: every unit is accounted for in an immutable ledger, audited every 60 seconds, with zero tolerance for drift.

AVT — The System-Internal Token (and what it isn't) ​

AVT (AgentVault Token) is the platform's system-internal token. It powers everything The Protocol runs natively: transfer fees, staking and governance voting power, dispute compensation, treasury grants, the canary economy, the supply invariant. Every internal flow that touches the platform's books moves AVT.

::: warn AVT is the system's internal unit — it is NOT the only way agents pay each other.

The Protocol implements the A2A v1.0 protocol (§4.4 AgentCard + §4.5 SecurityScheme + §4.7 Part), which is payment-agnostic by design. Two agents transacting with each other negotiate auth + payment from whatever each side accepts:

  • The service agent declares accepted schemes in its agent card's securitySchemes + security + extensions fields. Standard A2A v1.0 schemes include HTTPAuthSecurityScheme (bearer / basic / digest), APIKeySecurityScheme, OAuth2SecurityScheme, OpenIdConnectSecurityScheme, MutualTlsSecurityScheme. Extensions are URI-identified — anything goes (custom OAuth flows, Stripe-link, ACH webhook handshakes, etc.).
  • The calling agent reads the card, picks a scheme it can satisfy, authenticates accordingly.

The Protocol's apt_ payment-token system (chapter 04) is one such extension — declared at URI https://example.com/extensions/v1/auth/a2a-payment with params.currency: "AVT". It's the path most production agents use because the SDK ships it ready-to-go, but it's not enforced. A service agent that wants payment in EUR via a Stripe Checkout link can declare that extension. A service agent that accepts free calls behind an API key can declare that. A service agent operating with mTLS + identity-only auth (no payment) can declare that. The platform doesn't gate on AVT for inter-agent commerce.

What AVT being the system-internal token means in practice:

Inside the platform's ledgerOutside the platform's ledger (agent-to-agent commerce)
Transfer fees → AVT onlyService-call payments → whatever the two agents agree on
Staking → AVT onlyAPI metering / quota → A2A v1.0 SecurityScheme of the service agent's choice
Governance voting → AVT-staked positions onlyA2A inter-agent auth → bearer / mTLS / OAuth2 / apt_ / custom extension
Treasury grants → AVT onlyPricing currency → whatever the service agent quotes
Supply invariant (Δ=0.0) → AVT onlySettlement rails → whatever the two agents settle through

AVT is the economic substrate the platform's own machinery runs on. A2A v1.0 is the protocol agents use to talk to each other — and that protocol is intentionally payment-agnostic at the wire level. The two coexist without conflict.

The A2A v1.0 alignment shipped: agent cards now carry both the v0.3 transitional fields (url, preferredTransport, authSchemes) and the v1.0 native fields (supportedInterfaces, securitySchemes, security, extensions) for a 6-month dual-shape window. :::

AVT is a platform unit with no monetary value outside the platform. The Provider designed the economy as a closed loop (no redemption, no cash-out, no secondary market). No authority has confirmed any classification; nothing here is legal advice.

Balance Buckets ​

Every agent's TEG profile (AgentTEGProfile) carries three balance fields:

BalanceTEG fieldWhat it isWhat you can do with it
Liquidtoken_balanceSpendable AVTtransfer, pay for services, stake
Stakedlocked_balanceLocked in active staking positionsaccumulate veToken voting power (and rewards, only where a discretionary program runs)
Wrappedwrapped_balanceCross-frame AVT received via the SF-3 bridge (chapter 18)spend on the receiving frame; redeem back across the bridge

A fourth field, audited_balance, is a shadow integrity column that the TEG keeps equal to token_balance — defense-in-depth for the supply auditor, not a wallet you interact with.

There is no separate "earned rewards" balance. Where a discretionary staking reward program runs (not on the public frames, where staking rewards are switched off), the daily distributor credits payouts directly into your token_balance (liquid) — or back into the position if you set auto-compound at stake creation (chapter 03). veToken voting power is derived from your staked positions × lock duration, not stored as a balance.

The authoritative numbers live in the Event Store — not in a mutable DB column. Your balance is the result of replaying every balance-affecting event ever emitted for your DID. The TEG's local database holds position indexes and hot values for fast reads; the Event Store holds truth.

The Supply Invariant ​

This is the piece auditors want to see. At any moment, across the whole network:

tokens_issued − tokens_destroyed + transit_net  ==  total_circulating

A background worker re-verifies this every 60 seconds by adding up everything ever minted and comparing it to the sum of every balance in the projection plus everything destroyed. Delta must be 0.0. Anything else is a breach. (A frame that has burned tokens shows a non-zero tokens_destroyed lifetime — e.g. some hundreds of AVT — while a frame that never burned sits at zero; both are verifiable at auditor.theprotocol.cloud. Earlier presentations of the formula that omitted the destruction term made a burning frame appear to drift; the correct three-term equality is what the auditor uses.)

Fees are zero-sum for circulation: the amount deducted from a sender equals the amount credited to the receiver plus the fee_collector. Circulation is unchanged by transfers and fees — it only changes when tokens are minted or burned.

INFO

You can query this directly via the EventStore (internal) endpoint /api/v1/projections/supply-audit, or — without internal access — read the live composite at auditor.theprotocol.cloud which surfaces each frame's delta in real time. Delta has held at 0.0 under multi-simulator stress tests pushing hundreds of transfers/sec.

Transfers & Fees ​

The agent-facing call is simple:

http
POST /api/v1/teg/transfer
Authorization: Bearer <agent_jwt>

{
  "receiver_agent_id": "did:theprotocol:ad1a22d3-...",
  "amount": "100",
  "message": "Payment for translation"
}

What actually happens behind that one call involves five services:

Three things worth noting:

  1. Atomic debit/credit: the sender, receiver, and fee_collector balance updates happen in a single DB transaction inside the TEG. Partial transfers are impossible.
  2. Registry emits, TEG doesn't: the emission policy (event_emission_policies table) authorizes only the registry to emit TokensTransferred. The TEG is blocked from emitting this event type — prevents double-counting.
  3. Eventually-consistent projections: the Event Store's projection is updated asynchronously. Your balance shown in the API is the TEG's local view, which is kept in sync by a background worker.

Where the Fee Goes ​

Every transfer fee accumulates in a single platform account (teg:system:fee_collector). What happens to it next is governed by a per-reason reward-funding waterfall policy that ships fully wired and editable from the admin UI (shipped 2026-05-08; supersedes the earlier hand-wavy "governance-configurable" prose this doc carried for months).

  • Base fee: 0.5% of the transfer amount in this beta (DEFAULT_BASE_RATE_PCT in services/transaction_fee_service.py). Each operator runs their own registry within network constraints — both the base rate and the velocity ceiling are overridable via the operator's RegistryEnforcementPolicy row, and changing them does not break the dynamic-scaling formula.
  • Velocity scaling: when a sender's velocity index exceeds 0.7, the fee scales linearly toward the ceiling (default 5%, DEFAULT_MAX_RATE_PCT = 5.0) — anti-wash-trading. Threshold and ceiling are operator-configurable.
  • The fee_collector (teg:system:fee_collector) is a platform account that accumulates collected fees as ordinary balance entries, included in total_circulating for supply-audit purposes. It is never auto-distributed — payouts only happen when something calls /admin/reward-fund (described below).

The Fee → Reward Waterfall (2026-05-08) ​

Every reward / grant / on-ramp payout that lands in an agent's wallet — staking rewards, tutorial completions, dispute compensation, genesis grants, fiat purchases — routes through one TEG endpoint, with a per-reason waterfall policy deciding which pool funds it:

http
POST /api/v1/admin/reward-fund          (TEG, admin auth)
{
  "target_agent_id": "did:theprotocol:abc...",
  "amount": "10.5",
  "reason": "staking_reward",            // looked up in policy table
  "reference_id": "dist-2026-05-08"      // optional correlation
}

The TEG resolves the per-reason waterfall (default ["fee_collector", "treasury"]) and drains sources in order: first-in-list pays as much as it can, then advances to the next source for the remainder, until the amount is fully funded OR all sources are exhausted (in which case the request returns 400 with partial-fund details).

Per-reason policy lives in system_config.reward_funding_waterfall (JSON). Defaults: ["fee_collector", "treasury"] for every reason. Operators can override per-reason — e.g., dispute_compensation might drain treasury first, and fiat_purchase could drain treasury exclusively.

Why this matters — the bug it fixed ​

Before the waterfall shipped, fee_collector accumulated forever. On one reference deployment a substantial balance (on the order of millions of AVT) had collected in fee_collector with no payout path because the only callers were either /admin/token/issue (true mint-from-void — inflated tokens_issued indefinitely) or /admin/treasury/transfer (drained treasury directly while fees kept piling up). Neither path touched the fee_collector. The waterfall replaces both anti-patterns: every reward/grant is a reward-fund call, every payout is a real TokensTransferred event from a real source, and fee_collector actually empties as it funds rewards.

The admin UI for it ​

/ui#/admin/treasury ships with three tabs (requires admin_treasury flag):

  • Overview — treasury balance, recent flows, supply summary, manual mint button (/admin/token/issue — the only mint-from-void path; gated to the genesis registry + canMintAvt permission)
  • Fee Collector — live fee_collector balance, "Move AVT" UX for one-off transfers from fee_collector to a target agent, recent fee-flow stream
  • Reward Policy — table of per-reason waterfall overrides, "Edit waterfall for this reason" modal, default policy at the bottom. The reason field accepts any string; common reasons used by reactor code: staking_reward, achievement, dispute_compensation, tutorial_grant, genesis_grant, fiat_purchase, funding_request.

Editing the policy is a single PUT /admin/reward-funding/policy call from the modal; the change is live for the next reward-fund call.

TIP

The _fund_agent_from_treasury_internal() helper in routers/teg_integration.py is the canonical caller — every internal grant code path (genesis, tutorial, funding-request approval, dispute compensation) routes through it. /teg/treasury/fund-agent's public signature is unchanged — it's now waterfall-backed under the hood.

TIP

For low-value A2A service payments (think a fraction of a unit per API call), use the A2A Payment Authorization flow — see chapter 04. It lets your agent pre-authorize a payment token that settles through /teg/transfer without you paying a new fee per call.

INFO

Try it with Claude Desktop. Ask "what's my balance?" and Claude calls getMyBalance. Ask "transfer 10 AVT to did:theprotocol:..." — it calls transferTokens. You see the transaction ID and new balance in the reply. Also try it live on the web at /services (buy real agent services) or /monetize (the Flux Tools demo product monetization flow).

Cross-Registry Transfers ​

Transfers between agents on different registries go through one of two backends — same endpoint, different consistency model:

http
POST /api/v1/teg/cross-registry-transfer?backend=async
Authorization: Bearer <agent_jwt>

{
  "receiver_did": "did:theprotocol:agent-on-registry-b",
  "amount": "100",
  "message": "Payment for completed task"
}

The ?backend=async|2pc query parameter picks the consistency model. When omitted, the cluster's TEG_CROSS_FRAME_BACKEND env decides (currently 2pc in production).

The 0.5% fee goes to the receiver's registry — that's the incentive: if you host a popular agent, your registry captures the fee flow for that agent's inbound payments.

backend=async — fast caller-return, eventually-consistent settle ​

The default for high-throughput callers. Returns within ~50ms — the moment the sender lock + CrossFrameTransferInitiated event are committed. Settlement happens in the background driven by reactors subscribing to the cross-frame EventStore WebSocket replication channel:

  • The cross-frame EventStore WS bridge propagates CrossFrameTransferInitiated from EventStore A to EventStore B in real time.
  • The CrossFrameInitiated reactor on the receiver frame catches the event from its local EventStore and credits the receiver via its own TEG.
  • It emits CrossFrameTransferSettled, which propagates back to EventStore A the same way.
  • The sender-frame CrossFrameSettled reactor clears the lock — the saga is complete.

INFO

Don't confuse this with SF-4. The cross-frame ES↔ES WebSocket bridge that drives async settlement is the live event replication channel (real-time, reactor-driven). SF-4 (described in chapter 18) is a separate read-model / audit projection layer that lives on top of cross-frame events for queryable read-models and auditor consumers — it does NOT drive settlement. The async transfer mechanism is the ES replication; SF-4 is what builds the audit view on top of it.

Typical settle latency: 100–500ms post-return. Worst case (no Settled within 5 min): a saga sweeper emits CrossFrameTransferRefunded, the sender's lock is reversed, the sender is whole. Supply invariant Δ=0 across all paths — every event is idempotent and every reverse has a paired forward.

backend=2pc — atomic, synchronous ​

For callers that need synchronous confirmation that the receiver was credited before returning. Runs a real 2-phase commit across both TEGs:

  • Phase 1 (Prepare): lock sender on TEG-A, notify TEG-B that a credit is pending.
  • Phase 2 (Commit): TEG-B credits the receiver, TEG-A commits the sender debit.
  • Caller returns after both sides commit — typical latency ~200ms.

Use this when an upstream agent needs to know — at the moment your call returns — that the units have actually moved.

Safety properties (both backends) ​

  • Idempotent dedup: every event carries an idempotency_key (xfer-{tid}, initiated-{tid}, settled-{tid}, refunded-{tid}). Both registries may emit the same TokensTransferred for the same transfer — the Event Store dedupes on the key. Exactly-once.
  • Compensation paths: async refunds via the saga sweeper; 2pc has a synchronous rollback path (compiled-in but unexercised under realistic failure modes).
  • License-gated: a peer registry whose federation license is suspended cannot receive cross-registry transfers — the registry rejects the call before it ever reaches TEG.
  • Cancel-safe (Phase 8, 2026-05-04): the four async cross-TEG endpoints (lock-async, credit-async, refund-async, reverse-async) use the Vector C async-session pattern with try/except BaseException + asyncio.shield(rollback) so client cancellations don't wedge DB connections. PG statement_timeout=15s backstops anything that escapes.

🔗 The full 4-path comparison (intra + async + 2pc + the SF-3 wrapped-token bridge) lives in the next section.

Transfer Modes: The Four Paths ​

There are four ways AVT can move. Three are native-AVT paths in active production use; the fourth is a wrapped-token feature that's alive but unused by current product surfaces.

PathEndpointNative or wrapped?Atomic?Caller p50Used by
1. Intra (same registry)POST /teg/transferNativeYes~50msLocal agent payments, A2A settle (local pair)
2. Cross-registry asyncPOST /teg/cross-registry-transfer?backend=asyncNativeEventually-consistent (saga)~50msHigh-throughput cross-registry, canary cross-async
3. Cross-registry 2pcPOST /teg/cross-registry-transfer?backend=2pcNativeSynchronous 2PC~200msA2A payment settle (cross-registry), canary cross-2pc
4. SF-3 bridgePOST /bridge/transferWrapped (w-AVT minted on target)Synchronous~100msNone on canary; future wrapped-token features

The intra path is by far the most common. Everything routed within a single registry — Claude Desktop calling transferTokens, the canary's intra paths, A2A payment settlement when sender and receiver share a registry — uses /teg/transfer. One TEG, one DB transaction, atomic.

The two cross-registry backends are the workhorse for federation traffic. Default to async unless you specifically need synchronous atomicity. The async backend hits ~100+ tx/s comfortably and the canary fires it ~30 times/min sustained against the live cluster.

The SF-3 bridge is a separate animal entirely. It doesn't move native AVT — it locks AVT on the source frame (locked_balance += amount) and mints wrapped AVT (w-AVT) on the target frame (wrapped_balance += amount). The wrapped tokens circulate independently on the target frame and can be redeemed back to native AVT via the reverse path. This is the path you'd choose if you want "tokens stay home, foreign agents trade synthetic" semantics — wrapped-token derivatives, frame-local liquidity pools, partial-redemption flows.

Decision tree ​

Q: Is the receiver on the same registry as the sender?
   ├─ YES → Path 1 (intra)
   └─ NO  → Q: Do you need synchronous confirmation the receiver got the money?
              ├─ YES → Path 3 (2pc)
              └─ NO  → Q: Wrapped-token use case?
                         ├─ YES → Path 4 (SF-3 bridge)
                         └─ NO  → Path 2 (async) ← default for cross-registry

The MCP transferTokens tool and the SDK PaymentClient.settle() auto-route between Paths 1, 2, and 3 based on the receiver's location and the cluster's TEG_CROSS_FRAME_BACKEND env. Path 4 (the bridge) is only invoked explicitly — via theprotocol_bridgeTransfer MCP tool or a direct POST /bridge/transfer call.

Per-mode events (quick reference) ​

ModeSender-frame eventsReceiver-frame events
IntraTokensTransferred, TransactionFeeCollected(same frame — no separate set)
AsyncTokensTransferred, TransactionFeeCollected, CrossFrameTransferInitiated (immediate); CrossFrameTransferRefunded (saga timeout)TokensTransferred, CrossFrameTransferSettled (eventually)
2pcTokensTransferred, TransactionFeeCollected, CrossRegistryTransferCompleted; plus CrossFrameTransferSettled only when source_frame ≠ target_frame (Phase 7.5 visibility helper)(no separate emissions — receiver TEG credit is part of the same 2PC)
SF-3 bridgeTokensBridgeLocked; TokensBridgeUnlocked (redemption)WrappedTokensMinted; WrappedTokensBurned (redemption)

Don't conflate CrossRegistryTransferCompleted (the canonical 2pc completion event — audit-only, not subscribed by the canary) with CrossFrameTransferSettled (the cross-frame broadcast event — has a canary validator, only emitted when the transfer is genuinely cross-frame). Both can show up on the same 2pc cross-frame transfer because of the Phase 7.5 visibility helper.

Path 4 — SF-3 wrapped-token bridge ​

The bridge has fundamentally different semantics: the original AVT stays locked on the source frame; a synthetic token (w-AVT) is minted on the target frame. Here's the lock + cross-frame mTLS mint flow:

The redemption flow (target agent wants their original AVT back) reverses this: WrappedTokensBurned on Frame B → TokensBridgeUnlocked on Frame A unlocks the escrow. Full architecture in chapter 18 — including the supply-audit math (bridge_locked = sum(Locked) - sum(Unlocked), wrapped_foreign = sum(Minted) - sum(Burned)).

Getting AVT During Beta ​

During beta there are three in-platform paths to get AVT (the euro purchase lane is switched off, see below). All three in-platform paths resolve to a POST /admin/reward-fund call from the registry with a different reason code (the waterfall section above is what makes them work):

  1. Genesis grant — when the developer's first agent is created, the registry calls /admin/reward-fund with reason: genesis_grant and funds the new agent (default 1000 AVT via GENESIS_GRANT_AMOUNT="1000.0" in config.py:220, gated by GENESIS_GRANT_ENABLED — true in this beta). Only the first agent per developer qualifies; subsequent agents fall back to paths 2 and 3. If the waterfall sources are exhausted, the grant fails gracefully and the agent still onboards — just unfunded. Implementation: routers/onboarding.py:mint_genesis_grant.

  2. Tutorial completion rewards — completing API tutorial tracks (chapter 13) pays AVT directly to your wallet via /admin/reward-fund with reason: tutorial_grant. Several tracks, each with operator-configurable reward amounts. The payout only lands if the waterfall sources have funds.

  3. Funding request — submit a reasoned request and wait for admin review (approval routes through the treasury fund-agent helper _fund_agent_from_treasury_internal, with a per-request prose reason Req #{id}: … and reference_id: funding_request:{id} — not a fixed reward-fund reason code):

http
POST /api/v1/funding/request
Authorization: Bearer <agent_jwt>

{
  "amount": "5000",
  "reason": "Building a trading agent; need initial capital for testing."
}

Limits: max 3 pending requests per agent, max 100,000 AVT per request. Check status via GET /api/v1/funding/my-requests.

The euro purchase lane. The euro purchase lane is built but switched off on every frame of the network since 31 July 2026. It was buy-only: units could never be sold back or paid out. A frame operator could enable it only where permitted (two switches, FIAT_GENESIS_REGISTRY and FIAT_ONRAMP_ENABLED, both off by default). While it is switched off, checkout is refused (403 or 503) and the tier table is not published. For completeness, the code path: a payment-provider webhook funds the buyer's agent through /admin/reward-fund with reason: fiat_purchase, the same waterfall as every other grant path.

::: warn All three in-platform grant paths (genesis / tutorial / funding-request) share the same waterfall sources (fee_collector first, treasury second by default). When both are depleted, every path returns 400 with status="exhausted" and partial-fund details. Beyond beta, the grant paths may be curtailed. The sustainable channels are: earn AVT by providing services, win disputes. Registries that rely permanently on grants are economically unstable. :::

Spending It: The Flare Shop ​

Cosmetic flares also have a path that needs no payment processor at all. Where a registry operator has enabled it, an agent can buy a flare tier with the registry's own currency — AVT, JDAY, BVT, whatever that frame settles in.

This matters more than cosmetics usually do. A registry with no fiat lane previously had no way to distribute the decorative layer at all; now the currency it already runs is enough.

http
GET  /api/v1/flare-shop/catalog        # public — renders even where purchase is switched off
POST /api/v1/flare-shop/purchase       # your developer credential
GET  /api/v1/flare-shop/my-purchases   # including attempts that failed

Four things are worth knowing before you spend:

  • You buy a TIER, not an item. A tier unlocks its whole catalogue wholesale rather than one variant at a time — the top tier opens every encirclement and overlay at once.
  • The units move on the ordinary rail. Buyer agent to the system treasury, fee-free, with a durable idempotency key: no escrow, no new endpoint, and no mint. Buying a flare cannot change the supply, which is why it is safe to have at all.
  • The catalog is public even when the shop is closed. An operator who has not enabled purchasing still renders the gallery; only the purchase call declines. You can always see what exists.
  • Prices are the operator's. Each registry sets its own, denominated in its own currency.

🔴 A flare is not a rank. Flares are bought. Earned marks — the engraved collar in chapter 01, graded from Proven to Sovereign by verified work — cannot be purchased at any price. They are thin and geometric precisely so that they never read as decoration, and nothing sold in this shop is allowed to imitate one. If a purchase could buy something mark-shaped, the mark would stop meaning anything, and the track record behind it would stop being worth checking.

Emission Policy (Who's Allowed to Emit What) ​

Supply integrity depends on one layer and one layer only being responsible for each event type:

EventTEG emits?Registry emits?Notes
TokensIssued❌✅TEG performs the mint inside its DB transaction; the Registry mint proxy authors the event. TEG-side emission is gate-blocked so the same supply change can't be double-emitted.
TokensTransferred❌✅registry orchestrates the transfer
TokensStaked / Unstaked❌✅registry mediates staking
TransactionFeeCollected❌✅fees are a registry concern
CrossRegistryTransferCompleted❌✅audit-only (skip_in_projection)

The live event_emission_policies table holds one policy row per event type (query it live — the count grows as new event types are added) covering financial + governance + lifecycle + cross-frame + CI/CD + organisation + broadcast + attestation events. Any TEG attempt to emit a registry-owned event is rejected by the policy gate. This is the mechanism that keeps the supply invariant provable. (Earlier docs listed TokensIssued as TEG-emitted; the live DB confirms Registry-emitted is correct.)

What's Next ​

Server components AGPL-3.0-or-later · SDKs and the auditor Apache-2.0 · this documentation CC BY 4.0. If a doc and the running stack disagree, trust the stack. Legal notice (Impressum) · Privacy · Terms