> For the complete documentation index, see [llms.txt](https://docs.ojolabs.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ojolabs.xyz/markets/api/programmatic-trading/claiming-winnings.md).

# Claiming Winnings

Guide for claiming winnings from resolved prediction markets using the Python SDK. All claiming operations are gasless — no native tokens required.

## Prerequisites

You need a Level 2 client (private key + API credentials):

```python
import os
from dotenv import load_dotenv
from turbine_client import TurbineClient

load_dotenv()

client = TurbineClient(
    host=os.environ["TURBINE_HOST"],
    chain_id=int(os.environ.get("CHAIN_ID", "137")),
    private_key=os.environ["TURBINE_PRIVATE_KEY"],
    api_key_id=os.environ["TURBINE_API_KEY_ID"],
    api_private_key=os.environ["TURBINE_API_PRIVATE_KEY"],
)
```

## How Claiming Works

{% stepper %}
{% step %}

### Market resolution

When a market resolves, the winning outcome (YES or NO) is determined by the UMA oracle.
{% endstep %}

{% step %}

### Redeem winning tokens

Holders of the winning token can redeem each token for $1 USDC. Losing tokens become worthless.
{% endstep %}

{% step %}

### Gasless claim via SDK

The SDK signs an EIP-712 `RedeemPositions` permit and submits it to the relayer. No native gas is needed.
{% endstep %}
{% endstepper %}

## Check Resolution Status

Before claiming, verify the market is resolved:

```python
market_id = "0x..."

resolution = client.get_resolution(market_id)
print(f"Resolved: {resolution.resolved}")

if resolution.resolved:
    outcome = "YES" if resolution.outcome == 0 else "NO"
    print(f"Winner: {outcome}")
    print(f"Assertion ID: {resolution.assertion_id}")
```

## Claim from a Single Market

`claim_winnings()` takes the market's **contract address** (not the market ID). You can find it from the `Market` object:

```python
# Get the market to find the contract address
markets = client.get_markets()
market = next(m for m in markets if m.id == market_id)

# Claim winnings
try:
    result = client.claim_winnings(
        market_contract_address=market.contract_address
    )
    print(f"Claim submitted: {result}")
except ValueError as e:
    print(f"Cannot claim: {e}")
```

The method performs these steps internally:

{% stepper %}
{% step %}

### Query on-chain state

Queries the market contract on-chain for resolution status and condition data.
{% endstep %}

{% step %}

### Check balances

Checks your balance of the winning token.
{% endstep %}

{% step %}

### Sign permit

Signs an EIP-712 `RedeemPositions` permit.
{% endstep %}

{% step %}

### Submit to relayer

Submits to the relayer for gasless execution.
{% endstep %}
{% endstepper %}

It raises `ValueError` if:

* The market is not resolved yet
* You hold no winning tokens

## Batch Claim from Multiple Markets

Claim winnings from several resolved markets in a single batch transaction:

```python
contract_addresses = [
    "0xMarket1ContractAddress...",
    "0xMarket2ContractAddress...",
    "0xMarket3ContractAddress...",
]

try:
    result = client.batch_claim_winnings(contract_addresses)
    print(f"Batch claim submitted: {result}")
except ValueError as e:
    print(f"No markets to claim: {e}")
```

Markets that are not resolved or where you have no winning tokens are skipped automatically. The method only raises `ValueError` if *none* of the markets have claimable winnings.

## Find Markets with Claimable Winnings

Scan your positions for resolved markets you can claim from:

```python
# Get all your positions
positions = client.get_user_positions(
    address=client.address,
    chain_id=client.chain_id,
)

# Get markets and check which are resolved
markets = client.get_markets(chain_id=client.chain_id)
market_map = {m.id: m for m in markets}

claimable = []
for pos in positions:
    market = market_map.get(pos.market_id)
    if not market or not market.resolved:
        continue

    # Check if we hold winning tokens
    if market.winning_outcome == 0 and pos.yes_shares > 0:
        claimable.append(market)
        print(f"Claimable: {market.question}")
        print(f"  YES shares: {pos.yes_shares / 1e6:.2f} (payout: ${pos.yes_shares / 1e6:.2f} USDC)")

    elif market.winning_outcome == 1 and pos.no_shares > 0:
        claimable.append(market)
        print(f"Claimable: {market.question}")
        print(f"  NO shares: {pos.no_shares / 1e6:.2f} (payout: ${pos.no_shares / 1e6:.2f} USDC)")

# Batch claim all
if claimable:
    addresses = [m.contract_address for m in claimable]
    result = client.batch_claim_winnings(addresses)
    print(f"\nBatch claim submitted: {result}")
else:
    print("No claimable winnings found.")
```

## Monitor Claim Status

After submitting a claim, track its progress:

```python
# Check pending claims
pending = client.get_pending_claims()
for c in pending:
    print(f"Pending: market={c.market_address} payout={c.payout / 1e6:.2f} USDC tx={c.tx_hash}")

# Check failed claims
failed = client.get_failed_claims()
for c in failed:
    print(f"Failed: market={c.market_address} payout={c.payout / 1e6:.2f} USDC tx={c.tx_hash}")
```

## CLAIM\_ONLY\_MODE

The reference bot (`examples/price_action_bot.py`) supports a claim-only mode that disables trading and only claims winnings from previously traded markets:

```bash
CLAIM_ONLY_MODE=true TURBINE_PRIVATE_KEY=0x... python examples/price_action_bot.py
```

This is useful when you want to:

* Claim winnings without placing new orders
* Clean up positions from a previous trading session
* Run a background process that periodically claims resolved markets

## Complete Example

A standalone script that discovers and claims all available winnings:

```python
import os
import time
from dotenv import load_dotenv
from turbine_client import TurbineClient

load_dotenv()

client = TurbineClient(
    host=os.environ.get("TURBINE_HOST", "https://api.turbinefi.com"),
    chain_id=int(os.environ.get("CHAIN_ID", "137")),
    private_key=os.environ["TURBINE_PRIVATE_KEY"],
    api_key_id=os.environ["TURBINE_API_KEY_ID"],
    api_private_key=os.environ["TURBINE_API_PRIVATE_KEY"],
)

print(f"Wallet: {client.address}")
print(f"Chain: {client.chain_id}")

# Get positions and markets
positions = client.get_user_positions(address=client.address, chain_id=client.chain_id)
markets = client.get_markets(chain_id=client.chain_id)
market_map = {m.id: m for m in markets}

print(f"Found {len(positions)} positions across {len(markets)} markets\n")

# Find claimable markets
to_claim = []
total_payout = 0

for pos in positions:
    market = market_map.get(pos.market_id)
    if not market or not market.resolved:
        continue

    winning_shares = 0
    if market.winning_outcome == 0:
        winning_shares = pos.yes_shares
    elif market.winning_outcome == 1:
        winning_shares = pos.no_shares

    if winning_shares > 0:
        to_claim.append(market.contract_address)
        total_payout += winning_shares
        outcome = "YES" if market.winning_outcome == 0 else "NO"
        print(f"  {market.question}")
        print(f"    Winner: {outcome} | Your payout: ${winning_shares / 1e6:.2f} USDC")

if not to_claim:
    print("No claimable winnings found.")
    exit(0)

print(f"\nTotal payout: ${total_payout / 1e6:.2f} USDC from {len(to_claim)} markets")

# Claim all
if len(to_claim) == 1:
    result = client.claim_winnings(to_claim[0])
else:
    result = client.batch_claim_winnings(to_claim)

print(f"Claim submitted: {result}")

# Wait for confirmation
print("Checking claim status...")
time.sleep(10)

pending = client.get_pending_claims()
failed = client.get_failed_claims()

print(f"Pending: {len(pending)}")
print(f"Failed: {len(failed)}")

for f in failed:
    print(f"  FAILED: {f.market_address} — tx={f.tx_hash}")
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ojolabs.xyz/markets/api/programmatic-trading/claiming-winnings.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
