> For AI agents: the documentation index is at https://sdk.nimbusprivacy.xyz/llms.txt, and every page is available as Markdown at its URL with .md appended.

# History (/helpers/history)

`readHistory` reads one page of the user's past payments, newest first. Like the balance, it reads
the device, not the network. It shows what the last [sync](https://sdk.nimbusprivacy.xyz/helpers/sync) took in.

In this guide, Alice's app lists her payments ten at a time. Bob paid her 5 USDC with a Private
Send, and the app shows it as received.

## Read a page

```ts
import { readHistory } from "@umbra/nimbus-solana-web";

const page = await readHistory(session, {}, { limit: 10 });

for (const item of page.items) {
  console.log(item.slot, item.received.length, item.spent.length);
}
```

Each item is one Solana transaction that touched Alice's private balance:

- **`slot`** and **`signature`** say where it landed.
- **`received`** lists what it paid into her private balance. Each entry's `note.amount` is the
  amount, and `note.mintIdentifier` names the token.
- **`spent`** lists what it took out of her private balance.
- **`record`** is `kept` for Alice's own transactions. It holds their public side, such as the
  wallet a deposit came from.
- **`others`** holds the public side of someone else's transaction that paid her, when there is
  one.

## Page through it

`limit` is the page size, from 1 to 100. It is 20 when you leave it out. Any other value throws a
`NimbusSdkError` with reason `misconfigured`.

When `page.next.kind` is `more`, older items remain. Pass `page.next.position` back as `after` to
read them:

```ts
import { readHistory } from "@umbra/nimbus-solana-web";

switch (page.next.kind) {
  case "more": {
    const older = await readHistory(
      session,
      {},
      { limit: 10, after: page.next.position },
    );
    console.log(older.items.length);
    break;
  }
  case "done":
    console.log("That was the oldest page.");
    break;
}
```

Pass the position back unchanged. Each page continues where the last one ended, without repeats.

## Deposit, withdrawal or Private Send

The SDK does not label items. A transaction's public side decides what it was. Money in from a
public wallet is a deposit. Money out to one is a withdrawal. A transaction with neither is a
Private Send.

The example app labels items this way, in `apps/nimbus-example/lib/activity.ts`:

```ts
type HistoryItem = HistoryPage["items"][number];

type Activity =
  | "deposit"
  | "withdrawal"
  | "deposit-and-withdrawal"
  | "private-send-sent"
  | "private-send-received"
  | "deposit-received";

function describeActivity(item: HistoryItem): Activity {
  if (item.record.kind === "kept") {
    const legs = item.record.judgment.row.legs;
    if (legs.kind === "known") {
      const paidIn = legs.inflows.length > 0;
      const paidOut = legs.outflows.length > 0;
      if (paidIn && !paidOut) return "deposit";
      if (paidOut && !paidIn) return "withdrawal";
      if (paidOut) return "deposit-and-withdrawal";
    }
    return item.spent.length === 0 ? "deposit" : "private-send-sent";
  }
  if (item.spent.length > 0) return "private-send-sent";
  if (item.others.kind === "legs" && item.others.legs.inflows.length > 0) {
    return "deposit-received";
  }
  return "private-send-received";
}
```

Alice's own transactions carry their `record`. Its `legs` are the public money in (`inflows`) and
out (`outflows`), each with an address, a token and an amount. When the network has not served them
yet, `legs.kind` is `missing`.

Bob's Private Send to Alice has no record of hers, so it reads as `private-send-received`. When Bob
deposits straight into Alice's private balance instead, `others` shows his wallet, and it reads as
`deposit-received`.

## Name the token

A received entry names its token by `note.mintIdentifier`, not by address.
[`findMintByIdentifier`](https://sdk.nimbusprivacy.xyz/reference/tokens#findmintbyidentifier) turns it back into the token's
address and decimals:

```ts
import { findMintByIdentifier } from "@umbra/nimbus-solana-web";

for (const item of page.items) {
  for (const { note } of item.received) {
    const token = findMintByIdentifier(sdk, {
      mintIdentifier: note.mintIdentifier,
    });
    console.log(note.amount, token?.mint, token?.decimals);
  }
}
```

It returns nothing for a token the SDK's preset does not list.

## What history can and cannot show

- **Only what this device has synced.** A payment appears after the next sync takes it in.
- **Not who sent a Private Send.** Bob's payment shows its amount and token. Nothing in it names
  Bob.
- **Not every slot yet.** `page.coverage` gives, for each pool, the slot the history is complete
  through. Do not show anything after that slot as "nothing happened".
- **Payments still on their way.** `page.pendingOwn` lists Alice's own payments that were sent but
  not yet taken in by a sync. It is the same on every page.

## Next

- [Tokens](https://sdk.nimbusprivacy.xyz/helpers/tokens): Name a token and format its amounts.
- [Sync](https://sdk.nimbusprivacy.xyz/helpers/sync): Bring the device up to date before you read.
- [What's public](https://sdk.nimbusprivacy.xyz/explainers/visibility): What each payment shows, and to whom.
- [API reference](https://sdk.nimbusprivacy.xyz/reference/reads#readhistory): readHistory: its options and what it returns.


Last updated 21 October 2026
