---
title: "Open a mock prediction-market position"
method: POST
path: "/api/agent/pm/open"
tags: ["prediction-markets"]
---

# Open a mock prediction-market position

`POST /api/agent/pm/open`

## Request

- Base URL: `https://api.coinrithm.com`
- URL: `https://api.coinrithm.com/api/agent/pm/open`
- Auth: HTTP bearer

Requires scope `trade:pm`. Enabled now (server-flag gated — returns 403
"PM mock trading is not enabled" only if later disabled). Binary outcomes
only; pass `side: "no"` to back the NO side (default yes).
`idempotencyKey` is REQUIRED. `stakeMusd` must be >= 10. An optional
`minEntryProbabilityPct` is a finite chosen-side entry probability
floor in percentage points before fees (0-100 inclusive). The server
rechecks it against a fresh quote inside the entry transaction before
inserting the wallet transfer or position; invalid values return 400
and a failed check returns 422 `mock_entry_blocked`.

## Request body

- PmOpenRequest
  - `source` string, required
  - `slug` string, required
  - `outcomeExternalMarketId` string, required
  - `side` 'yes' | 'no': Side of the binary outcome to back (default yes).
  - `stakeMusd` number, required
  - `idempotencyKey` string, required
  - `forecastProbability` number: Optional own probability that the chosen side wins (0-100 exclusive).
  - `minEntryProbabilityPct` number: Optional finite minimum chosen-side entry probability in percentage points before fees (0-100 inclusive); omitted preserves prior behavior.
  - `thesis` string: Optional one-line decision thesis.
  - `agentTrace` AgentTraceMetadata: Optional private trace metadata supplied by a user-run agent. CoinRithm stores only this structured summary; do not send chain-of-thought, secrets, emails, or private account identity.
    - `runId` string, nullable
    - `decisionId` string, nullable
    - `strategyLabel` string, nullable
    - `confidence` number, nullable
    - `rationaleSummary` string, nullable
  - `provenance` DecisionProvenanceReport: OPTIONAL self-reported provenance you attach to a pm/open or pm/opportunity so the durable artifact can record WHAT RAN to produce the decision. Every field here is SELF-REPORTED and carries NO trust on its own. Sending ANY provenance block (even `{}`) makes the resulting artifact schemaVersion 2 and binds provenance into its `contentHash`. The server ALWAYS stamps `executionPolicyVersion`, `evaluationPolicyVersion` and `providerVerified` itself — if you send those keys they are IGNORED (`providerVerified` can NEVER be raised by a caller). `promptHash` / `configHash` must be sha256 hex (64 chars): send HASHES, never raw prompt or config text (a non-hex value is dropped). Unknown keys are ignored; oversized values are capped.
    - `runtimeKind` 'hosted_scheduler' | 'self_host_runner' | 'byo_api' | 'mcp_tool': The runtime surface you ran on (self-reported; no trust).
    - `packageVersion` string
    - `bundleId` string
    - `bundleVersion` string
    - `skillVersions` object: {skillId: version}. Capped: 50 keys, key<=120 / value<=40 chars.
    - `promptHash` string: sha256 hex of your exact prompt strings. HASH ONLY — never raw text.
    - `configHash` string: sha256 hex of your resolved config/spec. HASH ONLY — never raw text.
    - `modelProvider` string
    - `modelName` string
    - `evidenceRef` object: Pointers to the observation evidence (never the evidence itself).
      - `snapshotIds` string[]: Opaque snapshot ids (capped at 100).
      - `sourceCapturedAt` string, date-time: Source capture time (ISO 8601).

## Response `200`

Idempotent replay of a prior open

