Raeto

Agent Account History

Profile raeto-account/v1 · Status live on Robinhood Chain (chain 4663) since November 2026 · Published at https://raeto.cc/account-history

An agent's account history is an onchain record of how it handles money day to day: what it spent, what it earned and from whom, whether it ran dry, and whether anyone can check the figures. It is the bank-account side of an agent's financial identity. Credit history (ERC-8466, Agent Credit History) records what an agent borrowed and repaid; account history records everything else.

Statements are written to the ERC-8004 reputation registry in the same shape as ERC-8466 credit statements: the same registry, the same giveFeedback call, a canonical JSON file carried in the entry as a data: URI, and hash-chained, back-to-back windows. A reader that already handles credit statements reads these with the same code, and can tell them apart by tag1.

This document describes the format exactly as Raeto writes it. The key words MUST, MUST NOT, SHOULD and MAY are used as in RFC 2119.

Contents

  1. Where statements live
  2. Encoding
  3. The file
  4. The chain of statements
  5. The figures
  6. Rungs
  7. Receipts and hourly anchors
  8. Who gets a record
  9. Verifying a record
  10. Reading it as a lender or scorer
  11. Privacy
  12. Versioning
  13. Examples

1. Where statements live

Robinhood Chain (4663)
Identity registry (ERC-8004)0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
Reputation registry (ERC-8004)0x8004BAa17C55a88189AE136b182e5fdA19dE9b63
Statement writer (clientAddress)0x9d420a047EE7Cdc4FCbCbE891308306543Ee2DFf; current and past writers at GET https://api.raeto.cc/v1/statements/writers
Receipts anchor wallet0xb0Cde84c3F65C2551F309C560d0Fd0A192522b59
AssetUSDG 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168, 6 decimals

Each statement is one giveFeedback entry from the writer, for the agent's ERC-8004 id:

FieldValue
agentIdthe agent's ERC-8004 id
valuemoney moved in the window, USDG base units (§5.1). 0 for genesis, paused and stopped statements
valueDecimals6
tag1account.statement, or account.correction (§4.4)
tag2the kind: genesis, period, paused or closed
endpointempty
feedbackURIthe file as a data: URI (§2)
feedbackHashkeccak256 of the file's bytes

The writer is a gas-only wallet. It MUST NOT own or operate an agent, so a statement is never an agent rating itself.

2. Encoding

The file is canonical JSON (RFC 8785 as applied here): object keys sorted, no whitespace, numbers only as non-negative safe integers, and every amount and id as a decimal string ("4180000", never 4.18). Optional fields are left out, never null, except where this document says null is a value.

feedbackURI is one of:

Readers MUST accept both and MUST decode strictly: the exact prefix, canonical base64, and text that re-encodes to the same canonical JSON. Anything else is not a statement. feedbackHash MUST equal keccak256 of the decoded bytes. A file is at most 8,192 bytes; Raeto's weekly files run about 2 KB, under ERC-8466's 4 KB guidance.

3. The file

3.1 Top level

FieldMeaning
agentRegistryeip155:4663: + the identity registry
agentIdthe agent's ERC-8004 id, a decimal string
clientAddresseip155:4663: + the writer
createdAtwhen the file was built, YYYY-MM-DDTHH:MM:SSZ
value, valueDecimalsas in the entry: money moved, 6 decimals
tag1, tag2as in the entry
accountthe statement (§3.2)

3.2 account

FieldMeaning
vraeto-account/v1
provider{ name: "Raeto", about: "https://raeto.cc/account-history" }
chaineip155:4663
asset, decimalseip155:4663/erc20: + USDG, and 6
holder{ account, owner, match, tag? }: the Raeto account the agent runs on, the identity's owner when the statement was built, and how the two were tied (§8)
scopeagent-usage on a fleet agent's statement only (§3.3)
enrolmentauto or consent (§8)
kindgenesis, period, paused or closed; equals tag2
seq1, 2, 3 … (§4)
prevfeedbackHash of statement seq - 1; null on seq 1
window{ from, to }, unix seconds
posted{ cadence, reason }: weekly, biweekly or daily, and why this one posted (opening, weekly, biweekly, daily, milestone, paused, closed, correction)
figuresmoved, ai, tools, routing, payments, income, balance, flows, selfSufficiency, activity, rung, limitHits, refusals (§5, §6)
receiptswhat the figures were computed from (§7)
genesis, paused, closed, correctsby kind (§4)

3.3 Fleet agents

An operator running many agents on one Raeto account tells them apart with a stable tag on every call (X-Raeto-Agent). Each tagged agent can have its own record. Its statements set holder.match to partner-tag, holder.tag to the tag (1 to 128 characters) and scope to agent-usage, and carry usage only: moved, ai, tools, routing, activity, rung and receipts (the receipts tagged with it; a call serving several agents is split evenly). The account's money belongs to the operator, so a usage statement MUST NOT carry payments, income, balance, flows, selfSufficiency, limitHits or refusals. Its rung stops at Steady.

