Connect
Venue accounts — Kalshi, Polymarket, ProphetX and the rest — get linked on one hosted, co-branded page, and never through your code. Connect is for everyone: yourself, your app's users, or your own customers who never get an OpenMarkets account.
Three ways in
The same hosted page at connect.openmarkets.ai; a different credential opens it.
| Way in | Whose venues | Credential | Needs |
|---|---|---|---|
| Yourself | your own account | Console → Connect | account:write — Pro and up |
| Through your app | your marketplace app's users, on their own accounts | install key · POST /auth/account/link-sessions | the user consented to account:link |
| For your own users | people who are yours, not OpenMarkets' — one sub-account each | org key · POST /connect/link-sessions · X-OpenMarkets-Account | connect:read / write / trade — an organization plan |
What you skip
OpenMarkets handles
- The hosted page, co-branded with your name and icon (the OpenMarkets mark always shows)
- Credential storage — encrypted at rest, tested against the venue before it is kept, never returned
- Per-venue permissions the user sets:
history:read,trade:execute,balance:read - Execution limits, pausing a venue, disconnecting — enforced server-side on every call
- Venue history sync and the settled record it produces (OM-03)
- Signed webhooks when a user connects, changes permissions, or syncs
You do
- Hand the user a link, or open the page from a button
- Read balances, positions and history through one API
- Trade on their behalf, within what they granted
- Verify the webhook and dedupe on delivery_id
Yourself
account:writeOpen the console's Connect page and choose Manage venues. It mints a self link session and sends you to the hosted page; when you come back, your linked venues, balances and permissions are on the same page. Your API key then reads and trades on your own account with no act-as header at all.
A first-party app can do the same by calling the endpoint with the person's session: POST /flow/v1/auth/account/link-sessions with Authorization: Bearer returns a hosted_url to send them to.
Through your app
account:link · install keyAdd account:link to your app's scopes. The user approves it on the consent screen; your app can then open the hosted page for them, branded with your app's name. The venues they link belong to their account, and your app reaches them only through the other scopes it holds.
const res = await fetch('https://api.openmarkets.ai/flow/v1/auth/account/link-sessions', {
method: 'POST',
headers: { 'X-API-Key': (await auth.getApiKey())!, 'Content-Type': 'application/json' },
body: JSON.stringify({ return_url: 'https://yourapp.example/settings?linked=1', mode: 'connect' }),
})
const { data } = await res.json()
window.location.assign(data.hosted_url) // 15-minute link; redirect, don't open a popup
return_urlmust be on the origin of one of your registered redirect URIs.mode:connectto add a venue,manage(the default) to review what is linked and its permissions.allowed_partnersnarrows the venues offered; omit it for all.- The response is
{ link_session_id, link_token, hosted_url, expires_at }. Any other credential — an organization key, say — is refused with403 player_required.
The rest of the app story — sign-in, scopes, notifications — is on Sign in with OpenMarkets.
For your own users
connect:read · connect:write · connect:tradeYou address every user by your own id. OpenMarkets provisions a sub-account for it on first use, keyed to your organization, and every call carries two headers: your key, and X-OpenMarkets-Account naming the user.
POST /flow/v1/connect/link-sessions
X-API-Key: om_exec_live_...
{ "external_user_id": "your-user-123",
"return_url": "https://app.yourco.com/openmarkets/done" }
→ { "hosted_url": "https://connect.openmarkets.ai/start?token=lt_live_...", "link_token": "lt_live_..." }
Your Connect flow — venue allowlist, practice-only or real money, the permissions offered, which AI providers may be linked, branding, return URLs — is configured in the console under your organization. It is snapshotted onto each session at mint, so changing it never alters a link a user already holds.
The full walk-through — minting links, the button, webhooks, reading accounts, trading — is the integration guide.
What the user controls
- Per-venue permissions.
history:read,trade:executeandbalance:readare granted per venue, per connection, on the hosted page. A venue withoutbalance:readis omitted from balance reads; a buy on a venue withouttrade:executeis refused with403 scope_not_granted, naming the venue. Your entitlement lets you act; it never overrides what the user agreed to. - Execution limits. A cap on any single order, a venue allowlist, a pause. Set on the hosted page; read-only to you at
GET /connect/users/:id/policy. - Disconnect. Removes the stored credential. The consent record is kept, frozen.
The verified record
OM-03 · record:readOnce a venue is linked, OpenMarkets syncs its history and grades it: settled wins, losses, stake, return and ROI per venue, computed from the venue's own data. A person can share exactly that — not balances, not open bets — with an app that holds record:read. Details on Sign in with OpenMarkets.
Packages
@openmarketsai/connect-node wraps every organization call (users, link sessions, webhooks, act-as reads and orders, AI Connect). @openmarketsai/connect-web opens the hosted page from a button, in a popup or a redirect, with a React binding. Neither is required — everything here is plain HTTP.