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

# Get live wallet statistics, balance, and spend limits

> The stats endpoint returns a wallet's current balance, per-transaction spend limit, period spend limit, amount spent this period, and remaining allowance.

The stats endpoint gives you a **pre-aggregated spend summary** for a wallet — perfect for building a dashboard overview card without aggregating transactions yourself. A single request returns the current balance, configured spend limits, and how much of the period allowance has already been consumed.

## Endpoints

### `GET /v1/wallets/:id/stats`

Returns aggregated statistics for a single wallet. No query parameters required.

**Example response**

```json theme={null}
{
  "balance": 1000000,
  "spendLimitPerTx": 500000,
  "spendLimitPeriod": 2000000,
  "spentThisPeriod": 500000,
  "remainingAllowance": 1500000
}
```

**Stats fields**

| Field                | Type   | Description                                                                                      |
| -------------------- | ------ | ------------------------------------------------------------------------------------------------ |
| `balance`            | number | Current wallet balance in **kobo** — divide by 100 to display in naira                           |
| `spendLimitPerTx`    | number | Maximum amount allowed per individual transaction, in kobo                                       |
| `spendLimitPeriod`   | number | Total spend cap for the current period, in kobo                                                  |
| `spentThisPeriod`    | number | Amount already spent in the current period, in kobo                                              |
| `remainingAllowance` | number | Remaining spendable amount in the current period (`spendLimitPeriod - spentThisPeriod`), in kobo |

### `GET /v1/wallets/:id/transactions`

Returns the most recent transactions for a wallet. Use the `limit` parameter to control how many records come back.

**Query parameters**

| Parameter | Type   | Default | Description                              |
| --------- | ------ | ------- | ---------------------------------------- |
| `limit`   | number | `20`    | Maximum number of transactions to return |

Each transaction record includes: `amount`, `merchant`, `decision`, `reason`, and `createdAt`. Pair this with the stats endpoint to populate both the summary card and the recent activity list in a single render cycle.

## React example: stats dashboard card

The component below fetches wallet stats, converts kobo to naira for display, and renders a period-spend progress bar alongside balance and limit information.

```tsx theme={null}
import { useEffect, useState } from "react";

interface WalletStats {
  balance: number;
  spendLimitPerTx: number;
  spendLimitPeriod: number;
  spentThisPeriod: number;
  remainingAllowance: number;
}

interface WalletStatsCardProps {
  walletId: string;
  apiKey: string;
}

function koboToNaira(kobo: number): string {
  return (kobo / 100).toLocaleString("en-NG", {
    style: "currency",
    currency: "NGN",
  });
}

export function WalletStatsCard({ walletId, apiKey }: WalletStatsCardProps) {
  const [stats, setStats] = useState<WalletStats | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const fetchStats = async () => {
      try {
        const res = await fetch(`/v1/wallets/${walletId}/stats`, {
          headers: { Authorization: `Bearer ${apiKey}` },
        });
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        const json: WalletStats = await res.json();
        setStats(json);
      } catch (err) {
        setError(err instanceof Error ? err.message : "Failed to load stats");
      }
    };

    fetchStats();
  }, [walletId, apiKey]);

  if (error)   return <p className="text-red-500">Error: {error}</p>;
  if (!stats)  return <p className="text-gray-400">Loading stats…</p>;

  const spendPercent = stats.spendLimitPeriod > 0
    ? Math.min((stats.spentThisPeriod / stats.spendLimitPeriod) * 100, 100)
    : 0;

  return (
    <div className="rounded-xl border border-gray-200 bg-white p-6 shadow-sm space-y-4">
      <div>
        <p className="text-sm text-gray-500">Current Balance</p>
        <p className="text-3xl font-bold text-gray-900">
          {koboToNaira(stats.balance)}
        </p>
      </div>

      <div>
        <div className="flex justify-between text-sm text-gray-600 mb-1">
          <span>Period Spend</span>
          <span>
            {koboToNaira(stats.spentThisPeriod)} / {koboToNaira(stats.spendLimitPeriod)}
          </span>
        </div>
        <div className="h-2 w-full rounded-full bg-gray-100">
          <div
            className="h-2 rounded-full bg-indigo-500 transition-all"
            style={{ width: `${spendPercent}%` }}
          />
        </div>
      </div>

      <div className="grid grid-cols-2 gap-4 pt-2">
        <div className="rounded-lg bg-blue-50 p-3 text-center">
          <p className="text-2xl font-semibold text-blue-700">
            {koboToNaira(stats.remainingAllowance)}
          </p>
          <p className="text-xs text-blue-600">Remaining Allowance</p>
        </div>
        <div className="rounded-lg bg-gray-50 p-3 text-center">
          <p className="text-2xl font-semibold text-gray-700">
            {koboToNaira(stats.spendLimitPerTx)}
          </p>
          <p className="text-xs text-gray-600">Per-Tx Limit</p>
        </div>
      </div>
    </div>
  );
}
```

## Polling for live updates

Axis uses **short-polling** rather than WebSockets. To keep your dashboard card current, set up a polling interval of 1–2 seconds on the stats endpoint. The `useEffect` hook below starts polling on mount and clears the interval when the component unmounts.

```tsx theme={null}
import { useEffect, useState, useRef } from "react";

function useWalletStats(walletId: string, apiKey: string, intervalMs = 1500) {
  const [stats, setStats] = useState<WalletStats | null>(null);
  const [error, setError] = useState<string | null>(null);
  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);

  useEffect(() => {
    const fetchStats = async () => {
      try {
        const res = await fetch(`/v1/wallets/${walletId}/stats`, {
          headers: { Authorization: `Bearer ${apiKey}` },
        });
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        const json: WalletStats = await res.json();
        setStats(json);
        setError(null);
      } catch (err) {
        setError(err instanceof Error ? err.message : "Unknown error");
      }
    };

    // Fetch immediately, then start polling
    fetchStats();
    intervalRef.current = setInterval(fetchStats, intervalMs);

    return () => {
      if (intervalRef.current) clearInterval(intervalRef.current);
    };
  }, [walletId, apiKey, intervalMs]);

  return { stats, error };
}

// Usage in a component:
export function LiveStatsCard({ walletId, apiKey }: { walletId: string; apiKey: string }) {
  const { stats, error } = useWalletStats(walletId, apiKey, 1500);

  if (error)  return <p className="text-red-500">Error: {error}</p>;
  if (!stats) return <p className="text-gray-400">Connecting…</p>;

  return <WalletStatsCard walletId={walletId} apiKey={apiKey} />;
}
```

The hook fetches once immediately, then re-fetches every `intervalMs` milliseconds. The cleanup function returned from `useEffect` cancels the interval when the component unmounts, preventing memory leaks and stale state updates.

<Tip>
  The stats endpoint gives you the current aggregated balance and spend figures, but if you need the full
  immutable history of every balance change — top-ups, debits, and refunds — see
  [Query the Axis ledger](/guides/ledger).
</Tip>