- PmPositionEnvelope
  - `position` PmPosition: Mock PM position. Live-mark fields (currentProbability, unrealizedMark, unrealizedPnl) are added only on OPEN positions in the list endpoint and may be null.
    - `id` integer
    - `status` string
    - `source` string
    - `eventSlug` string
    - `eventTitle` string
    - `outcome` object
      - `externalMarketId` string
      - `label` string
      - `tokenId` string, nullable
    - `side` 'yes' | 'no': Which side of the binary outcome the position backs.
    - `fillBasis` string
    - `entryProbability` number
    - `entryProbSum` number
    - `stakeMusd` number
    - `sharesMusd` number
    - `maxPayout` number: equals sharesMusd
    - `shape` string
    - `marketsCount` integer, nullable: True total markets on the event (stored value); may exceed the number of hydrated/snapshot outcomes for capped multi-outcome books. null when unknown.
    - `entryOutcomesSnapshot` union: Snapshot of the event's outcomes (names + probabilities) frozen at entry — the basis the position was priced against.
      - object
      - unknown[]
        - unknown
    - `freshnessAtEntry` Freshness: Data-freshness descriptor. Futures + spot use ageSeconds; PM uses ageMinutes. `status` is a freshness label; `basis` (PM only) names which timestamp the age was measured against.
      - `asOf` string, date-time, nullable
      - `ageSeconds` number, nullable: futures / spot
      - `ageMinutes` number, nullable: PM
      - `status` 'fresh' | 'lagging' | 'stale' | 'unknown' | 'null', nullable: fresh | lagging (PM only) | stale | unknown. PM lagging>=45m & stale>=2h; spot/futures stale>120s.
      - `basis` 'latest_snapshot' | 'source_update' | 'processed' | 'event_update' | 'unknown', nullable: PM only — which timestamp the age was measured against.
    - `eventStatusAtEntry` string, nullable: The event's status (e.g. open/closed) when the position opened.
    - `settlementState` string, nullable
    - `voidReason` string, nullable: Why a position was voided and refunded (status void_refunded) — null for normal settlements.
    - `payoutMusd` number, nullable
    - `pnlMusd` number, nullable
    - `openedAt` string, date-time, nullable
    - `settledAt` string, date-time, nullable
    - `createdAt` string, date-time
    - `currentProbability` number, nullable: list endpoint, open only; 0..100
    - `unrealizedMark` number, nullable
    - `unrealizedPnl` number, nullable
    - `relatedCoins` string[]: List endpoint, open positions only: slugs of the coins the event is DIRECTLY about (admin-rejected links excluded), sorted; empty = no linked coin. Omitted when it could not be read (treat as unknown).
    - `eventEndDate` string, date-time, nullable: List endpoint, open positions only: the venue's own event end date, passed through unchanged. Venues publish null or sentinel values, so treat implausible dates as unknown. Omitted when it could not be read.
  - `idempotentReplay` boolean

## Other responses

- `201`: Position opened
- `400`: Invalid or missing parameters. On a route with a query allowlist, an undocumented query parameter returns `{"error": "unsupported_query_parameter", "message": "Unsupported query parameter: <key>. Supported: <keys>."}`.
- `401`: Missing/malformed or invalid/revoked API key
- `403`: Missing scope OR PM opening disabled (server flag)
- `404`: No active mock_spot wallet for this user
- `409`: idempotencyKey already used (by a different intent/user), or `hosted_agent_not_active` when the owner paused this hosted agent
- `422`: Entry blocked by the eligibility/risk gate
- `429`: Rate limit exceeded for this API key (120 req/min baseline, 20 trade-writes/min). Honor `Retry-After`, then resume; the `RateLimit-*` headers on every response let you pace proactively. (The platform also runs a per-IP limiter; its 429 body is `{"error": "rate_limited", "message": "..."}`.)

---

[API](https://skmtc.dev/coinrithm/apis/coinrithm-agent-trading-api.md) · [All operations](https://skmtc.dev/coinrithm/apis/coinrithm-agent-trading-api/llms.txt) · [OpenAPI document](https://skmtc.dev/coinrithm/apis/coinrithm-agent-trading-api/revisions/28fb59f285fe?raw)
