sdk or react

connect-sdk is the framework-neutral client — typed reads over HTTP plus one multiplexed WebSocket. connect-react is that, as hooks, plus the checkout drawer. Reach for react unless you can't.

Two clients, one wire.

@prophecy-dev/connect-sdk

The framework-neutral client. Typed reads over HTTP (cached), and realtime subscriptions over one multiplexed WebSocket — not a socket per subscription.

const client = new ConnectClient({ baseUrl: 'https://api.prophecyhosting.com' })
const { holders } = await client.markets.holders(id, { limit: 15 })

Use it directly when you’re not on React: a server route, a bot, a Svelte or Vue venue, a native app via a thin bridge.

@prophecy-dev/connect-react

The same client as hooks — useEvents, useOdds, useActivity, useSearch, useLiveStats, useLeaderboard, useWallet, usePositions, useResolution — plus the parts you should not rebuild:

  • <ConnectProvider> — one client, one socket, shared by every hook beneath it.
  • The {c} Checkout — the trade confirm surface, including the gasless path.
  • Live-trade animation<LiveTrades> / <TradePulse>, sharing one subscription.
  • The claim surface<WalletBalance> puts “Claim 42 PST” in the space the balance already occupies; <ClaimSheet> is the drawer behind it. A venue with its own claim page passes claim={{ href }} and we link there instead.

<ProphecyConfirm/> is required, and it is easy to miss

Mount it once, anywhere inside <ProphecyProvider>:

<ProphecyProvider …>
  {children}
  <ProphecyConfirm />
</ProphecyProvider>

useConfirm().confirm() only queues a request — <ProphecyConfirm/> is what renders it and settles the promise. Without one, any surface that awaits a confirm waits forever. That covers market creation and claiming: <ClaimSheet> hides its claim button when no confirm is mounted rather than offering an action that could never complete, and warns in dev saying so. If a claim button is missing on a wallet that clearly has winnings, this is the first thing to check.

Reach for this by default. The hooks handle subscription lifecycle, refresh intervals and deduplication, which is most of what you’d otherwise write twice.

What else ships in the box

Shipped across 1.13–1.18 and easy to miss, so listed with the one thing about each that stops you building it twice. Every signature below was read from the source, not remembered.

Claiming — a wallet’s settled winnings, and the way to take them.

client.wallets.claimable(address) every settled condition still holding redeemable tokens, with payout and why: kind ('winnings' / 'refund'), winningOutcomes, outcomeLabels. Not positions() filtered by resolution — that read is the trade fold, which never learns about a redeem.
useClaimable(wallet) the same, as claims / total / winnings / refunds / loading / error / refetch / clear. error is deliberately separate from an empty list.
buildRedeemPlan({ reader, claims, owner }) the calls, grouped: the ERC-1155 approval alone first, then every redeem batched. Hand it to useConfirm’s send.
predictor.redeem({ claims }) the same action, sent for you — for a one-tap surface rather than a confirm-first one.

A void refunds down the same path as a win, so both arrive in one list. Word a refund as a refund: kind is decided server-side precisely so the wrong wording takes deliberate effort.

Prefetching claims on a server render? Seed from wallets.claimablePending, not wallets.claimable — on the client and on createReadClient() from @prophecy-dev/connect-sdk/server (added in connect-sdk@1.44.0). They are two different reads, and only the first one matches what useClaimable puts in the cache:

wallets.claimable(address) the raw wire answer, { wallet, claimable }, edge-cached for a few seconds after a redeem.
wallets.claimablePending(address) the same rows as a bare Claimable[], with anything just claimed through this client filtered out. What useClaimable fetches.

Seed publicKeys.claimable(wallet) from the raw one and the hook never finds it — the shapes differ, so it looks up an entry nobody wrote. It fails safe (no seed, never a wrong seed), so the only symptom is a claim panel that flashes its skeleton on a page that was supposed to arrive warm, which is exactly the kind of thing nobody reports.

Overlays<ProphecyModal>, plus useModalBehaviour, useEscape, useSwipeToDismiss and focusablesIn. Portals to document.body (a transform on any ancestor otherwise becomes the containing block for position: fixed and clips the sheet), with aria-modal, Escape, a focus trap and focus restore. keepMounted keeps a closed overlay in the DOM for surfaces that animate out. Building your own floating surface? Use this rather than rediscovering the four defects it fixes.

Community — comments, takes, rooms, profiles and moderation. The full map, with which piece goes on which screen and the server rules behind them, is Comments & feeds. In brief:

  • Components: <Comments>, <Feed>, <TakeCard>, <StanceChip>, <TakePrompt>.
  • Reads: useComments, useFeed (with signals, threads, labels), useForYou, useAuthorTakes + takeReceipt, useTakeCounts, useRoomMembership, useRoomBoard.
  • Writes: usePostActions (create / edit / remove / react / report), useTail, useCanPost, useBlock.
  • Moderation: useModerationQueue, useModerate.

<Comments> takes viewer — the signed-in wallet, which gates edit/delete. Omit it and neither is drawn, because guessing puts a Delete button on somebody else’s writing. The composed screens (<MarketComments>, <CommunityTakes>, <RoomFeed>, <ModerationQueue>) are in venue-kit.

The market clockuseMarketClock(market) returns the phase and time remaining as a value that changes, on a shared tick, with a tier (urgent / soon / later / none) graded once and both thresholds overridable. formatMarketClock(clock) gives the label. Use them instead of formatting closesAt yourself: a countdown that never re-renders is how a closed market keeps looking open.

autoConfirm on a ConfirmRequest — for when your own surface was the confirmation. The drawer starts working instead of asking again, and still runs the sponsorship gate, the step progress and the decoded revert. It changes who asks, never whether the gate runs.

Choosing

You are… Use
A React venue connect-react
A React venue that also needs a one-off read outside a component both — connect-react wraps connect-sdk, and the client is available to you
Not React connect-sdk
Rendering markets on a server connect-sdk

One socket, one auth

Two independent ConnectAuth instances will race — each mints its own session, and writes land on whichever won. Create one and hand it to both providers. The Login & Session page shows the wiring a venue should copy.