4. The chain of statements

A record is one chain of statements per agent id, never per owner, so one owner's busy agent cannot prop up another.

4.1 genesis

Seq 1, value 0. It opens the record and carries genesis: { anchored: false, since, requests, spent, received, sent, tokens, balance, note }, the lifetime totals Raeto counted before receipts were anchored. These are a claim, not checked figures, and anchored is always false to say so.

4.2 period

The regular statement. Its window starts where the last one ended and ends at a UTC midnight, set by the record's cadence and its first day with money in or out:

Quiet stretches write nothing: the next window starts where the last one ended and covers them. Statements are built a couple of hours after the window ends, once that window's receipts are anchored.

4.3 paused and closed

4.4 Corrections

A statement is never revoked. If one is wrong, an account.correction entry names it in corrects: { seq, hash }, and its figures replace the named statement's. Corrections are not part of the seq chain.

5. The figures

All amounts are USDG base units (6 decimals) as decimal strings. Counts are integers. Figures cover the window only, except where they say 30 days.

5.1 moved

The headline, equal to value: real money the agent spent on AI requests, tools and routing, plus real money it paid to others outside its own cluster (§5.4), net of refunds. Like ERC-8466's value (principal repaid on time), it is money that actually moved. Credits Raeto gave out (promo, bonus, gifts) do not count as moved. Money sent to a lender is a repayment, not money moved.

5.2 Usage

FieldMeaning
ai{ requests, amount, tokens }: AI model requests, what they cost, tokens in and out
tools{ calls, amount }: paid tool calls
routing{ decisions, amount }: requests where Raeto picked the model, and its fee for that

5.3 payments

{ count, amount, payees }: payments the agent made to others through Raeto Pay, and to how many payees.

5.4 income

FieldMeaning
amount, payments, payersverified income in the window
d30{ amount, payers }: verified income over the 30 days ending at window.to
excluded{ promo, self, lender, roundTrip, overCap, belowFloor }: money received that did not count, by reason
onchainoptional { amount, payments }: USDG paid straight to the agent's account or declared wallet from outside wallets, gross
sourcesoptional, 1 to 16 entries { id, label, amount, payments }: income from approved revenue sources and from contracts in the window, by source (see below). Present only when there is some

Only income that costs real money to fake counts. These are the same rules as Priors' Score v2 income input:

5.5 balance

{ opening, closing, average, minimum, openingPromo, closingPromo, daysAtZero }. opening, closing, average and minimum keep their sign: a balance can go below zero when a chargeback is taken back, and a statement says so. The *Promo figures are how much of the balance was credits Raeto gave out. daysAtZero counts UTC days in the window that with a balance at $0.01 or less. closing follows from opening and every receipt in the window (§7), so it can be checked.

5.6 flows

in: { earned, funded, deposited, promo, returned } and out: { spent, paid, movedOut, withdrawn, fees }: every way money entered and left the account in the window.

5.7 selfSufficiency, limitHits, refusals, activity

FieldMeaning
selfSufficiency30-day verified income per 30-day real money out, in basis points (10000 = it pays its own way); null when nothing went out
limitHitsrequests refused because a limit (a daily cap, a budget) was hit
refusalsrequests refused for safety
activity{ weeksOnRecord, activeWeeks, cleanWeeks }, in calendar weeks (Monday to Monday, UTC)

6. Rungs

A record's standing is a rung, not a score. Each rung includes the ones below it, and the time gates mean nobody climbs overnight. rung is { level, name }.

LevelNameWhat it takes
0NewOn record
1Active8 active hours: UTC hours with at least $0.01 spent or paid (credits Raeto gave out count toward this rung)
2SteadyActive, 5 active days, no day at zero balance in the last 4 weeks, and no limit hit or safety refusal in the last 8 weeks
3EarningSteady, and verified income from at least 2 outside payers in the last 30 days
4Self-sustainingEarning, and 30-day verified income covers 30-day real money out

A rung describes the record. It is not a guarantee. A fleet agent's rung stops at Steady (§3.3).

7. Receipts and hourly anchors

Every movement of money on a Raeto account leaves a receipt: an AI or tool charge, a payment sent or received, a deposit, a refund. A receipt holds the account, a per-account sequence number, the time, the kind, the amount, the balance after it (bal), how much of that balance is promo (pbal), whether the money behind it came only from onchain deposits (real), and the previous receipt's hash. It holds no prompts and no answers. h = keccak256(canonical JSON of the receipt without h), so each account's receipts form a hash chain.

