OpenPoly logo
Operator Api

Polyflight tickets

List, inspect, and export the authenticated operator's native-IDR Polyflight tickets.

Polyflight tickets

Required scopes: both polyflight:read and polyflight_terms:read. Ticket responses expose the terms version and share BPS frozen at admission.

GET /api/operator/polyflight/tickets
GET /api/operator/polyflight/tickets/{ticketId}
GET /api/operator/polyflight/tickets/export
Authorization: Bearer {operator_api_key_or_staff_session}

ticketId is a UUID. Every query is constrained to the authenticated operator; a ticket owned by another operator returns 404 POLYFLIGHT_TICKET_NOT_FOUND. Responses use Cache-Control: private, no-store.

List and export filters

QueryMeaning
gamepolyflight for Classic or polyflight-pro for Pro; omit to combine both
external_user_idExact, case-sensitive operator user ID; maximum 255 characters
date_fromTicket createdAt at or after this ISO-8601 instant
date_toTicket createdAt before this ISO-8601 instant
date_from_dateInclusive acceptance calendar date (YYYY-MM-DD) in the authenticated operator's timezone
date_to_dateInclusive acceptance calendar date (YYYY-MM-DD), ending at the next local midnight
statusComma-separated purchased, won, lost, or refunded
searchCase-insensitive substring of flightCode or externalUserId
pagePositive integer, default 1, maximum 100000
page_sizePositive integer, default 50, maximum 200

ISO date intervals are half-open. Local calendar-day bounds account for daylight saving and also constrain the query when combined with ISO bounds. Invalid calendar dates or reversed ranges return 400; the client cannot override the authenticated operator's timezone. Invalid/repeated game values return 400 INVALID_GAME. Unknown ticket statuses match no rows. search does not search ticket IDs, purchase IDs, or payment status; use the detail route for a known ticket UUID and external_user_id when an exact user match is required.

curl -sS -G \
  -H "Authorization: Bearer ${OPERATOR_API_KEY}" \
  --data-urlencode "status=won,lost" \
  --data-urlencode "search=operator-user-123" \
  --data-urlencode "page=1" \
  --data-urlencode "page_size=25" \
  "https://your-beacon-origin.example.com/api/operator/polyflight/tickets"

Representative list response

{
  "items": [
    {
      "ticketId": "018f70e4-e9c3-7d86-a84c-7ead54e42953",
      "proofTicketId": "018f70e4-f2c1-73c8-9c26-a2fd7f077a4b",
      "purchaseRequestId": "018f70e4-df31-777d-b488-c5876162727e",
      "operatorId": 42,
      "operatorUserId": 701,
      "externalUserId": "operator-user-123",
      "flightId": "018f6f8a-0c47-7af3-8ac2-6c5d9f166d85",
      "flightCode": "PF-20260817-1200-A",
      "game": "polyflight",
      "status": "won",
      "choiceKind": "abcd",
      "choiceIndex": 2,
      "predictedSequence": "1234",
      "stakeMinor": "10000",
      "feeMinor": "500",
      "netStakeMinor": "9500",
      "potentialPayoutMinor": "38000",
      "termsVersionId": "018f4f92-acde-79e3-9a11-26e38cb73582",
      "ticketFeeShareBps": 10000,
      "positionShareBps": 8000,
      "paymentEffect": "win",
      "paymentStatus": "owed",
      "paymentAmountMinor": "38000",
      "createdAt": "2026-08-17T11:57:12.000Z",
      "settledAt": "2026-08-17T12:00:03.000Z",
      "refundedAt": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 25,
  "summary": {
    "ticketCount": 1,
    "userCount": 1,
    "stakeMinor": "10000",
    "feeMinor": "500",
    "potentialPayoutMinor": "38000",
    "unpaidLiabilityMinor": "38000",
    "currencyCode": "IDR"
  }
}

summary contains ticket and distinct-user counts, stake, included fees, potential payout, and currently unpaid liability for all matching tickets, independent of pagination. Money remains exact integer decimal strings. When no tickets match, the list returns items: [], total: 0, and zero summary values. A page beyond the last match retains the matching total and summary. The detail route returns one ticket without the page envelope.

Read result and delivery separately

status is the game result:

  • purchased: admitted, but no terminal result yet;
  • won or lost: authoritative result recorded;
  • refunded: the ticket was voided and its original stake became refundable.

paymentEffect is win, loss, or refund when delivery is required. paymentStatus is independently owed, in_flight, paid, or manual_review; both fields are null when there is no obligation. Therefore status: "won" with paymentStatus: "owed" is a final win with an unpaid payout, not a pending game result. Newly settled losses expose paymentEffect: "loss" and paymentAmountMinor: "0": their lifecycle tracks a zero-amount wallet acknowledgement, not money owed or paid. The loss remains final in every delivery state and does not block flight financial settlement. Inspect linked wallet evidence in Balance operations.

The existing ticket.resolved callback includes a non-null loss-delivery obligationId for newly settled losses. No loss payout pending/processed callback is emitted; read the ticket lifecycle and loss_credit operation for delivery status. Historical losses keep their existing lifecycle values without backfilled delivery, and older planned/dispatched wallet request evidence is preserved.

game identifies Classic or Pro. proofTicketId links a private operator ticket to its anonymous Classic v5 or Pro v2 public-proof ticket; it can be null before lock-snapshot publication or for legacy tickets. A null mapping does not prove absence from a published proof. Frozen terms are historical ticket terms, not the operator's current terms.

Export

Export applies the same filters to all matching rows. It returns formula-safe CSV by default; add format=json for the canonical JSON envelope.

curl -sS -G \
  -H "Authorization: Bearer ${OPERATOR_API_KEY}" \
  --data-urlencode "status=won" \
  "https://your-beacon-origin.example.com/api/operator/polyflight/tickets/export" \
  --output polyflight-winners.csv

In the dashboard, open Polyflight → Tickets to browse tickets and search by flight code or external user ID. Both date inputs default to the last 30 calendar days including today in the operator's timezone; Reset restores that range using the current local day. Dates filter acceptance time. Change dates, ticket status, or search, then choose Apply filters; Export all filtered uses only the applied filters. Metric cards describe all matching tickets, not just the displayed page. See Terms, statements, and settlement for how frozen ticket terms enter a monthly statement.

The dashboard combines Classic and Pro and does not expose game or exact external_user_id filtering. Use the API for those slices. Ticket feeMinor and the Fees card retain quoted included fees, including refunded tickets; they are not the statement's net fee entitlement or allocated operator revenue.

The table footer shows Current page sums for stake, included ticket fees, and potential payout in IDR. The table has a bounded scroll area with sticky headers and a sticky SUM footer, so totals remain under their amount columns while scrolling through a full page. On narrow screens, scroll horizontally to the amount columns. These totals include only the displayed rows, update with pagination and applied filters, and are zero on a successful empty page. Loading and failed requests show loading/unavailable states instead of stale financial values or fabricated zeros. Totals preserve exact integer precision; potential payout is not a confirmed wallet credit, and included fees are already part of gross stake.

Playground: /api-playground/polyflight?request=polyflight-tickets.

Copyright © 2026