> Documentation index: https://docs.squeekchain.com/llms.txt. Use it to find every page.

# API

> Read Squeekchain's measurement, settlement, issuance and Squeek data over HTTP: base URL, conventions, errors and every endpoint.

Web version: https://docs.squeekchain.com/developers/api/

## TL;DR

- `GET https://api.squeekchain.com/v1/…` serves Squeekchain's public data as JSON: no key, no wallet, nine read-only endpoints.
- Call it from a server, script or agent; browser calls from other websites are refused.
- A response can say `"status": "unavailable"` with HTTP 200; that is a valid answer, not an empty result or a zero balance.
- Use the API to display and explore. Read the contracts before preparing any transaction.

!!! warning "In active development"

    The Squeekchain API is in active development and is likely to change. Endpoints, fields and limits described here may change before a mainnet release. Validate responses against the published schemas and handle unknown fields.

## Base URL and access

```text
https://api.squeekchain.com
```

Every endpoint is a read-only `GET` under `/v1`. There is no API key and no request body. The API serves the Sepolia deployment listed under [Deployments](https://docs.squeekchain.com/developers.md#deployments).

Call it from a server, script or agent. Browsers can call it only from Squeekchain's own website; a request from any other site gets 403 `cors_origin_not_allowed`.

For monitoring, `GET /healthz` answers 200 while the API runs, and `GET /readyz` answers 200 only while its database is reachable.

## Conventions

These rules apply to every endpoint.

### Numbers and units

Large numbers (IDs, amounts, block numbers and work) are decimal strings. Parse them as `BigInt` or your language's big-integer type, never as floating point. Small values such as levels and speeds are plain JSON integers.

Field names carry their unit, as listed below.

<details markdown="1">
<summary>Field names and units</summary>

| Field | Meaning |
|---|---|
| `…BaseUnits`, `rewardPerBlock`, `supplyCap` | SQK with 18 decimals: `1000000000000000000` is 1 SQK |
| `weight`, `activeWeight`, `targetWeight`, `totalWeight`, `eligibleWeight` | [Power](https://docs.squeekchain.com/developers/mining.md#weightforlevel). `activeWeight` earns now; `targetWeight` applies once a pending change activates |
| `blockHeight`, `completedBlockHeight`, `closedThroughBlock`, `nextMergeBlock` | Squeek block numbers, not Ethereum blocks |
| `blockProgress`, `cumulativeBlockUnits` | Block units: 1,000,000,000 make one Squeek block |
| `workPerThousandBlocks` | Difficulty: work units needed for 1,000 Squeek blocks; see [SqueekCore](https://docs.squeekchain.com/developers/core.md#state) |
| `cumulativeWork`, `workUnits`, `cumulativeWorkUnits` | Wheel work units |
| `…Round`, `roundId` | 600-second rounds counted from the genesis timestamp |
| `ethereumBlockNumber`, `blockNumber`, `chain.…ThroughBlock` | Ethereum block numbers |
| `…At`, `blockTimestamp` | ISO 8601 times in UTC; on `/v1/core`, `blockTimestamp` and `genesisTimestamp` are Unix seconds |
| `date`, `utcDate` | `YYYY-MM-DD` |
| `…Bps` | Basis points, 0–10,000 |
| `…Milli` | Thousandths: `12500` is 12.5 |
| `rpmMilli`, `speedMmPerSecond`, `distanceMm` | Thousandths of a revolution per minute, millimetres per second, millimetres |

</details>

### Chain data

Everything read from Ethereum is 12 blocks behind the chain tip, so it is safe from short reorganizations. The `chain` object says which block a response was read at: compare `safeThroughBlock`, not `generatedAt`, to tell whether the chain has moved.

`release` and `identities` name the deployment and the contract addresses the data came from. Check them against [Deployments](https://docs.squeekchain.com/developers.md#deployments) before relying on a response.

### Availability

Most responses have a `status`. When it is `"unavailable"`, the response has a `reason` and no data, even though the HTTP status is 200. Show it as unknown, never as zero or empty.

### Caching

Responses come from a snapshot shared by all callers, so polling faster than it refreshes returns the same data. Three endpoints support conditional requests: send their `ETag` back in `If-None-Match` exactly as received, and an unchanged response comes back as 304 with no body.

| Endpoint | Refreshes | Conditional requests |
|---|---|---|
| [Pipeline status](https://docs.squeekchain.com/developers/api.md#status) | Every second, and on each new measurement | Yes |
| [Measurement statistics](https://docs.squeekchain.com/developers/api.md#measurement-stats) | When the data changes | Yes |
| [Settlement history](https://docs.squeekchain.com/developers/api.md#settlements) | Every 5 seconds, and at each range boundary | Yes |
| [SqueekCore state](https://docs.squeekchain.com/developers/api.md#core), [Issuance state](https://docs.squeekchain.com/developers/api.md#issuance-state) | Every 5 seconds | No |
| [Event feed](https://docs.squeekchain.com/developers/api.md#events), [owner](https://docs.squeekchain.com/developers/api.md#owner-squeeks) and [metadata](https://docs.squeekchain.com/developers/api.md#squeek-metadata) endpoints | Every request | No |

### Pagination

List endpoints return up to `limit` items (1–100) and a `nextCursor`. For the next page, repeat the request with `cursor` set to that value; `nextCursor` is `null` on the last page. Treat cursors as opaque. A cursor the API can't use gets 400 `invalid_cursor`, and an owner cursor invalidated by a chain reorganization gets 409 `cursor_invalidated`; either way, start again from the first page.

### Rate limits

Each IP address has a request budget per class of endpoint. Over budget, the API answers 429 with a `Retry-After` header: wait that many seconds before retrying.

| Class | Endpoints | Rate | Burst |
|---|---|---|---|
| `publicFast` | [Pipeline status](https://docs.squeekchain.com/developers/api.md#status), [SqueekCore state](https://docs.squeekchain.com/developers/api.md#core), [Issuance state](https://docs.squeekchain.com/developers/api.md#issuance-state) | 30 per second | 60 |
| `publicHeavy` | [Measurement statistics](https://docs.squeekchain.com/developers/api.md#measurement-stats), [Settlement history](https://docs.squeekchain.com/developers/api.md#settlements), [Event feed](https://docs.squeekchain.com/developers/api.md#events), [Owner's Squeeks](https://docs.squeekchain.com/developers/api.md#owner-squeeks), [Owner activity](https://docs.squeekchain.com/developers/api.md#owner-activity) | 5 per second | 20 |
| `metadata` | [Squeek metadata](https://docs.squeekchain.com/developers/api.md#squeek-metadata) | 20 per second | 40 |

### Headers

| Header | Use |
|---|---|
| `X-Request-Id` | On every response. Send your own (8–128 letters, digits, `.`, `_`, `:` or `-`) to trace a request, and quote it when reporting a problem |
| `ETag` | On cacheable responses; send it back as `If-None-Match`. See [Caching](https://docs.squeekchain.com/developers/api.md#caching) |
| `Retry-After` | On 429 and 503 responses: seconds to wait before retrying |
| `X-Squeek-Settlement-Source` | On [Settlement history](https://docs.squeekchain.com/developers/api.md#settlements): `live`, `durable-cache` or `unavailable` |

### Versioning and schemas

`/v1` versions the whole API. New endpoints, fields and optional parameters can appear within `/v1`, so ignore fields you don't use; removing or changing a field ships as `/v2`. Every response also has a `schemaVersion`.

Each endpoint links its complete JSON Schema (draft 2020-12). Enable the `date`, `date-time` and `uuid` formats; the `uint…-decimal` formats are unsigned decimal strings. The examples on this page are real responses with arrays shortened.

## Errors

Errors return an HTTP status and a body of the form `{"error": "<code>"}`. The codes below can come from any endpoint; endpoints list their own extra codes.

| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | `invalid_query` | A parameter is missing, malformed, repeated or unknown | Fix the request |
| 403 | `cors_origin_not_allowed` | A browser on another website called the API | Call it from your server |
| 404 | `not_found` | No such endpoint | Check the path |
| 429 | `rate_limited` | Over the rate limit | Wait `Retry-After` seconds |
| 503 | `database_busy`, `indexer_busy`, `database_unavailable` | The API is overloaded or a dependency is down | Wait `Retry-After` seconds, then retry with backoff |
| 504 | `request_timeout` | The request took too long | Retry with backoff |
| 500 | `internal_error` | Unexpected server failure | Retry a few times; report the `X-Request-Id` |

A response that doesn't parse or doesn't match its schema is an error, not empty data.

## API or contracts?

The API is an indexed, confirmation-delayed view for display, history and exploration. Anything that leads to a transaction reads the contracts, at a block you choose.

| You want to | Use |
|---|---|
| Show whether the wheel is running and how far the next block is | [`/v1/status`](https://docs.squeekchain.com/developers/api.md#status) |
| Chart wheel activity, records and settlement performance | [`/v1/measurement/stats`](https://docs.squeekchain.com/developers/api.md#measurement-stats) |
| Show settled work, block height and difficulty | [`/v1/core`](https://docs.squeekchain.com/developers/api.md#core); for an exact value at a block, [SqueekCore `state()`](https://docs.squeekchain.com/developers/core.md#state) |
| List settlements and SQK issued per period | [`/v1/settlements`](https://docs.squeekchain.com/developers/api.md#settlements); to rebuild history yourself, [Index events](https://docs.squeekchain.com/developers/index-events.md) |
| Show a feed of what happened | [`/v1/events`](https://docs.squeekchain.com/developers/api.md#events) |
| Show an owner's Squeeks and SQK | [`/v1/owners/{address}/squeeks`](https://docs.squeekchain.com/developers/api.md#owner-squeeks) |
| Prepare a claim or merge | The contracts: [`position`](https://docs.squeekchain.com/developers/mining.md#position), [`claimable`](https://docs.squeekchain.com/developers/mining.md#claimable) and [Build owner actions](https://docs.squeekchain.com/developers/owner-actions.md). Never take token IDs, amounts or eligibility from the API into a transaction |
| Show a Squeek's image and traits | [`/v1/squeeks/{tokenId}/metadata`](https://docs.squeekchain.com/developers/api.md#squeek-metadata); onchain, [`tokenURI`](https://docs.squeekchain.com/developers/nft.md#tokenuri) |

## Measurement and validation

What the WHEELY9000 measured, how the Oracle validated it, and how close the next Squeek block is.

### Pipeline status · GET /v1/status

The live state of the whole pipeline in one read: the latest accepted measurement, the block builder's projection, Oracle validation, the settlement queue and the device signer. Poll it to show whether the wheel is turning and how far the next block is.

The endpoint takes no parameters; any query parameter returns 400 `invalid_query`.

**Example request**

```sh
curl -i https://api.squeekchain.com/v1/status
```

**Response**

<details markdown="1">
<summary>Example response</summary>

```json
{
  "schemaVersion": 1,
  "installationId": "hamster-sepolia-core3-mining6-001",
  "revision": "YTgBydeEb9_TxJt9Z-Ke6LnZ4mAmm1TEmpUzWFB4Ys0",
  "generatedAt": "2026-10-15T00:56:11.129Z",
  "measurement": {
    "freshness": "online",
    "observedAt": "2026-10-15T00:56:09.341Z",
    "receivedAt": "2026-10-15T00:56:09.626Z",
    "staleAfterSeconds": 120,
    "counterEpoch": "fe146d83-582f-44cc-ae4f-372fa5e83920",
    "cumulativeWorkUnits": "29848",
    "provenance": "hardware",
    "coreStatus": "IDLE",
    "rpmMilli": 73330,
    "speedMmPerSecond": 1073,
    "distanceMm": 5727194
  },
  "builder": {
    "status": "available",
    "anchor": {
      "cumulativeWork": "29212",
      "cumulativeBlockUnits": "2614966878647",
      "blockHeight": "2614",
      "blockProgress": "966878647",
      "workPerThousandBlocks": "11676",
      "settledThroughRound": "295",
      "confirmedAt": "2026-10-15T00:41:12.000Z",
      "transactionHash": "0xe354794ba80cde1d2f75f0bcead87f652c2541fd5622ee46ef47b6f2ee78b274"
    },
    "queued": {"closedRoundCount": "1", "closedWorkUnits": "257", "openRoundWorkUnits": "379"},
    "projected": {
      "cumulativeWork": "29848",
      "cumulativeBlockUnits": "2669934363044",
      "blockHeight": "2669",
      "blockProgress": "934363044",
      "workPerThousandBlocks": "11432",
      "firstCompletedBlock": "2615",
      "lastCompletedBlock": "2669",
      "completedBlockCount": "55",
      "lifecycle": "optimistic"
    }
  },
  "oracle": {
    "state": "accepted",
    "reason": null,
    "latestAcceptedAt": "2026-10-15T00:56:09.626Z",
    "latestClosure": {
      "firstRound": "296",
      "lastRound": "296",
      "roundCount": "1",
      "acceptedAt": "2026-10-15T00:50:00.960Z"
    }
  },
  "settlementQueue": {
    "status": "available",
    "state": "ready",
    "settlementEnabled": true,
    "reporterEnvironmentEnabled": true,
    "buffered": {
      "firstRound": "296",
      "lastRound": "296",
      "roundCount": "1",
      "activeRoundCount": "1",
      "workUnits": "257"
    },
    "projected": {
      "cumulativeWork": "29469",
      "cumulativeBlockUnits": "2636977841305",
      "blockHeight": "2636",
      "blockProgress": "977841305",
      "workPerThousandBlocks": "11500",
      "firstCompletedBlock": "2615",
      "lastCompletedBlock": "2636",
      "completedBlockCount": "22",
      "lifecycle": "optimistic"
    },
    "incidentOpen": false,
    "blockedReason": null,
    "lastRun": {
      "startedAt": "2026-10-15T00:50:50.210Z",
      "finishedAt": "2026-10-15T00:50:50.707Z",
      "result": "failed"
    },
    "latestSubmission": {
      "submissionId": "eecbd361-33aa-43aa-984c-a38b4cf07cd6",
      "lifecycle": "confirmed",
      "previousSettledThroughRound": "294",
      "settledThroughRound": "295",
      "roundCount": "1",
      "activeRoundCount": "1",
      "expected": {
        "cumulativeWork": "29212",
        "cumulativeBlockUnits": "2614966878647",
        "blockHeight": "2614",
        "blockProgress": "966878647",
        "workPerThousandBlocks": "11676",
        "firstCompletedBlock": "2560",
        "lastCompletedBlock": "2614",
        "completedBlockCount": "55"
      },
      "transactionHash": "0xe354794ba80cde1d2f75f0bcead87f652c2541fd5622ee46ef47b6f2ee78b274",
      "createdAt": "2026-10-15T00:40:51.915Z",
      "submittedAt": "2026-10-15T00:40:51.915Z",
      "confirmedAt": "2026-10-15T00:45:32.542Z",
      "terminalAt": "2026-10-15T00:45:32.542Z",
      "changedAt": "2026-10-15T00:45:32.542Z",
      "outcomeCode": null
    }
  },
  "signer": {
    "kind": "trust-m",
    "algorithm": "ecdsa-p256-sha256",
    "keySlot": "0xE0F2",
    "enrolledAt": "2026-10-12T23:51:14.066Z",
    "lastVerifiedAt": "2026-10-15T00:56:09.626Z",
    "lastSignature": "tJG5ZDKdvX3cHC5rFeXu0rVj1aY2IXsJ/Dj1jMrtR5tI1wZiJUGxi7qMyLtl5lLbUphBGXBTA0+vJHhQzjPafA=="
  },
  "modules": [
    {
      "instanceId": "wheel",
      "moduleType": "wheel.counter",
      "driverId": "usb-rp2040-a3144e-lm393",
      "moduleVersion": "0.2.1",
      "schemaVersion": 1,
      "state": "ready",
      "observedAt": "2026-10-15T00:56:09.341611Z",
      "provenance": "hardware",
      "health": {"checkedAt": "2026-10-15T00:56:09.341611Z"},
      "data": {}
    }
  ]
}
```

</details>

| Field | Type | Description |
|---|---|---|
| `revision` | `string` | Opaque snapshot revision; the `ETag` is derived from it and from `modules` |
| `measurement` | `object` or `null` | Latest accepted device reading; `null` before the first |
| `measurement.freshness` | `string` | `online`, or `stale` once more than `staleAfterSeconds` (120) have passed since `receivedAt` |
| `measurement.observedAt` | `string` | When the device took the reading |
| `measurement.receivedAt` | `string` | When the API accepted it |
| `measurement.counterEpoch` | `string` | UUID of the device's counter epoch; `cumulativeWorkUnits` counts from its start |
| `measurement.cumulativeWorkUnits` | `string` | Work units counted in this counter epoch |
| `measurement.provenance` | `string` | `hardware`, `simulated`, `replay` or `derived` |
| `measurement.coreStatus` | `string` | Device state: `IDLE`, `ACTIVE` or `COUNTER_FAULT` |
| `measurement.rpmMilli` | `integer` | Wheel speed in thousandths of a revolution per minute |
| `measurement.speedMmPerSecond` | `integer` | Running speed in millimetres per second |
| `measurement.distanceMm` | `integer` | Distance the device reports for its current day, in millimetres |
| `builder.status` | `string` | `available`, or `unavailable` with `builder.reason` |
| `builder.anchor` | `object` | The settled frontier on SqueekCore: `settledThroughRound`, `cumulativeWork`, `blockHeight`, `blockProgress`, `workPerThousandBlocks`, `cumulativeBlockUnits`, and the confirming `transactionHash` and `confirmedAt` |
| `builder.queued` | `object` | Work not yet settled: `closedRoundCount`, `closedWorkUnits` and `openRoundWorkUnits` |
| `builder.projected` | `object` | `lifecycle: "optimistic"`: the frontier if all queued work settles, with `firstCompletedBlock`, `lastCompletedBlock` and `completedBlockCount` |
| `oracle.state` | `string` | `accepted`, `stale`, `blocked` or `unavailable`, with `oracle.reason` |
| `oracle.latestClosure` | `object` or `null` | The latest closed rounds the Oracle accepted: `firstRound`, `lastRound`, `roundCount`, `acceptedAt` |
| `settlementQueue.status` | `string` | `available`, or `unavailable` with `settlementQueue.reason` |
| `settlementQueue.state` | `string` | `disabled`, `empty`, `ready`, `preparing`, `submitted`, `retrying`, `blocked` or `stale` |
| `settlementQueue.buffered` | `object` | Closed rounds waiting to settle: `firstRound`, `lastRound`, `roundCount`, `activeRoundCount`, `workUnits` |
| `settlementQueue.projected` | `object` | The frontier once the buffered rounds settle; same fields as `builder.projected` |
| `settlementQueue.latestSubmission` | `object` or `null` | The latest settlement transaction: `lifecycle` (`preparing`, `submitted`, `retrying`, `confirmed`, `reverted`, `superseded`), round range, `expected` result, `transactionHash`, timestamps and `outcomeCode` |
| `signer` | `object` or `null` | The device's signing credential: `kind` (`trust-m`, `software-ecdsa` or `ed25519`), `algorithm`, `keySlot`, `enrolledAt`, `lastVerifiedAt`. May be absent |
| `modules[]` | `object` | The installation's sensor modules, as last reported: `instanceId`, `moduleType`, `driverId`, `moduleVersion`, `observedAt` and `provenance` |
| `modules[].state` | `string` | `disabled`, `starting`, `ready`, `degraded`, `faulted` or `stopped` |
| `modules[].health` | `object` | `checkedAt`, plus `code` and `message` when the module reports a problem |

[Complete response schema](https://docs.squeekchain.com/assets/api/status.json)

Projected values are optimistic. A projected completed block is not settled on Ethereum and has not issued SQK; settlement happens when the Reporter's batch confirms, and issuance when SqueekMining checkpoints it.

**Freshness**

A shared snapshot is recomputed at most once a second and right after each accepted measurement. Builder unavailable reasons: `no_measurement`, `counter_fault`, `counter_epoch_unapproved`, `round_projection_gap`, `oracle_head_unavailable`, `round_ineligible`. Queue unavailable reasons: `oracle_head_unavailable`, `round_projection_gap`, `round_ineligible`. A stale measurement alone doesn't make the builder unavailable.

### Measurement statistics · GET /v1/measurement/stats

Aggregates over the last 7 or 30 days: lifetime totals, daily and half-hourly activity, records, block production, round activity and settlement performance. Use it for charts and summaries; it's too heavy to poll.

**Query parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `range` | `string` | Yes | `7d` or `30d`. Exactly one `range`; no other parameter is accepted |

**Example request**

```sh
curl -i "https://api.squeekchain.com/v1/measurement/stats?range=7d"
```

**Response**

<details markdown="1">
<summary>Example response</summary>

```json
{
  "installationId": "hamster-sepolia-core3-mining6-001",
  "revision": "NVgZYvWK_8zjMiI9Tyhpt1wIySrwP2RSZILgqbhNtWQ",
  "generatedAt": "2026-10-15T00:56:10.810Z",
  "range": "7d",
  "timezone": "UTC",
  "window": {
    "startAt": "2026-10-08T12:00:00.000Z",
    "endAt": "2026-10-15T00:56:10.810Z",
    "dayCount": 7,
    "bucketSeconds": 1800,
    "roundSeconds": 600
  },
  "activity": {
    "provenance": "accepted_rounds",
    "coverage": {"expectedRoundCount": 941, "observedRoundCount": 296, "coverageBps": 3145, "complete": false},
    "summary": {
      "observedWorkUnits": "29469",
      "observedDistanceMm": "29757176",
      "activeDayCount": 3,
      "inactiveDayCount": 0,
      "averageWorkPerActiveDayMilli": "9823000",
      "medianWorkPerActiveDay": "8356",
      "averageDistancePerActiveDayMm": "9919058",
      "mostActiveDate": "2026-10-13",
      "mostActiveDateWorkUnits": "14969",
      "peakWindowStartMinuteUtc": 1410
    },
    "days": [
      {
        "date": "2026-10-14",
        "coverage": {"expectedRoundCount": 77, "observedRoundCount": 77, "coverageBps": 10000},
        "observedWorkUnits": "6144",
        "distanceMm": "5727194",
        "buckets": [
          {
            "startMinuteUtc": 0,
            "coverage": "complete",
            "observedRoundCount": 3,
            "workUnits": "1488"
          },
          {"startMinuteUtc": 30, "coverage": "partial", "observedRoundCount": 2, "workUnits": "897"}
        ]
      }
    ],
    "typicalDay": [
      {
        "startMinuteUtc": 0,
        "totalWorkUnits": "4370",
        "observedDayCount": 3,
        "meanWorkMilli": "1456666"
      },
      {
        "startMinuteUtc": 30,
        "totalWorkUnits": "2944",
        "observedDayCount": 2,
        "meanWorkMilli": "1472000"
      }
    ]
  },
  "records": {
    "mostWorkHalfHour": {"value": "1706", "occurredAt": "2026-10-13T23:30:00.000Z", "coverage": "complete"},
    "mostWorkUtcDay": {"value": "14969", "occurredAt": "2026-10-13T12:00:00.000Z", "coverage": "complete"},
    "maximumDailyDistanceMm": {"value": "13142782", "occurredAt": "2026-10-13T12:00:00.000Z", "coverage": "complete"},
    "peakObservedRpmMilli": {"value": "104281", "occurredAt": "2026-10-14T22:44:45.996Z", "coverage": "partial"},
    "peakObservedSpeedMmPerSecond": {"value": "1526", "occurredAt": "2026-10-14T22:44:45.996Z", "coverage": "partial"},
    "longestActiveWindowMinutes": {"value": "250", "occurredAt": "2026-10-13T22:00:00.000Z", "coverage": "complete"},
    "longestActiveDayStreak": {"value": "3", "occurredAt": "2026-10-12T12:00:00.000Z", "coverage": "partial"}
  },
  "blocks": {"status": "unavailable", "reason": "completion_boundaries_unavailable"},
  "rounds": {
    "observedCount": 296,
    "activeCount": 64,
    "zeroWorkCount": 232,
    "missingCount": 645,
    "activeRateBps": 2162,
    "averageActiveWorkMilli": "460453",
    "medianActiveWork": "479",
    "p90ActiveWork": "650",
    "mostActiveWork": "686"
  },
  "oracle": {"status": "unavailable", "reason": "projection_not_initialized"},
  "schemaVersion": 1,
  "lifetime": {
    "acceptedWorkUnits": "29469",
    "observedDistanceMm": "29757176",
    "activeDayCount": 3,
    "settledBlockCount": "2614",
    "settlementCount": "279",
    "coverageBps": 10000,
    "firstObservedAt": "2026-10-12T23:30:00.000Z",
    "settledWorkUnits": "29212"
  }
}
```

</details>

| Field | Type | Description |
|---|---|---|
| `revision` | `string` | Content revision; the `ETag` |
| `window` | `object` | `startAt`, `endAt`, `dayCount`, `bucketSeconds` (1800) and `roundSeconds` (600) |
| `lifetime` | `object` | Totals since the first observation: `acceptedWorkUnits`, `observedDistanceMm`, `activeDayCount`, `settledBlockCount`, `settlementCount`, `settledWorkUnits`, `coverageBps`, `firstObservedAt` |
| `activity.coverage` | `object` | Expected and observed rounds in the window, `coverageBps` and `complete` |
| `activity.summary` | `object` | Observed work and distance, active and inactive days, averages, median, the most active date and `peakWindowStartMinuteUtc` |
| `activity.days[]` | `object` | One entry per day: `date`, `coverage`, `observedWorkUnits`, `distanceMm` and 48 half-hour `buckets` |
| `activity.days[].buckets[]` | `object` | `startMinuteUtc`, `coverage` (`complete`, `partial`, `missing`, `future`), `observedRoundCount`, `workUnits` |
| `activity.typicalDay[]` | `object` | 48 half-hour slots averaged over the window: `startMinuteUtc`, `totalWorkUnits`, `observedDayCount`, `meanWorkMilli` |
| `records` | `object` | `mostWorkHalfHour`, `mostWorkUtcDay`, `maximumDailyDistanceMm`, `peakObservedRpmMilli`, `peakObservedSpeedMmPerSecond`, `longestActiveWindowMinutes`, `longestActiveDayStreak`: each `null` or a `value`, `occurredAt` and `coverage` |
| `blocks` | `object` | Available: blocks completed in the range and all time, per-day figures and completion times. Unavailable reasons: `completion_boundaries_unavailable`, `insufficient_history` |
| `rounds` | `object` | Observed, active, zero-work and missing rounds, `activeRateBps`, and active-round work statistics |
| `oracle` | `object` | Available: settlement submissions, confirmations, reverts and timings. Unavailable reasons: `projection_not_initialized`, `insufficient_history` |

[Complete response schema](https://docs.squeekchain.com/assets/api/measurement-stats.json)

Days run from 12:00 UTC to 12:00 UTC and are named by the date of their starting noon, matching the distance the device reports per day.

**Freshness**

Computed from accepted rounds and confirmed settlements. Send the `ETag` back in `If-None-Match` to get 304 while nothing has changed.

**Errors**

| Status | Code | Cause |
|---|---|---|
| 503 | `public_stats_rebuilding` | The statistics are being rebuilt; wait `Retry-After` and retry. Don't show an empty history |

## Settlement and events

What SqueekCore has settled on Ethereum, the history of settlements and issuance, and the event feed.

### SqueekCore state · GET /v1/core

SqueekCore's identity, configuration and settled state at the safe block, with its newest events. Use it to show settled work, block height and difficulty, and to check the API reads the deployment you expect.

The endpoint takes no parameters; any query parameter returns 400 `invalid_query`.

**Example request**

```sh
curl -i https://api.squeekchain.com/v1/core
```

**Response**

<details markdown="1">
<summary>Example response</summary>

```json
{
  "schemaVersion": 1,
  "installationId": "hamster-sepolia-core3-mining6-001",
  "status": "available",
  "chain": {
    "target": "sepolia",
    "chainId": "11155111",
    "confirmations": "12",
    "deploymentBlock": "11902282",
    "indexedThroughBlock": "11916986",
    "safeThroughBlock": "11916975"
  },
  "identities": {
    "core": "0x74665daeca35a2303e767e76a2ff1fb6f93e119f",
    "proxyAdmin": "0x05a9af6c3f6780dd58168f2e145cdd0d64564a5e",
    "proxyAdminOwner": "0x6b35ab6e96ef292e4fdd3f15a4e812f3ca291844",
    "operatorTimelock": "0x6b35ab6e96ef292e4fdd3f15a4e812f3ca291844",
    "operatorProposer": "0x83a8d3e5ed02e5201a996c3f03e017b6a6c19d31",
    "proxyImplementation": "0x0a71c86ab63a77675002a389fdf4d096a07b11e2",
    "proxyAdminSlot": "0x05a9af6c3f6780dd58168f2e145cdd0d64564a5e"
  },
  "configuration": {
    "streamId": "0xa0186b1a24b217f12f56c8574b492e286d00cd94bb5546cba45b048b19c60e44",
    "genesisTimestamp": "1791847800",
    "roundDuration": "600",
    "maxWorkPerRound": "10000",
    "maxRoundsPerBatch": "16",
    "guardian": "0x0e1b21ed2fc5fc48e221d3e863f09589cb490e73",
    "reporter": "0xa663b5c05eafa3e90bfbd3f7decdaaa3d41f5a75",
    "initialWorkPerThousandBlocks": "10875",
    "targetBlocksPerActiveRound": "40",
    "difficultySmoothingRounds": "30",
    "blockUnitsPerBlock": "1000000000"
  },
  "core": {
    "cumulativeWork": "29212",
    "cumulativeBlockUnits": "2614966878647",
    "blockHeight": "2614",
    "blockProgress": "966878647",
    "workPerThousandBlocks": "11676",
    "settledThroughRound": "295",
    "authorizationNonce": "280",
    "paused": false
  },
  "implementation": {
    "codeAddress": "0x0a71c86ab63a77675002a389fdf4d096a07b11e2",
    "codeVersion": "3",
    "storageLayoutDigest": "0x9a9c008e029460808209571703fbf2679785874e0e6d3232f16a864d12abcb20",
    "runtimeHash": "0xe8a5a5aa913141ddd8951cf9fcc1375044b541773e5b0bf8ee04a5c7ac2d194d"
  },
  "governance": {
    "operationId": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "operationKind": "None",
    "operationState": "None"
  },
  "source": {
    "eventName": "BatchSettled",
    "blockNumber": "11916912",
    "blockHash": "0x894b28afb201a9df4dcc19a7077deab5ad5b24f875e3a83d3acdda9778365be7",
    "blockTimestamp": "1792024872",
    "transactionHash": "0xe354794ba80cde1d2f75f0bcead87f652c2541fd5622ee46ef47b6f2ee78b274",
    "transactionIndex": "117",
    "logIndex": "434"
  },
  "events": [
    {
      "id": "179202487200000000111551110000000011916912000000000000011750000000000000434",
      "contractKind": "core",
      "contractAddress": "0x74665daeca35a2303e767e76a2ff1fb6f93e119f",
      "eventName": "BatchSettled",
      "blockNumber": "11916912",
      "blockHash": "0x894b28afb201a9df4dcc19a7077deab5ad5b24f875e3a83d3acdda9778365be7",
      "blockTimestamp": "1792024872",
      "transactionHash": "0xe354794ba80cde1d2f75f0bcead87f652c2541fd5622ee46ef47b6f2ee78b274",
      "transactionIndex": "117",
      "logIndex": "434",
      "arguments": [
        {
          "name": "digest",
          "value": "0x1c35b19677c08a83a7622bf1f7cd3849c57f646e702f4f1e146cd45b6856a1d0"
        },
        {"name": "reporter", "value": "0xa663b5c05eafa3e90bfbd3f7decdaaa3d41f5a75"},
        {"name": "settledThroughRound", "value": "295"}
      ]
    },
    {
      "id": "179202487200000000111551110000000011916912000000000000011750000000000000433",
      "contractKind": "core",
      "contractAddress": "0x74665daeca35a2303e767e76a2ff1fb6f93e119f",
      "eventName": "RoundRecorded",
      "blockNumber": "11916912",
      "blockHash": "0x894b28afb201a9df4dcc19a7077deab5ad5b24f875e3a83d3acdda9778365be7",
      "blockTimestamp": "1792024872",
      "transactionHash": "0xe354794ba80cde1d2f75f0bcead87f652c2541fd5622ee46ef47b6f2ee78b274",
      "transactionIndex": "117",
      "logIndex": "433",
      "arguments": [
        {"name": "roundId", "value": "295"},
        {"name": "work", "value": "640"},
        {"name": "cumulativeWork", "value": "29212"}
      ]
    }
  ]
}
```

</details>

| Field | Type | Description |
|---|---|---|
| `status` | `string` | `available`, or `unavailable` with a `reason` |
| `identities.core` | `string` | The SqueekCore proxy address |
| `identities.proxyImplementation` | `string` | The implementation the proxy runs |
| `identities.proxyAdmin`, `identities.proxyAdminOwner` | `string` | The ProxyAdmin and its owner, the governance timelock |
| `identities.operatorTimelock`, `identities.operatorProposer` | `string` | The governance timelock and the account that proposes its operations |
| `configuration` | `object` | Launch configuration: `streamId`, `genesisTimestamp`, `roundDuration`, `maxWorkPerRound`, `maxRoundsPerBatch`, `guardian`, `reporter`, `initialWorkPerThousandBlocks`, `targetBlocksPerActiveRound`, `difficultySmoothingRounds`, `blockUnitsPerBlock` |
| `core.settledThroughRound` | `string` | The last settled round |
| `core.cumulativeWork` | `string` | All settled work units |
| `core.blockHeight` | `string` | Completed Squeek blocks |
| `core.blockProgress` | `string` | Block units into the next block, out of 1,000,000,000 |
| `core.workPerThousandBlocks` | `string` | Current difficulty |
| `core.cumulativeBlockUnits` | `string` | All block units earned |
| `core.paused` | `boolean` | Whether the Guardian has paused settlement |
| `implementation` | `object` | The running code: `codeAddress`, `codeVersion`, `storageLayoutDigest`, `runtimeHash` |
| `governance` | `object` | The latest timelock operation on the proxy: `operationId`, `operationKind`, `operationState` |
| `source` | `object` | The event the state was last read from: `eventName`, block, transaction and log position |
| `events[]` | `object` | Up to 25 newest events from SqueekCore, its proxy, ProxyAdmin and timelock: `id`, `contractKind`, `contractAddress`, `eventName`, block, transaction and log position, and `arguments` as name/value pairs |

[Complete response schema](https://docs.squeekchain.com/assets/api/core.json)

Compare `identities` and `implementation` with [Deployments](https://docs.squeekchain.com/developers.md#deployments); stop if they differ.

**Freshness**

Read at `chain.safeThroughBlock` and shared for up to 5 seconds. Unavailable reasons: `indexer_disabled`, `not_yet_safe` (the indexer hasn't reached 12 confirmations past the deployment), `indexer_unavailable`, `indexer_mismatch` (the indexer reports a different deployment).

### Settlement history · GET /v1/settlements

Settlement totals and the most recent settlements for a time range, with SQK issuance by round. Use it for settlement and issuance charts.

**Query parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `range` | `string` | No | `now` (default), `24h`, `7d` or `30d`. At most one `range`; no other parameter is accepted |

**Example request**

```sh
curl -i "https://api.squeekchain.com/v1/settlements?range=24h"
```

**Response**

<details markdown="1">
<summary>Example response, range=24h</summary>

```json
{
  "schemaVersion": 1,
  "installationId": "hamster-sepolia-core3-mining6-001",
  "status": "available",
  "range": "24h",
  "generatedAt": "2026-10-15T00:56:09.168Z",
  "chain": {
    "target": "sepolia",
    "chainId": "11155111",
    "confirmations": "12",
    "deploymentBlock": "11902282",
    "indexedThroughBlock": "11916986",
    "safeThroughBlock": "11916975"
  },
  "window": {
    "startAt": "2026-10-14T01:00:00.000Z",
    "endAt": "2026-10-15T01:00:00.000Z",
    "bucketSeconds": 3600
  },
  "summary": {
    "settlementCount": "136",
    "activeRoundCount": "27",
    "workAdded": "12429",
    "completedBlockCount": "1093",
    "archivedSettlementCount": "124"
  },
  "recentSettlements": [
    {
      "transactionHash": "0xe354794ba80cde1d2f75f0bcead87f652c2541fd5622ee46ef47b6f2ee78b274",
      "previousSettledThroughRound": "294",
      "settledThroughRound": "295",
      "activeRoundCount": "1",
      "workAdded": "640",
      "cumulativeWork": "29212",
      "cumulativeBlockUnits": "2614966878647",
      "firstCompletedBlock": "2560",
      "lastCompletedBlock": "2614",
      "completedBlockCount": "55",
      "blockHeight": "2614",
      "ethereumBlockNumber": "11916912",
      "blockTimestamp": "2026-10-15T00:41:12.000Z",
      "logIndex": "434",
      "confirmationStatus": "safe",
      "sqkMintedBaseUnits": "308000000000000000000000"
    }
  ],
  "buckets": [
    {
      "startAt": "2026-10-14T01:00:00.000Z",
      "endAt": "2026-10-14T02:00:00.000Z",
      "settlementCount": "5",
      "activeRoundCount": "6",
      "workAdded": "2665",
      "completedBlockCount": "230",
      "sqkMintedBaseUnits": "1394400000000000000000000"
    },
    {
      "startAt": "2026-10-14T02:00:00.000Z",
      "endAt": "2026-10-14T03:00:00.000Z",
      "settlementCount": "6",
      "activeRoundCount": "2",
      "workAdded": "1001",
      "completedBlockCount": "87",
      "sqkMintedBaseUnits": "716800000000000000000000"
    }
  ],
  "mining": {
    "status": "available",
    "economy": {
      "releaseId": "squeeks-sepolia-core3-mining6-001",
      "mining": "0x3bee588fc20de788bac17d33b41da7346cb27ec4",
      "token": "0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76",
      "symbol": "SQK",
      "decimals": 18
    },
    "rewardPerBlock": "5600000000000000000000",
    "supplyCap": "2100000000000000000000000000",
    "totalMintedBaseUnits": "13624800000000000000000000",
    "unmintedCapacityBaseUnits": "2086375200000000000000000000",
    "processedThroughRound": "295",
    "rangeMintedBaseUnits": "6456800000000000000000000",
    "rangeCheckpointCount": "125",
    "nextRound": {
      "state": "accruing",
      "round": "296",
      "countedThroughRound": "295",
      "startsAt": "2026-10-15T00:40:00.000Z",
      "endsAt": "2026-10-15T00:50:00.000Z",
      "previousCumulativeBlockUnits": "2614966878647",
      "cumulativeBlockUnits": "2614966878647",
      "completedBlockCount": "0",
      "eligibleWeight": "100000",
      "amountBaseUnits": "0"
    },
    "recentCheckpoints": [
      {
        "afterRound": "294",
        "throughRound": "295",
        "completedBlockCount": "55",
        "cumulativeWork": "29212",
        "cumulativeBlockUnits": "2614966878647",
        "eligibleWeight": "100000",
        "amountBaseUnits": "308000000000000000000000",
        "totalMintedBaseUnits": "13624800000000000000000000",
        "transactionHash": "0x73380faf2c7c14f93af8c99f1d42d9f5d0ea32dddc18a606db5c735e550bbb65",
        "ethereumBlockNumber": "11916936",
        "blockTimestamp": "2026-10-15T00:46:00.000Z",
        "logIndex": "758",
        "confirmationStatus": "safe"
      }
    ]
  },
  "previousPeriod": {
    "startAt": "2026-10-13T01:00:00.000Z",
    "endAt": "2026-10-14T00:56:09.000Z",
    "sqkMintedBaseUnits": "6540800000000000000000000"
  }
}
```

</details>

<details markdown="1">
<summary>Example response, range=now</summary>

```json
{
  "schemaVersion": 1,
  "installationId": "hamster-sepolia-core3-mining6-001",
  "status": "available",
  "range": "now",
  "generatedAt": "2026-10-15T00:56:10.041Z",
  "chain": {
    "target": "sepolia",
    "chainId": "11155111",
    "confirmations": "12",
    "deploymentBlock": "11902282",
    "indexedThroughBlock": "11916986",
    "safeThroughBlock": "11916975"
  },
  "window": null,
  "summary": {
    "settlementCount": "279",
    "activeRoundCount": "63",
    "workAdded": "29212",
    "completedBlockCount": "2614",
    "archivedSettlementCount": "267"
  },
  "recentSettlements": [
    {
      "transactionHash": "0xe354794ba80cde1d2f75f0bcead87f652c2541fd5622ee46ef47b6f2ee78b274",
      "previousSettledThroughRound": "294",
      "settledThroughRound": "295",
      "activeRoundCount": "1",
      "workAdded": "640",
      "cumulativeWork": "29212",
      "cumulativeBlockUnits": "2614966878647",
      "firstCompletedBlock": "2560",
      "lastCompletedBlock": "2614",
      "completedBlockCount": "55",
      "blockHeight": "2614",
      "ethereumBlockNumber": "11916912",
      "blockTimestamp": "2026-10-15T00:41:12.000Z",
      "logIndex": "434",
      "confirmationStatus": "safe",
      "sqkMintedBaseUnits": "308000000000000000000000"
    }
  ],
  "buckets": [],
  "mining": {
    "status": "available",
    "economy": {
      "releaseId": "squeeks-sepolia-core3-mining6-001",
      "mining": "0x3bee588fc20de788bac17d33b41da7346cb27ec4",
      "token": "0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76",
      "symbol": "SQK",
      "decimals": 18
    },
    "rewardPerBlock": "5600000000000000000000",
    "supplyCap": "2100000000000000000000000000",
    "totalMintedBaseUnits": "13624800000000000000000000",
    "unmintedCapacityBaseUnits": "2086375200000000000000000000",
    "processedThroughRound": "295",
    "rangeMintedBaseUnits": "13624800000000000000000000",
    "rangeCheckpointCount": "263",
    "nextRound": {
      "state": "accruing",
      "round": "296",
      "countedThroughRound": "295",
      "startsAt": "2026-10-15T00:40:00.000Z",
      "endsAt": "2026-10-15T00:50:00.000Z",
      "previousCumulativeBlockUnits": "2614966878647",
      "cumulativeBlockUnits": "2614966878647",
      "completedBlockCount": "0",
      "eligibleWeight": "100000",
      "amountBaseUnits": "0"
    },
    "recentCheckpoints": [
      {
        "afterRound": "294",
        "throughRound": "295",
        "completedBlockCount": "55",
        "cumulativeWork": "29212",
        "cumulativeBlockUnits": "2614966878647",
        "eligibleWeight": "100000",
        "amountBaseUnits": "308000000000000000000000",
        "totalMintedBaseUnits": "13624800000000000000000000",
        "transactionHash": "0x73380faf2c7c14f93af8c99f1d42d9f5d0ea32dddc18a606db5c735e550bbb65",
        "ethereumBlockNumber": "11916936",
        "blockTimestamp": "2026-10-15T00:46:00.000Z",
        "logIndex": "758",
        "confirmationStatus": "safe"
      }
    ]
  },
  "recentRounds": [
    {"roundId": "254", "endAt": "2026-10-14T17:50:00.000Z", "sqkMintedBaseUnits": "0"},
    {"roundId": "255", "endAt": "2026-10-14T18:00:00.000Z", "sqkMintedBaseUnits": "0"}
  ]
}
```

</details>

| Field | Type | Description |
|---|---|---|
| `range` | `string` | The requested range |
| `window` | `object` or `null` | `startAt`, `endAt` and `bucketSeconds`; `null` for `now` |
| `summary` | `object` | `settlementCount`, `activeRoundCount`, `workAdded`, `completedBlockCount` and `archivedSettlementCount` for the range |
| `recentSettlements[]` | `object` | Up to 10 newest settlements that completed blocks (within the window, for ranged requests); settlements that completed none are counted in `summary` and `buckets` but never listed. Each has its round range, `activeRoundCount`, `workAdded`, `cumulativeWork`, completed blocks, `blockHeight`, `cumulativeBlockUnits`, the Ethereum `transactionHash`, `ethereumBlockNumber`, `blockTimestamp` and `logIndex`, and `sqkMintedBaseUnits`, the SQK its blocks minted, once `mining.processedThroughRound` reaches its `settledThroughRound` |
| `buckets[]` | `object` | Per-period totals: 24 hourly buckets for `24h`, 28 six-hour buckets for `7d`, 30 daily buckets for `30d`, none for `now`; each with `sqkMintedBaseUnits` when issuance is available |
| `mining.status` | `string` | `available`, or `unavailable` with `not_configured` or `not_yet_safe` |
| `mining.totalMintedBaseUnits`, `mining.unmintedCapacityBaseUnits` | `string` | SQK issued so far and the capacity left under the supply cap |
| `mining.rangeMintedBaseUnits`, `mining.rangeCheckpointCount` | `string` | SQK issued and checkpoints run in the range |
| `mining.processedThroughRound` | `string` | The last round SqueekMining has funded |
| `mining.nextRound` | `object` | The next round to fund: `state` (`accruing` or `ready`), `round`, its time span, the blocks it completes, `eligibleWeight` and `amountBaseUnits` |
| `mining.recentCheckpoints[]` | `object` | Up to 12 newest checkpoints: round span, blocks completed, `eligibleWeight`, `amountBaseUnits`, `totalMintedBaseUnits`, transaction and block |
| `recentRounds[]` | `object` | `now` only: up to 42 recent rounds with `roundId`, `endAt` and `sqkMintedBaseUnits` |
| `previousPeriod` | `object` | Ranged only, when available: SQK issued in the period before the window |

[Complete response schema](https://docs.squeekchain.com/assets/api/settlements.json)

Settlements and issuance are separate steps. A settlement records work on SqueekCore; SQK is issued later, per round, when SqueekMining checkpoints. Never attribute SQK to a single settlement.

**Freshness**

Read at the safe block and shared for up to 5 seconds. The `24h` window ends at the next full hour; the `7d` and `30d` windows end at the next 12:00 UTC, so buckets shift on those boundaries even without new events. The response header `X-Squeek-Settlement-Source` is `live`, `durable-cache` (the indexer is behind or unavailable and the last good snapshot is served) or `unavailable`. Unavailable reasons: `indexer_disabled`, `not_yet_safe`, `indexer_unavailable`, `indexer_mismatch`.

### Event feed · GET /v1/events

The newest-first feed of what happened: settlements and checkpoints, mints, merges and claims, and wheel milestones. Use it for an activity feed.

**Query parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `category` | `string` | No | `all` (default), `protocol`, `players` or `measurement` |
| `limit` | `integer` | No | 1–100; default 40 |
| `cursor` | `string` | No | `nextCursor` from the previous page, with the same `category` |

**Example request**

```sh
curl -i "https://api.squeekchain.com/v1/events?category=all&limit=20"
```

**Response**

<details markdown="1">
<summary>Example response</summary>

```json
{
  "schemaVersion": 1,
  "installationId": "hamster-sepolia-core3-mining6-001",
  "status": "available",
  "generatedAt": "2026-10-15T00:57:41.699Z",
  "catalogVersion": "public-activity-v2",
  "chain": {
    "target": "sepolia",
    "chainId": "11155111",
    "confirmations": "12",
    "deploymentBlock": "11902282",
    "economyDeploymentBlock": "11902290",
    "indexedThroughBlock": "11916994",
    "safeThroughBlock": "11916983",
    "safeBlockHash": "0x3af7c3393f01379493be3e10b29649f1ee6e7026b4f880821546ef4fe1e43714",
    "safeBlockTimestamp": "2026-10-15T00:55:24.000Z"
  },
  "release": {
    "id": "squeeks-sepolia-core3-mining6-001",
    "protocolRevision": "mining-6",
    "rewardModelRevision": "q128-round-fixed-1"
  },
  "identities": {
    "core": "0x74665daeca35a2303e767e76a2ff1fb6f93e119f",
    "mining": "0x3bee588fc20de788bac17d33b41da7346cb27ec4",
    "token": "0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76",
    "collection": "0x0eaf3e0d40a0a8e5a6ac030b2459e9fb0b7905c6",
    "miningImplementation": "0x08890b360c65fd878344bf6e23d1c36358433b4e",
    "miningImplementationVersion": "6",
    "miningStorageLayoutDigest": "0xace564e9c052f30122779a32fdf3333ebce7cc708eae9c01cb7875b4f6ad37a6"
  },
  "nextCursor": "eyJ2IjoxLCJrIjoicGEiLCJjIjoiYWxsIiwicyI6IjExOTE2OTgzIiwiYiI6IjExOTE2MTA5IiwidCI6IjEyNCIsImwiOiIyNDYiLCJvIjoiMjAyNi0xMC0xNFQyMjozOTozMC45MjNaIiwiciI6IjQyMzciLCJlIjoibWVhc3VyZW1lbnQ6aGFtc3Rlci1zZXBvbGlhLWNvcmUzLW1pbmluZzYtMDAxOmhhbXN0ZXItc3BlZWQtcmVjb3JkLTE6bWVhc3VyZW1lbnQuc3BlZWRfcmVjb3JkOjEzMjcifQ",
  "category": "all",
  "activeEventTypes": [
    "system.settlement_completed",
    "system.mining_checkpointed",
    "player.squeek_minted",
    "player.squeeks_merged",
    "player.rewards_claimed",
    "measurement.distance_milestone",
    "measurement.daily_distance_milestone",
    "measurement.speed_milestone",
    "measurement.speed_record",
    "measurement.distance_streak"
  ],
  "events": [
    {
      "id": "chain:11155111:0x3bee588fc20de788bac17d33b41da7346cb27ec4:0x73380faf2c7c14f93af8c99f1d42d9f5d0ea32dddc18a606db5c735e550bbb65:758:system.mining_checkpointed",
      "eventVersion": 2,
      "occurredAt": "2026-10-15T00:46:00.000Z",
      "recordedAt": "2026-10-15T00:46:00.000Z",
      "source": {
        "kind": "chain",
        "chainId": "11155111",
        "target": "sepolia",
        "releaseId": "squeeks-sepolia-core3-mining6-001",
        "contractAddress": "0x3bee588fc20de788bac17d33b41da7346cb27ec4",
        "blockNumber": "11916936",
        "blockHash": "0x275493b9fee9de376b03eece067362aacdc9a8006ed0c31c91ec8264e805e668",
        "transactionHash": "0x73380faf2c7c14f93af8c99f1d42d9f5d0ea32dddc18a606db5c735e550bbb65",
        "transactionIndex": "144",
        "logIndex": "758",
        "confirmationStatus": "safe"
      },
      "type": "system.mining_checkpointed",
      "payload": {
        "afterRound": "294",
        "throughRound": "295",
        "completedBlockCount": "55",
        "cumulativeWork": "29212",
        "cumulativeBlockUnits": "2614966878647",
        "amountBaseUnits": "308000000000000000000000",
        "asset": {"address": "0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76", "symbol": "SQK", "decimals": 18}
      }
    },
    {
      "id": "measurement:hamster-sepolia-core3-mining6-001:hamster-distance-streak-1:measurement.distance_streak:2026-10-14",
      "eventVersion": 1,
      "occurredAt": "2026-10-15T00:36:58.351Z",
      "recordedAt": "2026-10-15T00:36:58.627Z",
      "source": {
        "kind": "measurement",
        "installationId": "hamster-sepolia-core3-mining6-001",
        "receiptCursor": "5285",
        "telemetryId": "01a13cfd-a56f-7916-99a2-b18348ee2f98",
        "observedAt": "2026-10-15T00:36:58.351Z",
        "receivedAt": "2026-10-15T00:36:58.627Z",
        "policyVersion": "hamster-distance-streak-1",
        "disposition": "accepted"
      },
      "type": "measurement.distance_streak",
      "payload": {"days": 3, "minimumDailyDistanceMm": "5000000", "endingUtcDate": "2026-10-14"}
    }
  ]
}
```

</details>

| Field | Type | Description |
|---|---|---|
| `category` | `string` | The requested category |
| `activeEventTypes` | `string[]` | Event types this feed can contain |
| `events[].id` | `string` | Stable, unique event ID; use it to deduplicate |
| `events[].type` | `string` | One of the types below |
| `events[].occurredAt` | `string` | When it happened: the block time, or the measurement time |
| `events[].recordedAt` | `string` | When Squeekchain recorded it |
| `events[].source` | `object` | `kind: "chain"` with the contract, block, transaction and log position (always `confirmationStatus: "safe"`); or `kind: "measurement"` with the installation, telemetry ID and times |
| `events[].payload` | `object` | Type-specific values, below |
| `nextCursor` | `string` or `null` | The next page; `null` at the end |

| Type | Category | Payload |
|---|---|---|
| `system.settlement_completed` | `protocol` | Round range, `activeRoundCount`, `workAdded`, completed blocks, `cumulativeWork`, `blockHeight`, `cumulativeBlockUnits` |
| `system.mining_checkpointed` | `protocol` | `afterRound`, `throughRound`, `completedBlockCount`, `amountBaseUnits`, `asset`, `cumulativeWork`, `cumulativeBlockUnits` |
| `player.squeek_minted` | `players` | `owner`, `tokenId`, `weight`, `nextMergeBlock`, `firstRound` |
| `player.squeeks_merged` | `players` | `owner`, `survivorTokenId`, `donorTokenId`, `level`, `nextMergeBlock`, `effectiveRound` |
| `player.rewards_claimed` | `players` | `owner`, `tokenIds`, `amountBaseUnits`, `asset` |
| `measurement.distance_milestone` | `measurement` | `thresholdDistanceMm`, `observedLifetimeDistanceMm` at 1, 3, 5, 10, 15, 20, 30 … 100 km, then every 50 km |
| `measurement.daily_distance_milestone` | `measurement` | `thresholdDistanceMm`, `observedDayDistanceMm`, `utcDate` at 1, 3, 5, 10 and 15 km in a day |
| `measurement.speed_milestone` | `measurement` | `thresholdSpeedMmPerSecond`, `observedSpeedMmPerSecond` at 2, 3, 6 and 10 km/h |
| `measurement.speed_record` | `measurement` | `previousRecordMmPerSecond`, `recordMmPerSecond`, `observedSpeedMmPerSecond`; a new top speed at least 0.2 km/h above the last |
| `measurement.distance_streak` | `measurement` | `days`, `minimumDailyDistanceMm`, `endingUtcDate`: 5 km a day on consecutive days, from day two |

[Complete response schema](https://docs.squeekchain.com/assets/api/events.json)

The schema also lists `measurement.rpm_record`, which this endpoint never returns. Days for measurement events run from 12:00 UTC to 12:00 UTC.

**Freshness**

Chain events appear once they have 12 confirmations; measurement events once the measurement is accepted. Unavailable reasons: `indexer_disabled`, `not_yet_safe`, `indexer_unavailable`, `indexer_mismatch`, `source_disabled`.

**Errors**

| Status | Code | Cause |
|---|---|---|
| 400 | `invalid_cursor` | The cursor can't be decoded or was issued for another category; start again from the first page |
| 400 | `invalid_query` | Also returned for a cursor containing characters other than `A–Z a–z 0–9 _ -` |

## Issuance and Squeeks

SQK issuance and supply, each owner's Squeeks and rewards, their history, and each Squeek's metadata.

### Issuance state · GET /v1/mining/state

SQK issuance and supply, how far SqueekMining has processed rounds, and the state of the Squeek sale. Use it for supply figures and the mint page.

The endpoint takes no parameters; any query parameter returns 400 `invalid_query`.

**Example request**

```sh
curl -i https://api.squeekchain.com/v1/mining/state
```

**Response**

```json
{
  "schemaVersion": 1,
  "installationId": "hamster-sepolia-core3-mining6-001",
  "status": "available",
  "generatedAt": "2026-10-15T00:56:09.247Z",
  "release": {
    "id": "squeeks-sepolia-core3-mining6-001",
    "protocolRevision": "mining-6",
    "rewardModelRevision": "q128-round-fixed-1"
  },
  "chain": {
    "target": "sepolia",
    "chainId": "11155111",
    "confirmations": "12",
    "deploymentBlock": "11902282",
    "economyDeploymentBlock": "11902290",
    "indexedThroughBlock": "11916986",
    "safeThroughBlock": "11916975",
    "safeBlockHash": "0x6a4cec14952c737210721a03d40772a52d05650cd173cb627744be69cec18db6",
    "safeBlockTimestamp": "2026-10-15T00:53:48.000Z"
  },
  "identities": {
    "core": "0x74665daeca35a2303e767e76a2ff1fb6f93e119f",
    "mining": "0x3bee588fc20de788bac17d33b41da7346cb27ec4",
    "token": "0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76",
    "collection": "0x0eaf3e0d40a0a8e5a6ac030b2459e9fb0b7905c6",
    "miningImplementation": "0x08890b360c65fd878344bf6e23d1c36358433b4e",
    "miningImplementationVersion": "6",
    "miningStorageLayoutDigest": "0xace564e9c052f30122779a32fdf3333ebce7cc708eae9c01cb7875b4f6ad37a6"
  },
  "asset": {"address": "0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76", "symbol": "SQK", "decimals": 18},
  "issuance": {
    "mintedBaseUnits": "13624800000000000000000000",
    "tokenSupplyBaseUnits": "13624800000000000000000000",
    "unmintedCapacityBaseUnits": "2086375200000000000000000000",
    "closedThroughBlock": "2614",
    "processedThroughRound": "295",
    "lastActivationRound": "5",
    "supplyCapBaseUnits": "2100000000000000000000000000",
    "paidBaseUnits": "6272000000000000000000"
  },
  "collection": {
    "phase": "public",
    "paused": true,
    "publicMinted": "0",
    "publicAllocation": "8888",
    "reserveMinted": "100",
    "protocolReserve": "1111",
    "publicPriceBaseUnits": "0",
    "allowlistStart": null,
    "allowlistEnd": null
  },
  "livePositionCount": "100"
}
```

| Field | Type | Description |
|---|---|---|
| `asset` | `object` | The SQK token: `address`, `symbol`, `decimals` |
| `issuance.mintedBaseUnits` | `string` | SQK issued so far |
| `issuance.tokenSupplyBaseUnits` | `string` | SQK total supply |
| `issuance.unmintedCapacityBaseUnits` | `string` | SQK left under the supply cap |
| `issuance.supplyCapBaseUnits` | `string` | The lifetime cap. May be absent |
| `issuance.paidBaseUnits` | `string` | SQK claimed by owners so far. May be absent |
| `issuance.closedThroughBlock` | `string` | The last Squeek block SqueekMining has funded |
| `issuance.processedThroughRound` | `string` | The last round SqueekMining has funded |
| `issuance.lastActivationRound` | `string` | The last round in which pending power changes took effect |
| `collection.phase` | `string` | `unconfigured`, `pending`, `allowlist`, `public` or `closed`. The `collection` object may be absent |
| `collection.paused` | `boolean` | Whether minting is paused |
| `collection.publicMinted`, `collection.publicAllocation` | `string` | Squeeks minted from, and the size of, the public allocation |
| `collection.reserveMinted`, `collection.protocolReserve` | `string` | Squeeks minted from, and the size of, the Hamster-Owned Liquidity reserve |
| `collection.publicPriceBaseUnits` | `string` | Mint price in wei (ETH), not SQK |
| `collection.allowlistStart`, `collection.allowlistEnd` | `string` or `null` | The allowlist window |
| `livePositionCount` | `string` | Squeeks currently registered in SqueekMining. May be absent |

[Complete response schema](https://docs.squeekchain.com/assets/api/mining-state.json)

**Freshness**

Read at the safe block and shared for up to 5 seconds. Unavailable reasons: `indexer_disabled`, `not_yet_safe`, `indexer_unavailable`, `indexer_mismatch`, `unsupported_contract_version`, `projection_rebuilding`.

### Owner's Squeeks · GET /v1/owners/{address}/squeeks

Every Squeek an address owns, with its level, power, merge readiness and SQK, plus totals and seven days of earnings. Use it for a portfolio view.

**Path and query parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `address` | `string` | Yes | The owner's address: `0x` and 40 hex digits, all lowercase or with a valid EIP-55 checksum. Anything else, including a wrong checksum or the zero address, returns 400 `invalid_address` |
| `limit` | `integer` | No | Squeeks per page, 1–100; default 25 |
| `cursor` | `string` | No | `nextCursor` from the previous page, with the same `address` |

**Example request**

```sh
curl -i "https://api.squeekchain.com/v1/owners/0x828CB04Dbf0BDd8eB35d19045638a1af6E3D17E8/squeeks?limit=25"
```

```ts
// api-owner-squeeks.ts
import { apiGet, required } from "./api";

type Page = {
  status: "available" | "unavailable";
  reason?: string;
  summary?: { positionCount: string; claimableBaseUnits: string };
  positions?: { tokenId: string; level: number; activeWeight: string; claimableBaseUnits: string }[];
  nextCursor?: string | null;
};

const owner = required("OWNER_ADDRESS");
const positions: NonNullable<Page["positions"]> = [];
let cursor: string | null = null;
do {
  const query = new URLSearchParams({ limit: "100", ...(cursor ? { cursor } : {}) });
  const page: Page = await apiGet<Page>(`/v1/owners/${owner}/squeeks?${query}`);
  if (page.status !== "available") throw new Error(`Owner data unavailable: ${page.reason}`);
  positions.push(...(page.positions ?? []));
  cursor = page.nextCursor ?? null;
} while (cursor !== null);
const claimable = positions.reduce((sum, position) => sum + BigInt(position.claimableBaseUnits), 0n);
console.log({ owner, squeeks: positions.length, claimableSqkBaseUnits: claimable });
```

```ts
// api.ts
export const required = (name: string): string => {
  const value = process.env[name];
  if (!value) throw new Error(`Supply ${name}`);
  return value;
};

/** GET a public endpoint, waiting out rate limits and capacity errors a bounded number of times. */
export async function apiGet<T>(path: string): Promise<T> {
  const base = required("API_BASE_URL");
  for (let attempt = 0; ; attempt += 1) {
    const response = await fetch(new URL(path, base), { headers: { accept: "application/json" } });
    if ((response.status === 429 || response.status === 503) && attempt < 3) {
      const seconds = Number(response.headers.get("retry-after") ?? "2");
      await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
      continue;
    }
    if (!response.ok) throw new Error(`${path}: HTTP ${response.status} ${await response.text()}`);
    return (await response.json()) as T;
  }
}
```

Set `API_BASE_URL=https://api.squeekchain.com` and `OWNER_ADDRESS`, then run `npx tsx api-owner-squeeks.ts`.

**Response**

<details markdown="1">
<summary>Example response</summary>

```json
{
  "schemaVersion": 1,
  "installationId": "hamster-sepolia-core3-mining6-001",
  "status": "available",
  "generatedAt": "2026-10-15T00:57:41.296Z",
  "release": {
    "id": "squeeks-sepolia-core3-mining6-001",
    "protocolRevision": "mining-6",
    "rewardModelRevision": "q128-round-fixed-1"
  },
  "owner": "0x828cb04dbf0bdd8eb35d19045638a1af6e3d17e8",
  "chain": {
    "target": "sepolia",
    "chainId": "11155111",
    "confirmations": "12",
    "deploymentBlock": "11902282",
    "economyDeploymentBlock": "11902290",
    "indexedThroughBlock": "11916993",
    "safeThroughBlock": "11916982",
    "safeBlockHash": "0x44ce0cd3258a6668ba8a9e19c06153a53dca21e68bdcded5189ab951ff99e019",
    "safeBlockTimestamp": "2026-10-15T00:55:12.000Z"
  },
  "identities": {
    "core": "0x74665daeca35a2303e767e76a2ff1fb6f93e119f",
    "mining": "0x3bee588fc20de788bac17d33b41da7346cb27ec4",
    "token": "0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76",
    "collection": "0x0eaf3e0d40a0a8e5a6ac030b2459e9fb0b7905c6",
    "miningImplementation": "0x08890b360c65fd878344bf6e23d1c36358433b4e",
    "miningImplementationVersion": "6",
    "miningStorageLayoutDigest": "0xace564e9c052f30122779a32fdf3333ebce7cc708eae9c01cb7875b4f6ad37a6"
  },
  "configuration": {
    "genesisTimestamp": "1791847800",
    "roundDuration": "600",
    "maxCheckpointActivations": "32",
    "blockUnitsPerBlock": "1000000000",
    "rewardPerBlock": "5600000000000000000000",
    "supplyCap": "2100000000000000000000000000",
    "initialWorkPerThousandBlocks": "10875",
    "maximumLevel": 10,
    "claimLimit": "32",
    "tokenSymbol": "SQK",
    "tokenDecimals": 18,
    "levels": [
      {"level": 1, "weight": "1000", "cooldownBlocks": "2"},
      {"level": 2, "weight": "3000", "cooldownBlocks": "4"}
    ]
  },
  "mining": {
    "settledThroughRound": "295",
    "currentRound": "297",
    "completedBlockHeight": "2614",
    "processedThroughRound": "295",
    "lastActivationRound": "5",
    "totalWeight": "100000"
  },
  "summary": {
    "positionCount": "100",
    "activeWeight": "100000",
    "targetWeight": "100000",
    "claimableBaseUnits": "13618528000000000000000000",
    "earnedBaseUnits": "13624800000000000000000000",
    "earnedSevenDayBaseUnits": "13624800000000000000000000"
  },
  "earnings": [
    {"date": "2026-10-14", "earnedBaseUnits": "6636000000000000000000000"},
    {"date": "2026-10-15", "earnedBaseUnits": "1243200000000000000000000"}
  ],
  "positions": [
    {
      "tokenId": "8889",
      "level": 1,
      "activeWeight": "1000",
      "targetWeight": "1000",
      "pendingRound": null,
      "pendingActivationSource": null,
      "mergeState": "ready",
      "nextMergeBlock": "2",
      "blocksUntilMerge": "0",
      "claimableBaseUnits": "129976000000000000000000",
      "earnedBaseUnits": "136248000000000000000000",
      "earnedSevenDayBaseUnits": "136248000000000000000000",
      "ownershipStartedAt": "2026-10-13T00:09:00.000Z",
      "metadataStatus": "available"
    }
  ],
  "nextCursor": "eyJ2ZXJzaW9uIjoyLCJraW5kIjoicG9zaXRpb25zIiwib3duZXIiOiIweDgyOGNiMDRkYmYwYmRkOGViMzVkMTkwNDU2MzhhMWFmNmUzZDE3ZTgiLCJyZWxlYXNlSWQiOiJzcXVlZWtzLXNlcG9saWEtY29yZTMtbWluaW5nNi0wMDEiLCJzYWZlVGhyb3VnaEJsb2NrIjoiMTE5MTY5ODIiLCJzYWZlQmxvY2tIYXNoIjoiMHg0NGNlMGNkMzI1OGE2NjY4YmE4YTllMTljMDYxNTNhNTNkY2EyMWU2OGJkY2RlZDUxODlhYjk1MWZmOTllMDE5IiwibGFzdFRva2VuSWQiOiI4ODkwIn0"
}
```

</details>

| Field | Type | Description |
|---|---|---|
| `owner` | `string` | The owner, lowercase, whatever casing the request used |
| `configuration` | `object` | SqueekMining's settings: `genesisTimestamp`, `roundDuration`, `maximumLevel`, `claimLimit`, `maxCheckpointActivations`, `rewardPerBlock`, `supplyCap`, token symbol and decimals |
| `configuration.levels[]` | `object` | Per level: `level`, `weight` (power) and `cooldownBlocks` |
| `mining` | `object` | Global progress: `settledThroughRound`, `currentRound`, `completedBlockHeight`, `processedThroughRound`, `lastActivationRound`, `totalWeight` |
| `summary` | `object` | Across all the owner's Squeeks, not just this page: `positionCount`, `activeWeight`, `targetWeight`, `claimableBaseUnits`, `earnedBaseUnits`, `earnedSevenDayBaseUnits` |
| `earnings[]` | `object` | Seven entries, oldest first: `date` (UTC) and `earnedBaseUnits` |
| `positions[].tokenId` | `string` | The Squeek's token ID |
| `positions[].level` | `integer` | Level, 1–10 |
| `positions[].activeWeight` | `string` | Power earning now |
| `positions[].targetWeight` | `string` | Power once a pending change activates |
| `positions[].pendingRound` | `string` or `null` | The round a pending change activates in |
| `positions[].pendingActivationSource` | `string` or `null` | `mint` or `merge` |
| `positions[].mergeState` | `string` | The first that applies: `pending` (a change is waiting to activate), `terminal` (maximum level), `cooldown` or `ready` |
| `positions[].nextMergeBlock` | `string` | The Squeek block from which it can merge again |
| `positions[].blocksUntilMerge` | `string` | Squeek blocks until then; `0` when ready |
| `positions[].claimableBaseUnits` | `string` | SQK claimable now, at the safe block |
| `positions[].earnedBaseUnits` | `string` | SQK earned since the current owner took it, including what a merged-in donor had earned for that owner |
| `positions[].earnedSevenDayBaseUnits` | `string` | SQK earned in the last seven days |
| `positions[].ownershipStartedAt` | `string` | When the current owner received it |
| `positions[].metadataStatus` | `string` | Whether `/v1/squeeks/{tokenId}/metadata` can serve it: `available` or `unavailable` |
| `nextCursor` | `string` or `null` | The next page; `null` at the end |

[Complete response schema](https://docs.squeekchain.com/assets/api/owner-squeeks.json)

`claimableBaseUnits` is a display value 12 blocks old. Before preparing a claim, read [`claimable`](https://docs.squeekchain.com/developers/mining.md#claimable) at your own block; see [Build owner actions](https://docs.squeekchain.com/developers/owner-actions.md#claim-rewards).

**Freshness**

Computed per request at the safe block. A cursor pins the owner, release, safe block and that block's hash. Unavailable reasons: `indexer_disabled`, `not_yet_safe`, `indexer_unavailable`, `indexer_mismatch`, `unsupported_contract_version`, `projection_rebuilding`.

**Errors**

| Status | Code | Cause |
|---|---|---|
| 400 | `invalid_address` | `address` is malformed, has a wrong checksum or is the zero address |
| 400 | `invalid_cursor` | The cursor can't be decoded or was issued for another route; start again from the first page |
| 409 | `cursor_invalidated` | The page's block was reorganized away, or the cursor belongs to another owner or release. Restart from the first page |

### Owner activity · GET /v1/owners/{address}/activity

An address's history with its Squeeks, newest first: mints, merges, claims and transfers. Use it for an account history.

**Path and query parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `address` | `string` | Yes | The owner's address, lowercase or checksummed, as for [Owner's Squeeks](https://docs.squeekchain.com/developers/api.md#owner-squeeks) |
| `limit` | `integer` | No | Entries per page, 1–100; default 25 |
| `cursor` | `string` | No | `nextCursor` from the previous page, with the same `address` |

**Example request**

```sh
curl -i "https://api.squeekchain.com/v1/owners/0x828cb04dbf0bdd8eb35d19045638a1af6e3d17e8/activity?limit=25"
```

**Response**

```json
{
  "schemaVersion": 1,
  "installationId": "hamster-sepolia-core3-mining6-001",
  "status": "available",
  "generatedAt": "2026-10-15T00:56:14.556Z",
  "owner": "0x828cb04dbf0bdd8eb35d19045638a1af6e3d17e8",
  "chain": {
    "target": "sepolia",
    "chainId": "11155111",
    "confirmations": "12",
    "deploymentBlock": "11902282",
    "economyDeploymentBlock": "11902290",
    "indexedThroughBlock": "11916986",
    "safeThroughBlock": "11916975",
    "safeBlockHash": "0x6a4cec14952c737210721a03d40772a52d05650cd173cb627744be69cec18db6",
    "safeBlockTimestamp": "2026-10-15T00:53:48.000Z"
  },
  "release": {
    "id": "squeeks-sepolia-core3-mining6-001",
    "protocolRevision": "mining-6",
    "rewardModelRevision": "q128-round-fixed-1"
  },
  "identities": {
    "core": "0x74665daeca35a2303e767e76a2ff1fb6f93e119f",
    "mining": "0x3bee588fc20de788bac17d33b41da7346cb27ec4",
    "token": "0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76",
    "collection": "0x0eaf3e0d40a0a8e5a6ac030b2459e9fb0b7905c6",
    "miningImplementation": "0x08890b360c65fd878344bf6e23d1c36358433b4e",
    "miningImplementationVersion": "6",
    "miningStorageLayoutDigest": "0xace564e9c052f30122779a32fdf3333ebce7cc708eae9c01cb7875b4f6ad37a6"
  },
  "activity": [
    {
      "id": "179185251600000000111551110000000011902583000000000000009350000000000000132",
      "kind": "claim",
      "tokenIds": ["8889"],
      "amountBaseUnits": "6272000000000000000000",
      "from": null,
      "to": null,
      "level": null,
      "effectiveRound": null,
      "nextMergeBlock": null,
      "source": {
        "blockNumber": "11902583",
        "blockHash": "0xefbeeed403baf747669d24a95bca2230b1389b2ac7180868722a812d8135eb78",
        "blockTimestamp": "2026-10-13T00:48:36.000Z",
        "transactionHash": "0x4e21ce566ec8a4eb3fb9e1a49a58faf6acd87d677764740a41f5b18e44fe94d8",
        "transactionIndex": "93",
        "logIndex": "132",
        "confirmationStatus": "safe"
      }
    }
  ],
  "total": "101",
  "nextCursor": "eyJ2ZXJzaW9uIjoxLCJzYWZlVGhyb3VnaEJsb2NrIjoiMTE5MTY5NzUiLCJibG9ja051bWJlciI6IjExOTAyMzg3IiwidHJhbnNhY3Rpb25JbmRleCI6Ijk0IiwibG9nSW5kZXgiOiI0NzMifQ"
}
```

| Field | Type | Description |
|---|---|---|
| `activity[].id` | `string` | Stable, unique entry ID |
| `activity[].kind` | `string` | `mint`, `merge`, `claim` or `transfer` |
| `activity[].tokenIds` | `string[]` | The Squeeks involved; for a merge, the survivor and the donor |
| `activity[].amountBaseUnits` | `string` or `null` | SQK claimed; `null` except for claims |
| `activity[].from`, `activity[].to` | `string` or `null` | Transfer parties; `null` except for transfers |
| `activity[].level` | `integer` or `null` | The survivor's new level after a merge |
| `activity[].nextMergeBlock` | `string` or `null` | When the Squeek can merge again, after a mint or merge |
| `activity[].effectiveRound` | `string` or `null` | The round new power activates in, after a mint or merge |
| `activity[].source` | `object` | `blockNumber`, `blockHash`, `blockTimestamp`, `transactionHash`, `transactionIndex`, `logIndex`, `confirmationStatus: "safe"` |
| `total` | `string` | Entries in the owner's whole history. May be absent |
| `nextCursor` | `string` or `null` | The next page; `null` at the end |

[Complete response schema](https://docs.squeekchain.com/assets/api/owner-activity.json)

**Freshness**

Computed per request at the safe block; an entry is final once listed, at 12 confirmations. A cursor keeps reading at the first page's safe block, so pages are consistent. Unavailable reasons: `indexer_disabled`, `not_yet_safe`, `indexer_unavailable`, `indexer_mismatch`, `unsupported_contract_version`, `projection_rebuilding`.

**Errors**

| Status | Code | Cause |
|---|---|---|
| 400 | `invalid_address` | `address` is malformed, has a wrong checksum or is the zero address |
| 400 | `invalid_cursor` | The cursor can't be decoded or was issued for another route; start again from the first page |

### Squeek metadata · GET /v1/squeeks/{tokenId}/metadata

A Squeek's name, description, traits and image, rendered onchain by the [DotGrid renderer](https://docs.squeekchain.com/developers/dotgrid.md). Use it to show a Squeek without calling `tokenURI` yourself.

**Path and query parameters**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `tokenId` | `string` | Yes | Token ID, 1–9999, without leading zeros |
| `release` | `string` | No | The release ID from `release.id`. With it, the response may give a cached raster image (`cardImageUrl`) instead of the inline SVG. Any other value returns 400 `invalid_query` |

**Example request**

```sh
curl -i https://api.squeekchain.com/v1/squeeks/8889/metadata
```

**Response**

```json
{
  "schemaVersion": 1,
  "installationId": "hamster-sepolia-core3-mining6-001",
  "status": "available",
  "generatedAt": "2026-10-15T00:56:15.076Z",
  "tokenId": "8889",
  "chain": {
    "target": "sepolia",
    "chainId": "11155111",
    "confirmations": "12",
    "deploymentBlock": "11902282",
    "economyDeploymentBlock": "11902290",
    "indexedThroughBlock": "11916986",
    "safeThroughBlock": "11916975",
    "safeBlockHash": "0x6a4cec14952c737210721a03d40772a52d05650cd173cb627744be69cec18db6",
    "safeBlockTimestamp": "2026-10-15T00:53:48.000Z"
  },
  "identities": {
    "core": "0x74665daeca35a2303e767e76a2ff1fb6f93e119f",
    "mining": "0x3bee588fc20de788bac17d33b41da7346cb27ec4",
    "token": "0x6872bfa5ccc3e9e440c6c16e5ffdabb8dba4cc76",
    "collection": "0x0eaf3e0d40a0a8e5a6ac030b2459e9fb0b7905c6",
    "miningImplementation": "0x08890b360c65fd878344bf6e23d1c36358433b4e",
    "miningImplementationVersion": "6",
    "miningStorageLayoutDigest": "0xace564e9c052f30122779a32fdf3333ebce7cc708eae9c01cb7875b4f6ad37a6"
  },
  "release": {
    "id": "squeeks-sepolia-core3-mining6-001",
    "protocolRevision": "mining-6",
    "rewardModelRevision": "q128-round-fixed-1"
  },
  "collection": "0x0eaf3e0d40a0a8e5a6ac030b2459e9fb0b7905c6",
  "name": "Squeek #8889",
  "description": "Squeek is a dot-grid character rendered fully onchain from an immutable art page.",
  "imageDataUri": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciLz4=",
  "attributes": [
    {"traitType": "Palette", "value": "Spectral Acid Lime"},
    {"traitType": "Color Pattern", "value": "Vertical Split"},
    {"traitType": "Body Glyph", "value": "Circle"}
  ]
}
```

| Field | Type | Description |
|---|---|---|
| `tokenId` | `string` | The token ID |
| `collection` | `string` | The SqueekNFT address |
| `name`, `description` | `string` | As in the onchain metadata |
| `imageDataUri` | `string` | The image as an SVG data URI (up to about 240 KB). Present unless `cardImageUrl` is |
| `cardImageUrl` | `string` | An HTTPS raster image, only for requests that name `release` when one exists |
| `attributes[]` | `object` | Traits: `traitType` and `value` |

[Complete response schema](https://docs.squeekchain.com/assets/api/squeek-metadata.json)

**Freshness**

Read at the safe block for the current metadata epoch. Responses are `no-store`, except a release-scoped response with `cardImageUrl`, which is `private, max-age=300`. Unavailable reasons: `indexer_disabled`, `not_yet_safe`, `indexer_unavailable`, `indexer_mismatch`, `unsupported_contract_version`, `projection_rebuilding`.

**Errors**

| Status | Code | Cause |
|---|---|---|
| 400 | `invalid_token_id` | Not a token ID from 1 to 9999 |

## Related pages

- [Developers](https://docs.squeekchain.com/developers.md)
- [Quickstart](https://docs.squeekchain.com/developers/quickstart.md)
- [Index events](https://docs.squeekchain.com/developers/index-events.md)
- [Build owner actions](https://docs.squeekchain.com/developers/owner-actions.md)
- [Build with AI](https://docs.squeekchain.com/developers/build-with-ai.md)
