# registeredOutcomesSnapshot

{% hint style="warning" %}

### ⚠️ This is an add-on endpoint - access has to be purchased separately.

{% endhint %}

Returns compressed snapshots for active HIP-4 outcomes — one snapshot per outcome side (YES/NO). Each snapshot lists every holder of that side and their balance.

There are two endpoints:

1. **Metadata Endpoint (Fast)** — check whether new snapshots are available.
2. **Snapshot Endpoint (Heavy)** — download compressed snapshot data.

***

## registeredOutcomesSnapshotTimestamp (Fast)

* **Endpoint:** `POST /info`
* **Purpose:** check whether new snapshots have been written
* **Response time:** \~1 ms

### Request

<table><thead><tr><th width="161">Field</th><th width="119">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"registeredOutcomesSnapshotTimestamp"</code></td></tr></tbody></table>

```bash
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "type": "registeredOutcomesSnapshotTimestamp" }'
```

### Response

```json
{
  "snapshot_id": "20260428_state_123456789",
  "timestamp": 1745846400
}
```

***

## registeredOutcomesSnapshot (Heavy)

* **Endpoint:** `POST /info`
* **Purpose:** download per-side outcome snapshots
* **Response time:** \~100 ms+

### Request

<table><thead><tr><th width="161">Field</th><th width="170">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>Must be <code>"registeredOutcomesSnapshot"</code></td></tr><tr><td><code>outcome_ids</code></td><td>array of integers</td><td>Outcome ids to fetch (optional). Each id expands to two asset_ids: YES = <code>#{id*10}</code>, NO = <code>#{id*10+1}</code>.</td></tr><tr><td><code>asset_ids</code></td><td>array of strings</td><td>Asset ids in <code>#NNNN</code> format (optional). Used as-is.</td></tr><tr><td><code>question_ids</code></td><td>array of integers</td><td>HIP-4 question ids (optional). Each is server-side-expanded to its child outcomes (named + fallback), then each child to its YES + NO asset_ids.</td></tr></tbody></table>

If `outcome_ids`, `asset_ids`, and `question_ids` are all omitted, the response contains every active outcome side.

After deduplication, the combined `outcome_ids` (expanded) + `asset_ids` + `question_ids` (expanded to children, then to asset\_ids) list must not exceed **50 entries**; larger requests are rejected with `400 Bad Request`.

```bash
# Specific outcomes (YES + NO)
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  --output outcomes.bin \
  -d '{ "type": "registeredOutcomesSnapshot", "outcome_ids": [3, 7] }'

# All active outcomes
curl -X POST https://api.hydromancer.xyz/info \
  -H "Authorization: Bearer $HYDROMANCER_API_KEY" \
  -H "Content-Type: application/json" \
  --output outcomes.bin \
  -d '{ "type": "registeredOutcomesSnapshot" }'
```

### Response Headers

* **Single asset\_id:** `x-payload-format: msgpack`, `Content-Encoding: zstd`
* **Multiple asset\_ids:** `x-payload-format: multi-zstd`, `x-compression: inner-zstd`

### Data Format

<details>

<summary>Single Snapshot Response</summary>

**Format:** raw zstd-compressed MessagePack.

**Decompressed structure** — a positional 4-element array. rmp-serde encodes Rust structs as msgpack arrays by default, so the field order matters, not the names:

```json
[
  "20260428_state_123456789",            // [0] snapshot_id
  3,                                      // [1] outcome_id
  "#30",                                  // [2] asset_id
  {                                       // [3] balances — address → integer-lot string
    "0xa11ce...000a": "100",
    "0xb0b...000b": "5"
  }
]
```

> **Note:** balances are formatted via HL's size-decimals rules. Outcome side tokens currently ship with `szDecimals=0` and `weiDecimals=5` on-chain; the producer reads both per-token from spot meta and uses them to descale and format. With `szDecimals=0`, balances are rounded to whole lots and rendered as integer strings — no decimal point, no trailing zeros (`"100"`, not `"100.00"`). Sub-lot dust uses banker's rounding (round-half-to-even). Parse with `int(s)`.

> **Note:** the HL escrow precompile address for each token is excluded from the snapshot. Every spot token has a deterministic escrow at `0x32{:038x}` of its `token_id` (e.g. `0x32000000000000000000000000000000000001ca` for token 458) that holds the unsold/issuer supply — it isn't a real user position. Thus, it is dropped from each side's balances map.

</details>

<details>

<summary>Multiple Snapshots Response</summary>

**Format:** custom binary framing with per-snapshot zstd payloads.

**Binary structure:**

```
[count: 4 bytes LE][len1: 4 bytes LE][zstd_blob1][len2: 4 bytes LE][zstd_blob2]...
```

Each `zstd_blob` decompresses to one positional 4-element msgpack array with the `[snapshot_id, outcome_id, asset_id, balances]` shape shown above. Snapshots are returned in `(outcome_id, side_index)` order.

</details>

### Implementation Example

```python
import requests, struct, zstandard as zstd, msgpack, os

response = requests.post(
    "https://api.hydromancer.xyz/info",
    json={"type": "registeredOutcomesSnapshot", "outcome_ids": [3, 7]},
    headers={
        "Authorization": f"Bearer {os.environ['HYDROMANCER_API_KEY']}",
        "Content-Type": "application/json",
    },
)
body = response.content
fmt = response.headers.get("x-payload-format")

if fmt == "msgpack":
    snapshot = msgpack.unpackb(zstd.ZstdDecompressor().decompress(body), raw=False)
    print(snapshot)
else:
    # multi-zstd: count, then [len][blob] pairs
    count = struct.unpack("<I", body[:4])[0]
    offset = 4
    snapshots = []
    for _ in range(count):
        length = struct.unpack("<I", body[offset:offset + 4])[0]
        offset += 4
        blob = body[offset:offset + length]
        offset += length
        snapshots.append(
            msgpack.unpackb(zstd.ZstdDecompressor().decompress(blob), raw=False)
        )
    for snap in snapshots:
        # snap is a 4-element list: [snapshot_id, outcome_id, asset_id, balances_map].
        # Balance values are integer-lot strings (sz_decimals=0).
        asset_id = snap[2]
        balances = {addr: int(s) for addr, s in snap[3].items()}
        print(asset_id, len(balances), "holders")
```

### Error Handling

* **400** — `asset_id` missing the `#` prefix, or the request exceeds 50 deduped asset\_ids.
* **500** — no matching snapshots in Redis, or the producer hasn't written any yet. Retry after polling `registeredOutcomesSnapshotTimestamp`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hydromancer.xyz/readme/rest-api/outcomes/registeredoutcomessnapshot.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
