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.
| 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 wallet | 0xb0Cde84c3F65C2551F309C560d0Fd0A192522b59 |
| Asset | USDG 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168, 6 decimals |
Each statement is one giveFeedback entry from the writer, for the agent's ERC-8004 id:
| Field | Value |
|---|---|
agentId | the agent's ERC-8004 id |
value | money moved in the window, USDG base units (§5.1). 0 for genesis, paused and stopped statements |
valueDecimals | 6 |
tag1 | account.statement, or account.correction (§4.4) |
tag2 | the kind: genesis, period, paused or closed |
endpoint | empty |
feedbackURI | the file as a data: URI (§2) |
feedbackHash | keccak256 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.
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:
data:application/json;utf8, followed by the JSON text, used when the text is printable ASCII with no # or %;data:application/json;base64, followed by canonical base64 of the bytes, otherwise.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.
| Field | Meaning |
|---|---|
agentRegistry | eip155:4663: + the identity registry |
agentId | the agent's ERC-8004 id, a decimal string |
clientAddress | eip155:4663: + the writer |
createdAt | when the file was built, YYYY-MM-DDTHH:MM:SSZ |
value, valueDecimals | as in the entry: money moved, 6 decimals |
tag1, tag2 | as in the entry |
account | the statement (§3.2) |
account| Field | Meaning |
|---|---|
v | raeto-account/v1 |
provider | { name: "Raeto", about: "https://raeto.cc/account-history" } |
chain | eip155:4663 |
asset, decimals | eip155: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) |
scope | agent-usage on a fleet agent's statement only (§3.3) |
enrolment | auto or consent (§8) |
kind | genesis, period, paused or closed; equals tag2 |
seq | 1, 2, 3 … (§4) |
prev | feedbackHash 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) |
| figures | moved, ai, tools, routing, payments, income, balance, flows, selfSufficiency, activity, rung, limitHits, refusals (§5, §6) |
receipts | what the figures were computed from (§7) |
genesis, paused, closed, corrects | by kind (§4) |
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.
A record is one chain of statements per agent id, never per owner, so one owner's busy agent cannot prop up another.
seq starts at 1 and rises by one with no gaps. Each statement's prev is the feedbackHash of the one before.window.from is the previous window.to.genesisSeq 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.
periodThe 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:
daily (the default): the midnight after that day.weekly (the owner's choice, after the first 14 days): the Monday 00:00 UTC after that day, one statement for the week.biweekly: a week later, two weeks in one statement.posted.reason milestone) can end a weekly window early, so a new rung shows without waiting.posted.reason daily), so its first figures reach the chain within a day. Days with no activity post nothing.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.
paused and closedpaused: the record was unlinked, stopped or unpaid for a while, then carried on. It covers the gap with value 0, no figures and paused: { note }, so windows stay back to back.closed: the record ends, with closed: { reason }. unlinked: the identity no longer points to the account (it still carries the figures up to that point). stopped: Raeto ended it (a wrong match or a legal request); a stopped close carries no figures and value 0. Nothing follows a closed statement.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.
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.
movedThe 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.
| Field | Meaning |
|---|---|
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 |
payments{ count, amount, payees }: payments the agent made to others through Raeto Pay, and to how many payees.
income| Field | Meaning |
|---|---|
amount, payments, payers | verified 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 |
onchain | optional { amount, payments }: USDG paid straight to the agent's account or declared wallet from outside wallets, gross |
sources | optional, 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:
self.income.sources, id contracts ("From contracts").income.sources, with the source's id and label.income.amount and are always named in income.sources as raeto-rewards ("Raeto rewards"). They never count in d30 and never toward a rung: Earning and Self-sustaining read real money from real payers only.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.
flowsin: { earned, funded, deposited, promo, returned } and out: { spent, paid, movedOut, withdrawn, fees }: every way money entered and left the account in the window.
selfSufficiency, limitHits, refusals, activity| Field | Meaning |
|---|---|
selfSufficiency | 30-day verified income per 30-day real money out, in basis points (10000 = it pays its own way); null when nothing went out |
limitHits | requests refused because a limit (a daily cap, a budget) was hit |
refusals | requests refused for safety |
activity | { weeksOnRecord, activeWeeks, cleanWeeks }, in calendar weeks (Monday to Monday, UTC) |
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 }.
| Level | Name | What it takes |
|---|---|---|
| 0 | New | On record |
| 1 | Active | 8 active hours: UTC hours with at least $0.01 spent or paid (credits Raeto gave out count toward this rung) |
| 2 | Steady | Active, 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 |
| 3 | Earning | Steady, and verified income from at least 2 outside payers in the last 30 days |
| 4 | Self-sustaining | Earning, 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).
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:
| Field | Meaning |
|---|---|
count, first, last | how many receipts, and the first and last sequence numbers |
head | the hash of the last receipt |
hours, root | how many hours they span, and a Merkle root over those hours' roots |
anchored | true when every one of those hours was anchored before the statement was built |
anchors | the 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.
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:
match | enrolment | The link |
|---|---|---|
declared-wallet | auto | The identity's payment wallet (getAgentWallet) is the Raeto account, set apart from the owner. The chain proves it; no signature is needed. |
self-owned | auto | The account owns the identity, the payment wallet is the owner, and the account works as an agent (agent keys, no app sign-in). |
owner-consent | consent | The identity's owner signed a consent (below). |
partner-tag | consent | A 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.
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:
getLastIndex) was read back.feedbackHash, names this agent and writer, and its value is the moved it states.prev the previous hash, windows back to back, seq 1 a genesis, nothing after a closed.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.
Account history is meant to sit next to credit history. Some signals a reader may use:
selfSufficiency and income.d30 against money out. Rung 4 means 30-day income covers spending.balance.daysAtZero and balance.minimum. Steady requires no day at zero for 4 weeks.income.payers counts distinct outside payer clusters after the filters in §5.4, and excluded shows what was thrown out and why.activity.activeWeeks against weeksOnRecord, and the daily strip of active days.receipts.anchored, and the verifier passing.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.
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.
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.
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
}
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
}