{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/coinrithm-com/json-schema/coinrithm-com-pm-position-schema.json",
  "title": "PmPosition",
  "description": "Mock PM position. Live-mark fields (currentProbability, unrealizedMark,\nunrealizedPnl) are added only on OPEN positions in the list endpoint and\nmay be null.\n",
  "x-generated": "2026-11-04",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/coinrithm-com-openapi.yml#/components/schemas/PmPosition",
  "type": "object",
  "properties": {
    "id": {
      "type": "integer"
    },
    "status": {
      "type": "string"
    },
    "source": {
      "type": "string"
    },
    "eventSlug": {
      "type": "string"
    },
    "eventTitle": {
      "type": "string"
    },
    "outcome": {
      "type": "object",
      "properties": {
        "externalMarketId": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "tokenId": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "side": {
      "type": "string",
      "enum": [
        true,
        false
      ],
      "description": "Which side of the binary outcome the position backs."
    },
    "fillBasis": {
      "type": "string"
    },
    "entryProbability": {
      "type": "number"
    },
    "entryProbSum": {
      "type": "number"
    },
    "stakeMusd": {
      "type": "number"
    },
    "sharesMusd": {
      "type": "number"
    },
    "maxPayout": {
      "type": "number",
      "description": "equals sharesMusd"
    },
    "shape": {
      "type": "string"
    },
    "marketsCount": {
      "type": [
        "integer",
        "null"
      ],
      "description": "True total markets on the event (stored value); may exceed the\nnumber of hydrated/snapshot outcomes for capped multi-outcome books.\nnull when unknown.\n"
    },
    "entryOutcomesSnapshot": {
      "description": "Snapshot of the event's outcomes (names + probabilities) frozen at\nentry — the basis the position was priced against.\n",
      "type": [
        "object",
        "array",
        "null"
      ],
      "items": {}
    },
    "freshnessAtEntry": {
      "$ref": "#/$defs/Freshness"
    },
    "eventStatusAtEntry": {
      "type": [
        "string",
        "null"
      ],
      "description": "The event's status (e.g. open/closed) when the position opened."
    },
    "settlementState": {
      "type": [
        "string",
        "null"
      ]
    },
    "voidReason": {
      "type": [
        "string",
        "null"
      ],
      "description": "Why a position was voided and refunded (status void_refunded) —\nnull for normal settlements.\n"
    },
    "payoutMusd": {
      "type": [
        "number",
        "null"
      ]
    },
    "pnlMusd": {
      "type": [
        "number",
        "null"
      ]
    },
    "openedAt": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time"
    },
    "settledAt": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    },
    "currentProbability": {
      "type": [
        "number",
        "null"
      ],
      "description": "list endpoint, open only; 0..100"
    },
    "unrealizedMark": {
      "type": [
        "number",
        "null"
      ]
    },
    "unrealizedPnl": {
      "type": [
        "number",
        "null"
      ]
    },
    "relatedCoins": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "List endpoint, open positions only: slugs of the coins the event is\nDIRECTLY about (admin-rejected links excluded), sorted; empty = no\nlinked coin. Omitted when it could not be read (treat as unknown).\n"
    },
    "eventEndDate": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time",
      "description": "List endpoint, open positions only: the venue's own event end date,\npassed through unchanged. Venues publish null or sentinel values,\nso treat implausible dates as unknown. Omitted when it could not be\nread.\n"
    }
  },
  "$defs": {
    "Freshness": {
      "type": "object",
      "description": "Data-freshness descriptor. Futures + spot use ageSeconds; PM uses\nageMinutes. `status` is a freshness label; `basis` (PM only) names which\ntimestamp the age was measured against.\n",
      "properties": {
        "asOf": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        },
        "ageSeconds": {
          "type": [
            "number",
            "null"
          ],
          "description": "futures / spot"
        },
        "ageMinutes": {
          "type": [
            "number",
            "null"
          ],
          "description": "PM"
        },
        "status": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "fresh",
            "lagging",
            "stale",
            "unknown",
            null
          ],
          "description": "fresh | lagging (PM only) | stale | unknown. PM lagging>=45m &\nstale>=2h; spot/futures stale>120s.\n"
        },
        "basis": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "latest_snapshot",
            "source_update",
            "processed",
            "event_update",
            "unknown"
          ],
          "description": "PM only — which timestamp the age was measured against.\n"
        }
      }
    }
  }
}