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

# Metadata Standard

> Token and collection JSON for Xpectrum (v1.0)

The Xpectrum Metadata Standard v1.0 defines the JSON that describes a token and a collection. It is deliberately self-describing (a token renders from its own JSON without fetching the collection) and provenance-friendly (every byte that matters is covered by the [provenance hash](/standards/provenance)).

This page is the practical reference. If your folder passes [xpress](/developers/xpress) `check`, it conforms.

## Layout

A collection lives in one Circle. Files use a fixed path convention:

```
oct://[circle_id]/collection.json          collection metadata
oct://[circle_id]/[token_id].json          one per token, 0-indexed, no leading zeros
oct://[circle_id]/traits/[trait]/[value].png   trait layers (composed collections)
oct://[circle_id]/avatar.png               avatar (cosmetic)
oct://[circle_id]/banner.png               banner (cosmetic)
```

The collection JSON URI is derived from the token URI (swap the filename for `collection.json`); there is no `collection_uri` field.

## Token metadata (`[token_id].json`)

| Field               | Type   | Required    | Purpose                                                                                                               |
| ------------------- | ------ | ----------- | --------------------------------------------------------------------------------------------------------------------- |
| `xpectrum_metadata` | string | Yes         | Standard version. Must be `"1.0"`.                                                                                    |
| `name`              | string | Yes         | Display name, max 128 chars.                                                                                          |
| `description`       | string | Optional    | Free-form, max 2000 chars, not rendered as Markdown.                                                                  |
| `image`             | string | Conditional | Required for `prerendered`; ignored by the frontend for `composed`. Schemes: `oct://` (native) or `ipfs://` (legacy). |
| `animation_uri`     | string | Optional    | Reserved for video/audio/3D/HTML. Indexers preserve it; frontend rendering is not built in v1.0.                      |
| `external_url`      | string | Optional    | HTTPS link to a creator webpage. Never media storage.                                                                 |
| `attributes`        | array  | Yes         | Trait list (may be empty).                                                                                            |

Each attribute is `{ "trait_type": string, "value": string | number }`, with optional `id` and `display_type`. Rules: `value` is always present and human-readable; max 32 attributes; a `trait_type` appears at most once per token. Royalty fields must never appear in JSON; royalties are on-chain only.

## Collection metadata (`collection.json`)

| Field               | Type   | Required    | Purpose                                                                                                |
| ------------------- | ------ | ----------- | ------------------------------------------------------------------------------------------------------ |
| `xpectrum_metadata` | string | Yes         | Must be `"1.0"`.                                                                                       |
| `name`              | string | Yes         | Display name.                                                                                          |
| `image`             | string | Yes         | `oct://` URI to the avatar.                                                                            |
| `banner`            | string | Optional    | `oct://` URI to the banner.                                                                            |
| `category`          | string | Optional    | `pfp`, `art`, `photography`, `music`, `gaming`, `membership`, `domain`, `identity`, `ticket`, `other`. |
| `render_type`       | string | Yes         | `"composed"` or `"prerendered"`.                                                                       |
| `trait_types`       | array  | Conditional | Required for `composed`. Declares trait categories and layer order.                                    |
| `creators`          | array  | Optional    | Declarative attribution. On-chain `creator_of()` is the source of truth for payments.                  |
| `mutability`        | string | Yes         | `"frozen_by_provenance"`.                                                                              |
| `contract_address`  | string | Recommended | The Xcollection address this file claims. Indexers reject a mismatch.                                  |

The on-chain `provenance_hash` is **not** mirrored here (that would be circular). It lives only on-chain.

## Render types

* **`composed`**: the token's image is composited at display time from trait layers, ordered by each `trait_types[].layer_order` (lower renders first). Token JSONs carry no `image`.
* **`prerendered`**: each token JSON points at a finished `image` asset.

## Mutability

Collections launched on Xpectrum are **`frozen_by_provenance`**: `set_provenance_hash()` has been called, the collection is immutable on-chain, and indexers may cache it indefinitely. This is the only mode the Launchpad offers.

<Note>
  The standard reserves a `"mutable"` value for collections that keep write access open, but Xpectrum does not currently offer it. Treat `frozen_by_provenance` as the expected value.
</Note>

## Provenance hash

For a frozen collection, the hash is built over the exact stored bytes in a canonical order:

```
input = sha256(0.json) || ... || sha256((N-1).json)
        || sha256(collection.json)
        || sha256(trait layers, sorted by (trait_slug, value_slug))
        || sha256(referenced token images, ascending token id, deduped)
        || sha256(referenced animation assets, ascending token id, deduped)
hash  = sha256(input)
```

N is `max_supply` (all token JSONs must exist before freezing). `ipfs://` media is not byte-hashed because the CID inside the JSON is already a content hash; `https://` media is not allowed in a frozen collection. Avatar and banner are excluded. See [Provenance](/standards/provenance) for the verification flow.

