Trading

Claim winnings

Find settled positions that need a claim, call POST /execution/redeem, and track the result

Some venues pay a settled position on their own. Others need a claim, and sufwan-local-test makes that claim for you by default. POST /execution/redeem claims the user's managed positions as USDC on demand. It needs no wallet prompt.

Automatic or manual, by venue

VenueClaim
Polymarket, Limitless, Predict, MyriadAutomatic by default: sufwan-local-test claims managed winning positions about 2 minutes after the market resolves. If you turn auto-redeem off, call POST /execution/redeem.
Kalshi, Hyperliquid, BetDEX, TipRun, PREDAutomatic. No call.
ProphetX direct accountsAutomatic, in the user's own ProphetX account.
Novig, ProphetX clearinghouseNo claim through sufwan-local-test. The call returns ineligible.

Self-custody positions on Polymarket, Limitless, Predict and Myriad are redeemed with redeemSelfCustody (see Self-custody). This becomes available once sufwan-local-test enables it on the platform; until then the fill is refused with quote_self_custody_redeem_unsupported. On Polymarket it works only for shares in the user's Polymarket deposit wallet. On other venues the user claims them on the venue.

Opting out of automatic claims. Automatic claiming covers Polymarket, Limitless, Predict and Myriad, and is on for every app by default. To claim on your own schedule instead, turn off Settings → Auto-redeem winning positions in the sufwan-local-test dashboard, then use the steps below. Self-custody positions are never claimed automatically.

You do not need this table at run time. Read redeemStatus on each position instead.

1. Find claimable positions

GET /execution/positions returns one group per market. Claim the groups whose redeemStatus is eligible, using the winning outcome ids in venueBreakdown.

SDK
const positions = await client.getExecutionPositions();
const outcomeIds = positions.data
  .filter((p) => p.redeemStatus === "eligible")
  .flatMap((p) => p.venueMarket.venueMarketOutcomes)
  .filter((o) => o.winner === true)
  .flatMap((o) => o.venueBreakdown.map((leg) => leg.venueMarketOutcomeId));

Get user positions

redeemStatusMeaning
eligibleClaim it.
pendingA claim is in progress. Wait.
redeemedPaid. Nothing to do.
ineligibleNothing to claim through sufwan-local-test: not settled yet, lost, settled by the venue, or self-custody.

A split or void can mark more than one outcome as a winner. Read Market resolution & voids before you show an amount.

2. Redeem

SDK
if (outcomeIds.length > 0) {
  const { redeemId, results } = await client.redeem({ venueMarketOutcomeIds: outcomeIds });
  for (const r of results) console.log(redeemId, r.venueMarketOutcomeId, r.status, r.reason);
}

Redeem winnings for resolved positions

Send x-app-id and the user's access token. Send 1 to 20 ids per call. mode (live or paper) is optional and defaults to live. Claims, paper included, are refused with 403 and code: "geo_blocked" where your app's or the platform's region list blocks the user. The check is the same for every venue.

A 4xx means no claim started. After a timeout or 5xx, some outcomes may have been submitted: they are claimed one at a time. The claim shows in GET /users/activity?type=redeem before anything is sent on-chain. Resending the same ids is safe and is how you find out. An outcome already being claimed returns rejected with redeem in progress, and one already paid returns ineligible with already redeemed. A position is never paid twice.

3. Read the result

The call returns before an on-chain claim finishes. Each results[] entry has a status and a reason:

statusMeaningWhat to do
submittedThe claim is on its way.Wait for completion (below).
confirmedDone, or nothing was owed.Nothing.
ineligibleNot claimable now. reason says why, for example market not resolved, market winner not yet available, already redeemed, or venue ... does not support redeem.Retry later only for the first two.
rejectedRefused. reason says why, for example not owned by user or unknown id, redeem in progress, or position reserved for execution.Fix the id, or retry after the other claim or sell finishes.

To see completion, read positions again until redeemStatus is redeemed, or listen for redeem_event on the WebSocket.

On this page