Skip to content

Creating markets

An approved app can list player-prop markets on STX events. You name the event, the player, the stat and the line; STX builds the market, settles it from its stats feed, and returns one outcome for each market you asked for.

Creating markets is granted by STX, per app. It is not part of the standard ISV access.

The market creation flowTwo lanes: your app and STX. Your app requests an app token with client_credentials and the markets.write scope. It lists events to get an event_id, then gets the event's players for a player_id and the allowed stats. It posts the markets; STX checks the player, stat, half line and that the event has not started, builds each market, and answers created, exists or rejected for each one. The new markets then trade like any other.Your app (server)STX1POST /oauth/token (client_credentials, markets.write)app access token2GET /api/v1/eventsevent_id3GET /api/v1/events/{event_id}/playersplayer_id per player, allowed stats4POST /api/v1/markets (player_id, stat, line), up to 25Checks player, stat, .5 line, not startedbuilds title, rules and price rangeper market: created | exists | rejected (reason)Then: ordinary markets. Quote them with your market-making account through the orders endpoints and channels.

STX enables your app for market creation:

  • adds the markets.write app scope to your client. Only STX can grant it.
  • sets your client’s IP allow-list to your servers’ egress addresses. Every write scope requires one, and a call from any other address is refused.

Ask your STX contact to enable it on the demo exchange first.

Request an app token with the client_credentials grant, as described in Tokens and security. Send it as Authorization: Bearer <access_token> on every call below, from an allow-listed address.

GET /api/v1/events lists upcoming events. Take the event’s id. Markets can be created only while the event is scheduled and has not started.

GET /api/v1/events/{event_id}/players returns each team’s roster and the stats a market can be created on.

{
"event_id": "ee2ee8f9-4326-4e4f-841a-1bc3f598dbd9",
"teams": [
{
"team": "Utah Jazz",
"players": [
{ "player_id": "4873138", "name": "Ace Bailey", "jersey": "19", "position": "G" }
]
}
],
"stats": [
{ "stat": "POINTS", "name": "Points" },
{ "stat": "REBOUNDS", "name": "Rebounds" }
]
}
  • Rosters are the teams’ current rosters, not game-day actives, and can be up to 15 minutes old.
  • teams is empty until a roster is published. Try again later.
  • Send player_id back exactly as returned.

POST /api/v1/markets takes the event and up to 25 markets, each described by a stat_detail:

{
"event_id": "ee2ee8f9-4326-4e4f-841a-1bc3f598dbd9",
"markets": [
{ "stat_detail": { "player_id": "4873138", "stat": "POINTS", "prop_type": "ou", "line": 18.5 } },
{ "stat_detail": { "player_id": "4873138", "stat": "REBOUNDS", "prop_type": "ou", "line": 4.5 } }
]
}
Field Value
player_id From the players endpoint.
stat One of the event’s stats.
prop_type ou (over/under). Optional; ou is the only type today.
line A positive half line, such as 18.5.

The response is 200 with one outcome per market, in request order:

{
"event_id": "ee2ee8f9-4326-4e4f-841a-1bc3f598dbd9",
"markets": [
{ "status": "created", "market_id": "5766e668-b5ad-4db4-8dd1-e1b7f27d9974",
"stat_detail": { "player_id": "4873138", "stat": "POINTS", "prop_type": "ou", "line": 18.5 } },
{ "status": "exists", "market_id": "4b2b8139-7968-4a20-b760-f6751af88f06",
"stat_detail": { "player_id": "4873138", "stat": "REBOUNDS", "prop_type": "ou", "line": 4.5 } }
]
}
  • created: a new market. STX sets its title, rules and price range.
  • exists: an open market for the same player, stat and line is already on the event. Its market_id is returned and nothing new is created, so resending a request is always safe.
  • rejected: not created. reason is one of invalid_market, unsupported_market_type, unsupported_prop_type, unsupported_stat, invalid_line, unknown_player, event_not_open or not_created.

A whole request can also fail:

Status Meaning
400 Malformed body, or more than 25 markets.
401 Missing or invalid token.
403 Not an app token with markets.write, or a call from outside the IP allow-list.
404 Unknown event.
422 event_not_open, unsupported_event (no player props for this event) or roster_unavailable.

The new markets behave like any other STX market. Find them with GET /api/v1/markets and the market data channels, and quote them with your market-making account’s API key through the orders endpoints. STX settles them from its stats feed when the game ends.

@stxapp/stx-typescript 0.8.0 and later wrap these calls. createMarkets() returns the same per-market results, and validate: true checks players, stats and lines before sending (it reads the event’s players, so the token also needs events).

import { AppScopes, OAuthClient } from "@stxapp/stx-typescript/oauth";
const oauth = new OAuthClient({ clientId, clientSecret });
const stx = oauth.appClient([AppScopes.EVENTS, AppScopes.MARKETS_WRITE]);
const roster = await stx.eventPlayers(eventId);
const player = roster.teams[0].players[0];
const results = await stx.createMarkets(
eventId,
[
{ playerId: player.player_id, stat: "POINTS", line: 18.5 },
{ playerId: player.player_id, stat: "REBOUNDS", line: 4.5 },
],
{ validate: true },
);
for (const r of results) console.log(r.status, r.status === "rejected" ? r.reason : r.market_id);
v1.5.9Changelogllms.txtllms-full.txt