> ## Documentation Index
> Fetch the complete documentation index at: https://docs.walley.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Reading Ledger State Through the Walley Ledger API Proxy

> Use the Walley dApp SDK ledgerApi method to forward read-only Canton JSON Ledger API requests through the wallet's authenticated proxy, with token handling and reconnect.

The `ledgerApi` method lets your dApp read ledger state on behalf of the connected user. It forwards a [Canton JSON Ledger API](https://docs.daml.com/) request through Walley's authenticated, read-only proxy and returns the upstream response. This implements the CIP-0103 `ledgerApi` provider method.

Unlike `prepareExecute`, `ledgerApi` does **not** open a popup and does **not** submit transactions — it's a read path that runs against the user's existing session token.

## Making a request

```ts theme={null}
const { response } = await provider.request({
  method: "ledgerApi",
  params: {
    requestMethod: "GET",
    resource: "/v2/state/active-contracts",
  },
});

const data = JSON.parse(response);
```

### Parameters

| Field           | Type               | Description                                                                                 |
| --------------- | ------------------ | ------------------------------------------------------------------------------------------- |
| `requestMethod` | string             | The HTTP method for the upstream Ledger API call, e.g. `"GET"` or `"POST"`.                 |
| `resource`      | string             | The Ledger API path, e.g. `/v2/state/active-contracts`. A leading slash is optional.        |
| `body`          | string  (optional) | A JSON string request body. When present, the proxy sends `Content-Type: application/json`. |

### Result

```ts theme={null}
// { response: string }
```

The `response` is the raw upstream body as a string. Parse it with `JSON.parse` for JSON endpoints.

### Example with a body

```ts theme={null}
const { response } = await provider.request({
  method: "ledgerApi",
  params: {
    requestMethod: "POST",
    resource: "/v2/state/active-contracts",
    body: JSON.stringify({ filter: { filtersByParty: {} }, verbose: false }),
  },
});
```

## Authentication & tokens

The proxy authenticates with the short-lived access token issued when the user connected. You don't manage the token directly — the SDK attaches it automatically — but you do need to handle expiry.

<Warning>
  Access tokens are short-lived. When a token has expired, a `ledgerApi` call throws `providerErrors.unauthorized`. Recover by calling `connect` again to refresh the session, then retry the request.
</Warning>

```ts theme={null}
import { providerErrors } from "@canton-network/core-rpc-errors";

async function readLedger(params) {
  try {
    return await provider.request({ method: "ledgerApi", params });
  } catch (err) {
    if (err.code === providerErrors.unauthorized().code) {
      await provider.request({ method: "connect" }); // refresh session
      return provider.request({ method: "ledgerApi", params });
    }
    throw err;
  }
}
```

## Errors

| Condition                                  | Error                                                         |
| ------------------------------------------ | ------------------------------------------------------------- |
| Not connected / no access token in session | `rpcErrors.internal`                                          |
| Session token expired (HTTP 401)           | `providerErrors.unauthorized` — reconnect and retry           |
| Transport failure reaching the proxy       | `rpcErrors.internal`                                          |
| Upstream returns a non-2xx status          | `rpcErrors.internal`, with the status and body in the message |

## When to use it

* **Use `ledgerApi`** to read contracts and ledger state — no popup, no fee.
* **Use [`prepareExecute` / `prepareExecuteAndWait`](/build/transactions)** to write — these require user approval in a popup.
