OpenPoly logo
Operator Api

Private market requests

Submit and inspect staff-authenticated requests for operator-underwritten private markets.

Private market requests

This page describes the current repository API contract, not confirmation that private markets are enabled in your environment. Confirm private-market requests and underwriting-attribution availability with Polynion Support before using this workflow.

All endpoints require a staff-session bearer token. Operator API keys, including * keys, cannot call them. Operator identity and requesting staff identity are derived from the session; do not send operatorId or operator_id.

Method and pathRequired scopeResponse
GET /api/operator/market-requestsmarkets:read{ requests, total, page, pageSize, totalPages }
GET /api/operator/market-requests/optionsmarkets:read{ categories, tags }
GET /api/operator/market-requests/{id}markets:read{ request }
POST /api/operator/market-requestsmarkets:write{ ok: true, requestId }

There is no operator approve, reject, edit, or cancel route. Submission creates a pending request, not a live market. Provider review is a separate authorization boundary.

List and detail

List accepts only these query parameters; unknown keys are rejected:

ParameterValues/default
statusOptional pending, approved, or rejected; omission includes all.
pagePositive canonical decimal integer; default 1, maximum 2147483647.
pageSizePositive canonical decimal integer; default 20, maximum 100. This is camelCase, not page_size.

Invalid pagination is rejected rather than silently defaulted/capped; page and offset must fit safe integer arithmetic. Requests are ordered by createdAt descending, then ID descending. totalPages is at least 1. IDs for detail are positive canonical decimal integers within the database integer range.

Request objects use camelCase:

  • id, operatorId, operatorName, operatorSlug;
  • draft (the normalized submission below), status;
  • createdByAdminUserId, nullable reviewedByAdminUserId and reviewReason;
  • nullable marketId and marketSlug (populated after approval);
  • ISO timestamp createdAt and nullable reviewedAt.

Read routes use Cache-Control: private, no-store. A missing or other-operator request returns 404 MARKET_REQUEST_NOT_FOUND.

Options

GET /api/operator/market-requests/options returns categories and tags, each containing { id, name, slug } objects. Tags are active tags ordered by name. Use the returned taxonomy IDs; submission and approval recheck that the selected category and every tag are active. The options endpoint does not return an underwriting quote or promise approval.

Submission

{
  "riskAccepted": true,
  "draft": {
    "title": "Will the published event meet this condition?",
    "description": "Resolve YES only if the named source confirms the condition by the deadline; otherwise resolve NO.",
    "resolverLabel": "Official results",
    "resolverUrl": "https://example.com/results",
    "categoryId": 1,
    "tagIds": [],
    "initialYesPriceBps": 5000,
    "marketDepthShares": 100,
    "openAt": "2027-01-01T00:00:00.000Z",
    "tradingCutoffTs": "2027-01-02T00:00:00.000Z",
    "resolveDeadlineTs": "2027-01-03T00:00:00.000Z"
  }
}

The example's dates and category are illustrative: use future dates within your operator's configured resolution horizon and a currently active category. Both the top-level object and draft are strict; unknown properties return 400 INVALID_MARKET_REQUEST.

FieldRequirement and limits
riskAcceptedRequired literal true: explicit acceptance of operator underwriting responsibility.
draft.titleRequired trimmed text, 1–255 characters.
draft.descriptionRequired trimmed text, 1–10000 characters; include objective resolution criteria.
draft.resolverLabelRequired trimmed text, 1–100 characters; no commas.
draft.resolverUrlRequired HTTP(S) URL, maximum 512 characters; no embedded username/password or commas. A LiveScore locale path, when present, must be English (en).
draft.categoryIdRequired active positive integer category ID.
draft.tagIdsRequired array, possibly empty; at most 100 unique active positive integer tag IDs.
draft.initialYesPriceBpsRequired integer 100..9900; 10000 represents 100%.
draft.marketDepthSharesRequired integer 50..500 whole shares, not micro-shares or currency.
draft.imageUrlOptional HTTP(S) URL, maximum 512 characters, without embedded credentials.
draft.yesLabel, draft.noLabelOptional trimmed nonempty labels, maximum 32 characters each.
draft.openAt, draft.tradingCutoffTs, draft.resolveDeadlineTsRequired UTC ISO timestamps ending in Z, with seconds and optional 1–3 fractional digits. All must be future dates; openAt < tradingCutoffTs <= resolveDeadlineTs.

Category/tag IDs must also fit the database integer range (1..2147483647). Where a maximum market duration is configured, the resolution deadline must be strictly earlier than current time plus that duration. The server checks dates again during approval; a pending request can become too old to publish. Resubmit with suitable dates through the agreed review process rather than assuming acceptance freezes the schedule.

Private-market and money semantics

Approval associates the published market with the owning operator and adds an allow visibility rule. Ownership is immutable and is not overridden by another operator's visibility configuration. Private markets are not public-channel markets and cannot be made visible to another operator by sharing a market ID. Ordinary geo and resolution-horizon eligibility still apply.

The owning operator retains 100% of principal gains or losses and winning-share payout obligations for its private markets. Existing trade-fee allocation percentages remain unchanged. marketDepthShares and initial price are market configuration, not a payment or deposit instruction. Use Opinion Settlement Reports for total versus operator-underwritten principal/payout attribution; do not treat all reported principal as Polynion economics.

Failures

  • 403 STAFF_SESSION_REQUIRED: use a staff session, not an API key; required scopes are checked separately.
  • 403 INSUFFICIENT_SCOPE: staff lacks markets:read or markets:write for the route.
  • 400 INVALID_MARKET_REQUEST: invalid/unknown fields, IDs, pagination, date ordering, operator selectors, or configured horizon.
  • 400 INVALID_CATEGORY / INVALID_TAGS: taxonomy is invalid or inactive.
  • 404 MARKET_REQUEST_NOT_FOUND: missing or inaccessible request.
  • 409 OPERATOR_NOT_ACTIVE: operator became inactive during processing.
  • 500 MARKET_REQUEST_UNAVAILABLE: operation could not complete; check the request list before resubmitting after an ambiguous response.

No idempotency key is accepted by the creation route. Repeating a successful POST can create another pending request.

Copyright © 2026