Creating markets
Direct creation versus hosted draft-based creation.
We want two creation paths in the public SDK:
- direct creation for explicit onchain contract parameters
- draft-based creation for the product-shaped path apps and agents should prefer
Those creation paths should be usable through two execution modes:
hostedfor session-backed managed executionlocal-walletfor self-custody agents and bots
Recommended path: drafts
The target high-level flow is:
const draft = await client.drafts.generate({
prompt: "Will we ship v2 before July 1?",
type: "parimutuel",
});
const market = await client.markets.createAndWait({
draftId: draft.id,
});That flow is where we want:
- validation
- prompt-to-market drafting
- hosted orchestration
- async job handling
- session-backed managed wallet execution
Under the hood, the default hosted request model should use:
- project API key in SDK/provider config
- the app's authenticated user session
- managed wallet execution behind the scenes
For non-interactive automation, the same draft and create APIs should also be able to sit on top of a local signer instead of a hosted session when the caller opts into self-custody mode.
Direct creation
Direct creation remains important when you want full control over the factory arguments.
const market = await client.markets.createDirect({
question: "Will the Fed cut rates at the next FOMC?",
options: ["Yes", "No"],
closeTime: new Date("2026-02-01T18:00:00Z"),
challengeWindow: "48h",
resolution: { mode: "multi", admins: [admin1, admin2, admin3], quorum: 2 },
creatorFeeBps: 200,
});The lower-level contract shape still matters, because it is the real execution layer behind the higher-level hosted flow.
CreateMarketInput
type CreateMarketInput = {
question: string; // 1–200 chars
options: string[]; // 2–8 items, each 1–50 chars
closeTime: Date | bigint | number; // Date, or unix seconds as bigint/number
challengeWindow: Duration; // "24h", "3600s", "1d", or a number of seconds
resolution:
| { mode: "single"; admin: Address }
| { mode: "multi"; admins: Address[]; quorum: number }
| { mode: "aiOracle" };
whitelistEnabled?: boolean; // default false
creatorFeeBps?: number; // 0–500, default 0
creatorFeeRecipient?: Address; // defaults to the caller
};Duration accepts strings like "24h", "30m", "7200s", "2d", or a raw number of seconds.
Resolution modes
The resolution field is a discriminated union so TypeScript enforces the right shape per mode:
// Single resolver
resolution: { mode: "single", admin: "0x..." }
// Multi-admin quorum — 2 of 3 must vote for the same option
resolution: { mode: "multi", admins: ["0x...", "0x...", "0x..."], quorum: 2 }
// AI oracle (mechanically identical to "single"; held by an off-chain service)
resolution: { mode: "aiOracle" }See resolution for the runtime flow of each.
Validation rules
The SDK forwards your inputs to the factory which reverts on:
question.lengthoutside 1–200.options.lengthoutside 2–8, or any option string outside 1–50 chars.closeTime <= block.timestamp.challengeWindowoutside 3,600–259,200 seconds (1h–72h).mode: "multi"withadmins.lengthoutside 1–5 orquorumoutside1..admins.length.creatorFeeBps + platformFeeBps > 1000.
Validate client‑side too — a failing factory call costs gas.
Hosted creation flows should validate before they ever trigger managed execution. Direct creation should still validate locally before touching the factory.
What the factory doesn't do
- Metadata. Descriptions, tags, cover images, and resolution sources live off‑chain — most hosts use Convex or a CMS. The factory stores only what the contract needs on‑chain.
- Uniqueness. Two markets with identical questions are allowed.
- Bonds. The creator pays gas; there is no capital deposit.
How this fits the future SDK
The important split is:
client.markets.createDirect(...)is contract-shapedclient.drafts.generate(...)plusclient.markets.createAndWait(...)is product-shaped
We want both, but most apps should eventually default to the second.