Every UTC hour, Raeto folds that hour's receipt hashes (leaves keccak256(h), in the order written) into a Merkle root with sorted pairs (compatible with OpenZeppelin MerkleProof) and posts it from the anchor wallet to itself as transaction data:

"RAETO-RCPT-1" (12 bytes) | epoch uint64 | count uint32 | root bytes32 | prevRoot bytes32

epoch is floor(unix seconds / 3600). prevRoot is the previous anchored hour's root, so the anchors form a chain and a skipped hour shows. An hour with no receipts gets no anchor.

A statement's receipts names what it was computed from:

FieldMeaning
count, first, lasthow many receipts, and the first and last sequence numbers
headthe hash of the last receipt
hours, roothow many hours they span, and a Merkle root over those hours' roots
anchoredtrue when every one of those hours was anchored before the statement was built
anchorsthe latest anchor references, { epoch, root, tx } (Raeto writes up to 5; readers accept up to 16)
unrecorded{ count, amount }: balance changes no receipt explained, written down so the chain still adds up

An owner can export its agent's receipts with Merkle proofs (GET /v1/receipts/export) and check every figure against the anchored roots.

8. Who gets a record

A record needs a provable link between the agent's ERC-8004 identity and the Raeto account it runs on. holder.match says which kind:

matchenrolmentThe link
declared-walletautoThe identity's payment wallet (getAgentWallet) is the Raeto account, set apart from the owner. The chain proves it; no signature is needed.
self-ownedautoThe account owns the identity, the payment wallet is the owner, and the account works as an agent (agent keys, no app sign-in).
owner-consentconsentThe identity's owner signed a consent (below).
partner-tagconsentA fleet agent: the owner signed which tag each identity covers (§3.3).

The consent is EIP-712, signed by ownerOf(agentId) (a wallet, or a contract through EIP-1271):

domain  { name: "Raeto Account History", version: "1", chainId: 4663 }
Consent { agentId uint256, account address, owner address, publish bool, nonce uint256, deadline uint256 }

To publish many records with one signature, the owner signs PublishRecords { owner, requestedBy, count, recordsHash, pricePerStatement, chargedTo, publish, nonce, deadline } in the same domain. recordsHash is keccak256(abi.encode((uint256 agentId, address account)[])) sorted by agent id, or, for fleet agents, (uint256 agentId, address account, string tag)[], so the signature binds which tag each identity covers.

9. Verifying a record

Anyone can check a record with nothing but a Robinhood Chain RPC endpoint:

node verify-account-statement.mjs <agentId> [--rpc URL]

The script (https://raeto.cc/verify-account-statement.mjs, Node 18+ and ethers v6) runs five checks:

  1. Found. Every entry the registry counts for each writer (getLastIndex) was read back.
  2. Files. Each file decodes strictly, hashes to its feedbackHash, names this agent and writer, and its value is the moved it states.
  3. Chain. Seq 1, 2, 3 … with no gap, each prev the previous hash, windows back to back, seq 1 a genesis, nothing after a closed.
  4. Anchors. Every receipts root a statement names was anchored: the transaction exists, came from the anchor wallet, succeeded and carries that hour and root.
  5. Corrections. Each correction points to a statement that exists, by seq and hash.

What this proves: the record is complete, unaltered and anchored hour by hour. The figures are Raeto's statement of what it saw. The anchored receipts let anyone holding them (an owner's export) check the figures too.

10. Reading it as a lender or scorer

Account history is meant to sit next to credit history. Some signals a reader may use:

Loans never appear as income or money moved, so an agent's Priors borrowing does not inflate its account history, and the two records can be read side by side without double counting.

11. Privacy

Statements carry totals only: no prompts, no answers, no counterparties, no model names, no per-call amounts. The payer count says how many, never who. Receipts stay with Raeto and the account's owner; only their hourly roots are public.

12. Versioning

account.v names the profile. Additive changes (a new optional field) keep raeto-account/v1, and readers MUST ignore fields they don't know. A change that alters the meaning of an existing field gets a new profile name, and a record never mixes profiles within its chain.

13. Examples

13.1 A real genesis statement

rae, agent #20515 on Robinhood Chain, opened its record on November 2, 2026. Transaction 0x140168157401994f2e5e2a28a8bc2bf9cc3182325f620181758aadc9d2366ccf, block 104,531,419, feedbackHash 0xe08f51e2796370debf398865e242f2128ebcfd7b32fca79374906ae21e82c0b7. The file, pretty-printed (on chain it is the canonical form):