## Examples

Complete, copy-ready examples covering both render types and every supported field. A renderer that handles these handles the standard.

### Composed collection

The collection declares `trait_types` with `layer_order`; each token lists its `attributes` and the renderer composites the trait layers bottom-to-top. Token JSONs carry no `image`.

**`collection.json`**

```json theme={"system"}
{
  "xpectrum_metadata": "1.0",
  "name": "Xpectrum Wraiths",
  "description": "1024 wraiths drifting through the Octra void.",
  "image": "oct://c_abc.../avatar.png",
  "banner": "oct://c_abc.../banner.png",
  "external_url": "https://wraiths.example.art",
  "category": "pfp",
  "render_type": "composed",
  "contract_address": "oct1coll...",
  "trait_types": [
    {
      "name": "Background",
      "layer_order": 10,
      "values": [
        { "id": 1, "name": "Midnight Blue", "rarity_pct": 30.50 },
        { "id": 2, "name": "Crimson", "rarity_pct": 12.20 },
        { "id": 3, "name": "Forest", "rarity_pct": 57.30 }
      ]
    },
    {
      "name": "Body",
      "layer_order": 20,
      "values": [
        { "id": 1, "name": "Pale" },
        { "id": 2, "name": "Ash" }
      ]
    },
    { "name": "Eyes", "layer_order": 30 },
    { "name": "Aura", "layer_order": 40 }
  ],
  "creators": [
    { "address": "oct1artist...", "name": "Nyx", "share": 70 },
    { "address": "oct1dev...", "name": "Vex", "share": 30 }
  ],
  "mutability": "frozen_by_provenance",
  "reveal": { "status": "post", "revealed_at": 1717000000 },
  "links": {
    "twitter": "https://twitter.com/example",
    "discord": "https://discord.gg/example"
  }
}
```

**`42.json`** (one token)

```json theme={"system"}
{
  "xpectrum_metadata": "1.0",
  "name": "Wraith #42",
  "description": "A wraith with crimson smoke and pale skin.",
  "attributes": [
    { "trait_type": "Background", "value": "Crimson", "id": 2 },
    { "trait_type": "Body", "value": "Pale", "id": 1 },
    { "trait_type": "Eyes", "value": "Hollow Gold" },
    { "trait_type": "Aura", "value": "Static" }
  ]
}
```

The renderer composites these layers, ordered by each trait's `layer_order` (bottom to top):

```
oct://c_abc.../traits/background/crimson.png      (layer_order 10)
oct://c_abc.../traits/body/pale.png               (layer_order 20)
oct://c_abc.../traits/eyes/hollow-gold.png        (layer_order 30)
oct://c_abc.../traits/aura/static.png             (layer_order 40)
```

Trait layer paths are `traits/[trait_slug]/[value_slug].png`, where the slug lowercases and hyphenates the names (`"Hollow Gold"` becomes `hollow-gold`).

### Prerendered collection

Each token points at a finished `image`. `trait_types` is optional (include it only to give indexers nicer filter labels). This example also shows `external_url` and `display_type` on attributes.

**`collection.json`**

```json theme={"system"}
{
  "xpectrum_metadata": "1.0",
  "name": "Octra Skylines",
  "description": "25 photographic prints of skylines along the Octra coast.",
  "image": "oct://c_def.../avatar.png",
  "banner": "oct://c_def.../banner.png",
  "category": "photography",
  "render_type": "prerendered",
  "contract_address": "oct1skyl...",
  "creators": [
    { "address": "oct1photog...", "name": "Marin Vey" }
  ],
  "mutability": "frozen_by_provenance",
  "links": {
    "twitter": "https://twitter.com/example"
  }
}
```

**`7.json`** (one token)

```json theme={"system"}
{
  "xpectrum_metadata": "1.0",
  "name": "Harbour, 04:18",
  "description": "Long exposure, 240 seconds, from the east pier.",
  "image": "oct://c_def.../images/7.png",
  "external_url": "https://example.art/harbour",
  "attributes": [
    { "trait_type": "Location", "value": "East Pier" },
    { "trait_type": "Time", "value": 1717474680, "display_type": "date" },
    { "trait_type": "Exposure (s)", "value": 240, "display_type": "number" }
  ]
}
```

### Notes for renderers and wallets

* A token is fully renderable from its own JSON. For composed tokens, fetch `collection.json` once for `layer_order`; everything else is in the token.
* `display_type: "date"` is Unix seconds; `display_type: "number"` renders the raw numeric value.
* `external_url` is an informational webpage link only. Never fetch display media from it.
* `animation_uri` is reserved for video/audio/3D/HTML. Preserve and surface it; a poster `image` should accompany it when present.
* Resolve `oct://[circle_id]/[path]` by reading the asset from that circle on-chain. `ipfs://` resolves through any IPFS gateway.
