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

# Score

> GET /api/score — On-chain reputation score (0–100) for any wallet.

Returns the on-chain reputation score for a wallet, computed from its activity across 9 chains (Ethereum, Polygon, Arbitrum, Linea, Gnosis, Blast, Mantle, Berachain, Unichain), ENS identity, wallet age, and participation in reward programs.

The score is independent of any specific point system — it reflects the wallet's real on-chain history. Scores are cached for 30 days and refreshed daily by the scoring engine.

<Note>
  These are the chains the reputation score reads from. They are **not** where reward campaigns run. Rewards are deployed only on Somnia (Mainnet `5031`, Testnet `50312`) and Base (Mainnet `8453`, Sepolia `84532`). See [Supported chains](/api-reference/rewards#supported-chains).
</Note>

***

## GET /api/score

### Request

```bash theme={null}
GET https://api.rewards.so/score?address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045
Authorization: Bearer rw_your_api_key
```

### Query parameters

| Parameter | Type      | Required | Description                                                      |
| --------- | --------- | -------- | ---------------------------------------------------------------- |
| `address` | `string`  | Yes      | `0x` address (lowercase)                                         |
| `force`   | `boolean` | No       | Set to `true` to bypass the 30-day cache and fetch a fresh score |

### Response `200`

```json theme={null}
{
  "id": "uuid",
  "address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
  "finalScore": 78,
  "breakdown": {
    "age_factor": 0.95,
    "activity_factor": 0.87,
    "wallet_age_days": 1842,
    "total_txs": 312,
    "chains_active": 5,
    "last_tx_days_ago": 2
  },
  "bonuses": {
    "ens": 5,
    "multichain": 3,
    "rewards": 8
  },
  "penalties": {
    "recency": 0,
    "humanity": 0,
    "bot": 0
  },
  "dataSources": {
    "etherscan": true,
    "rewards": true
  },
  "cached": true,
  "cachedAt": "2026-04-21T08:00:00.000Z"
}
```

### Response fields

| Field                        | Type             | Description                                              |
| ---------------------------- | ---------------- | -------------------------------------------------------- |
| `finalScore`                 | `number`         | Reputation score from 0 to 100                           |
| `breakdown.age_factor`       | `number`         | Wallet age factor (0–1). Reaches 1.0 at 4+ years         |
| `breakdown.activity_factor`  | `number`         | On-chain activity factor (0–1). Reaches 1.0 at 2000+ txs |
| `breakdown.wallet_age_days`  | `number \| null` | Age of the wallet in days                                |
| `breakdown.total_txs`        | `number`         | Total transactions across all tracked chains             |
| `breakdown.chains_active`    | `number`         | Number of chains with at least one transaction           |
| `breakdown.last_tx_days_ago` | `number \| null` | Days since the last transaction                          |
| `bonuses.ens`                | `number`         | +5 if the wallet has a primary ENS or Base name          |
| `bonuses.multichain`         | `number`         | +3 if active on 3+ chains                                |
| `bonuses.rewards`            | `number`         | 0–10 based on percentile rank across reward programs     |
| `penalties.recency`          | `number`         | -5 if no activity in the last 180 days                   |
| `penalties.humanity`         | `number`         | 0–30 penalty for bot-like temporal patterns              |
| `penalties.bot`              | `number`         | 0–30 penalty for correlated blacklist signals            |
| `dataSources.etherscan`      | `boolean`        | Whether on-chain data was available                      |
| `dataSources.rewards`        | `boolean`        | Whether rewards program data was available               |
| `cached`                     | `boolean`        | `true` if the score was served from cache                |
| `cachedAt`                   | `string \| null` | ISO timestamp of when the score was cached               |

### Errors

| Status | Message                                       | Cause                                                  |
| ------ | --------------------------------------------- | ------------------------------------------------------ |
| `400`  | `Missing address`                             | No `address` query parameter                           |
| `401`  | `Missing API key`                             | No `Authorization` header                              |
| `401`  | `Invalid API key`                             | Key not found                                          |
| `403`  | `This API key does not have read permissions` | Key lacks `read` permission                            |
| `502`  | `Score service returned no score`             | Scoring backend returned a response but no score value |
| `503`  | `Score service unavailable`                   | Scoring backend unreachable and no cached score        |

***

## Scoring formula

```
rawScore = age_factor × activity_factor × 100
         + ens_bonus       (0 or +5)
         + multichain_bonus (0 or +3)
         + rewards_bonus    (0–10)
         - recency_penalty  (0 or -5)

finalScore = clamp(rawScore - bot_penalty - humanity_penalty, 0, 100)
```

A wallet with no activity gets a score near 0. A long-lived, multi-chain wallet with ENS and active reward program participation scores close to 100.

***

## Code examples

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.rewards.so/score?address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045" \
    -H "Authorization: Bearer rw_your_api_key"
  ```

  ```ts TypeScript theme={null}
  type WalletScore = {
    id: string;
    address: string;
    finalScore: number;
    breakdown: {
      age_factor: number;
      activity_factor: number;
      wallet_age_days: number | null;
      total_txs: number;
      chains_active: number;
      last_tx_days_ago: number | null;
    };
    bonuses: { ens: number; multichain: number; rewards: number };
    penalties: { recency: number; humanity: number; bot: number };
    dataSources: { etherscan: boolean; rewards: boolean };
    cached: boolean;
    cachedAt: string | null;
  };

  async function getWalletScore(address: string, force = false): Promise<WalletScore> {
    const url = new URL("https://api.rewards.so/score");
    url.searchParams.set("address", address);
    if (force) url.searchParams.set("force", "true");

    const res = await fetch(url.toString(), {
      headers: { Authorization: `Bearer ${process.env.REWARDS_API_KEY}` },
    });

    if (!res.ok) {
      const { error } = await res.json();
      throw new Error(`Score API error: ${error}`);
    }

    return res.json();
  }

  // Check if a wallet is trustworthy before granting access
  const score = await getWalletScore("0xd8da6bf26964af9d7eed9e03e53415d37aa96045");

  if (score.finalScore < 30) {
    console.log("Low-reputation wallet — consider additional verification");
  } else {
    console.log(`Score: ${score.finalScore}/100 — wallet age: ${score.breakdown.wallet_age_days}d`);
  }
  ```

  ```python Python theme={null}
  import os
  import requests

  def get_wallet_score(address: str, force: bool = False) -> dict:
      res = requests.get(
          "https://api.rewards.so/score",
          params={"address": address, **({"force": "true"} if force else {})},
          headers={"Authorization": f"Bearer {os.environ['REWARDS_API_KEY']}"},
      )
      res.raise_for_status()
      return res.json()

  score = get_wallet_score("0xd8da6bf26964af9d7eed9e03e53415d37aa96045")
  print(f"Score: {score['finalScore']}/100")
  print(f"Chains active: {score['breakdown']['chains_active']}")
  print(f"Bot penalty: {score['penalties']['bot']}")
  ```
</CodeGroup>