{
  "account": {
    "asset": "eip155:4663/erc20:0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
    "chain": "eip155:4663",
    "decimals": 6,
    "enrolment": "consent",
    "genesis": {
      "anchored": false,
      "balance": "9999811",
      "note": "Lifetime totals as Raeto counted them before receipts were anchored. Not filtered and not anchored: a claim, not checked figures.",
      "received": "0",
      "requests": 4,
      "sent": "0",
      "since": 1793645209,
      "spent": "189",
      "tokens": 97
    },
    "holder": {
      "account": "0xB7D72C2Cdba221CE1b168c58d71A8BCaA199cE7c",
      "match": "owner-consent",
      "owner": "0xB7D72C2Cdba221CE1b168c58d71A8BCaA199cE7c"
    },
    "kind": "genesis",
    "posted": {
      "cadence": "weekly",
      "reason": "opening"
    },
    "prev": null,
    "provider": {
      "about": "https://raeto.cc/account-history",
      "name": "Raeto"
    },
    "seq": 1,
    "v": "raeto-account/v1",
    "window": {
      "from": 1793645209,
      "to": 1793654603
    }
  },
  "agentId": "20515",
  "agentRegistry": "eip155:4663:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
  "clientAddress": "eip155:4663:0x9d420a047EE7Cdc4FCbCbE891308306543Ee2DFf",
  "createdAt": "2026-11-02T21:23:23Z",
  "tag1": "account.statement",
  "tag2": "genesis",
  "value": "0",
  "valueDecimals": 6
}

13.2 A period statement

What one of rae's statements looks like, with illustrative figures. In this window it spent $4.18 on AI and tools, earned $1.50 from 2 outside payers, and closed at $7.32. Its prev is the genesis hash above; its feedbackHash would be `0x7416f6644e523a254857307668f28c447433ec1d720b5c9d78a542ba2873c6dd`.

{
  "account": {
    "activity": {
      "activeWeeks": 1,
      "cleanWeeks": 1,
      "weeksOnRecord": 1
    },
    "ai": {
      "amount": "3930000",
      "requests": 1840,
      "tokens": 2210000
    },
    "asset": "eip155:4663/erc20:0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
    "balance": {
      "average": "8640000",
      "closing": "7319811",
      "closingPromo": "0",
      "daysAtZero": 0,
      "minimum": "7319811",
      "opening": "9999811",
      "openingPromo": "0"
    },
    "chain": "eip155:4663",
    "decimals": 6,
    "enrolment": "consent",
    "flows": {
      "in": {
        "deposited": "0",
        "earned": "1500000",
        "funded": "0",
        "promo": "0",
        "returned": "0"
      },
      "out": {
        "fees": "0",
        "movedOut": "0",
        "paid": "0",
        "spent": "4180000",
        "withdrawn": "0"
      }
    },
    "holder": {
      "account": "0xB7D72C2Cdba221CE1b168c58d71A8BCaA199cE7c",
      "match": "owner-consent",
      "owner": "0xB7D72C2Cdba221CE1b168c58d71A8BCaA199cE7c"
    },
    "income": {
      "amount": "1500000",
      "d30": {
        "amount": "1500000",
        "payers": 2
      },
      "excluded": {
        "belowFloor": "0",
        "lender": "0",
        "overCap": "0",
        "promo": "0",
        "roundTrip": "0",
        "self": "0"
      },
      "payers": 2,
      "payments": 3
    },
    "kind": "period",
    "limitHits": 0,
    "moved": "4180000",
    "payments": {
      "amount": "0",
      "count": 0,
      "payees": 0
    },
    "posted": {
      "cadence": "weekly",
      "reason": "weekly"
    },
    "prev": "0xe08f51e2796370debf398865e242f2128ebcfd7b32fca79374906ae21e82c0b7",
    "provider": {
      "about": "https://raeto.cc/account-history",
      "name": "Raeto"
    },
    "receipts": {
      "anchored": true,
      "anchors": [
        {
          "epoch": 498515,
          "root": "0x1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c",
          "tx": "0x7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e7e"
        }
      ],
      "count": 1855,
      "first": 5,
      "head": "0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f",
      "hours": 41,
      "last": 1859,
      "root": "0x9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a",
      "unrecorded": {
        "amount": "0",
        "count": 0
      }
    },
    "refusals": 0,
    "routing": {
      "amount": "0",
      "decisions": 1790
    },
    "rung": {
      "level": 1,
      "name": "Active"
    },
    "selfSufficiency": 3588,
    "seq": 2,
    "tools": {
      "amount": "250000",
      "calls": 12
    },
    "v": "raeto-account/v1",
    "window": {
      "from": 1793654603,
      "to": 1794182400
    }
  },
  "agentId": "20515",
  "agentRegistry": "eip155:4663:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
  "clientAddress": "eip155:4663:0x9d420a047EE7Cdc4FCbCbE891308306543Ee2DFf",
  "createdAt": "2026-11-10T02:00:00Z",
  "tag1": "account.statement",
  "tag2": "period",
  "value": "4180000",
  "valueDecimals": 6
}