Skip to main content

Python SDK

The official Python client for the Legend API. Async-first, built on httpx.

Installation

pip install legend-prime
For signing transactions, you’ll also need eth-account:
pip install eth-account

Quick start

from legend_prime import LegendPrime

async with LegendPrime(
    query_key="qk_abc123_8f2e9a7b4c1d6e3f5a0b",
) as client:
    # Create a sub-account
    account = await client.accounts.create(
        signer_type="eoa",
        signer_address="0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
    )

    # List all accounts
    result = await client.accounts.list()
    accounts = result["accounts"]

    # Get portfolio
    folio = await client.accounts.folio(account["account_id"])

Client configuration

client = LegendPrime(
    query_key="qk_...",                          # Required: your query key
    base_url="https://prime-api.legend.xyz",               # Optional: override the API base URL
)
The client supports async context manager for automatic cleanup:
async with LegendPrime(query_key="qk_...") as client:
    # client is automatically closed when the block exits
    ...
Or manage the lifecycle manually:
client = LegendPrime(query_key="qk_...")
# ... use client ...
await client.close()

Accounts

# Create
account = await client.accounts.create(
    signer_type="eoa",
    signer_address="0x...",
)

# List all
result = await client.accounts.list()

# Get one
account = await client.accounts.get("acc_2o0yiljtp378")

# Get portfolio
folio = await client.accounts.folio("acc_2o0yiljtp378")
cached_folio = await client.accounts.folio("acc_2o0yiljtp378", cached=True)

# Activities
result = await client.accounts.activities("acc_2o0yiljtp378")
activity = await client.accounts.activity("acc_2o0yiljtp378", 1)

# Events (with long-polling)
result = await client.accounts.events("acc_2o0yiljtp378", since=0, poll=True)

Plans

Yield

# Earn (supply to protocol)
earn_plan = await client.plan.earn(
    "acc_2o0yiljtp378",
    amount="1000000",
    asset="USDC",
    network="base",
    protocol="compound",
)

# Withdraw from protocol
withdraw_plan = await client.plan.withdraw(
    "acc_2o0yiljtp378",
    amount="500000",
    asset="USDC",
    network="base",
    protocol="compound",
)

# Claim protocol rewards
claim_plan = await client.plan.claim_rewards(
    "acc_2o0yiljtp378",
    asset="COMP",
)

# Reinvest rewards (claim + swap + resupply)
reinvest_plan = await client.plan.reinvest_rewards(
    "acc_2o0yiljtp378",
    asset="USDC",
    protocol="compound",
    network="base",
    reward_assets=["COMP"],
)

Swaps

# Swap with sell amount
swap_plan = await client.plan.swap(
    "acc_2o0yiljtp378",
    sell_asset="USDC",
    buy_asset="WETH",
    network="base",
    sell_amount="10000000",
)

# Swap and supply to a protocol
zap_plan = await client.plan.swap_and_supply(
    "acc_2o0yiljtp378",
    sell_asset="WETH",
    sell_amount="1000000000000000000",
    buy_asset="USDC",
    protocol="compound",
    network="base",
)

Transfers

transfer_plan = await client.plan.transfer(
    "acc_2o0yiljtp378",
    amount="1000000",
    asset="USDC",
    network="base",
    recipient="0x...",
)

Borrowing

# Borrow
borrow_plan = await client.plan.borrow(
    "acc_2o0yiljtp378",
    amount="1000000",
    asset="USDC",
    collateral_amount="500000000000000000",
    collateral_asset="WETH",
    network="base",
    protocol="compound",
)

# Repay
repay_plan = await client.plan.repay(
    "acc_2o0yiljtp378",
    amount="1000000",
    asset="USDC",
    collateral_amount="500000000000000000",
    collateral_asset="WETH",
    network="base",
    protocol="compound",
)

Leverage

# Open/increase a leveraged long position
loop_plan = await client.plan.loop_long(
    "acc_2o0yiljtp378",
    exposure_asset="WETH",
    backing_asset="USDC",
    market_id="0xb323495f7e4148be5643a4ea4a8221eef163e4bccfdedc2a6f4696baacbc86cc",
    is_increase=True,
    exposure_amount="1000000000000000000",
    max_swap_backing_amount="5000000000",
    max_provided_backing_amount="1000000000",
    pool_fee=500,
    network="base",
)

# Close/reduce a leveraged long position
unloop_plan = await client.plan.unloop_long(
    "acc_2o0yiljtp378",
    exposure_asset="WETH",
    backing_asset="USDC",
    market_id="0xb323495f7e4148be5643a4ea4a8221eef163e4bccfdedc2a6f4696baacbc86cc",
    exposure_amount="1000000000000000000",
    backing_amount_to_exit="500000000",
    min_swap_backing_amount="490000000",
    pool_fee=500,
    network="base",
)

# Add collateral to a position
add_backing_plan = await client.plan.add_backing(
    "acc_2o0yiljtp378",
    exposure_asset="WETH",
    backing_asset="USDC",
    market_id="0xb323495f7e4148be5643a4ea4a8221eef163e4bccfdedc2a6f4696baacbc86cc",
    amount="1000000000",
    is_short=False,
    network="base",
)

# Remove collateral from a position
withdraw_backing_plan = await client.plan.withdraw_backing(
    "acc_2o0yiljtp378",
    exposure_asset="WETH",
    backing_asset="USDC",
    market_id="0xb323495f7e4148be5643a4ea4a8221eef163e4bccfdedc2a6f4696baacbc86cc",
    amount="500000000",
    is_short=False,
    network="base",
)

Migration

# Migrate a supply position between protocols
migrate_plan = await client.plan.migrate(
    "acc_2o0yiljtp378",
    amount="1000000",
    asset="USDC",
    from_protocol="compound",
    to_protocol="aave",
    network="base",
)

Sign and execute

from eth_account import Account

signer = Account.from_key(private_key)
digest = earn_plan["details"]["eip712_data"]["digest"]
sig = signer.unsafe_sign_hash(bytes.fromhex(digest[2:]))
signature = "0x" + sig.signature.hex()

result = await client.plan.execute(
    "acc_2o0yiljtp378",
    plan_id=earn_plan["plan_id"],
    signature=signature,
)

Reference data

# Get your Prime Account info
me = await client.prime_account()

# List supported networks
result = await client.networks()

# List supported assets
result = await client.assets()

Error handling

from legend_prime import LegendPrime, LegendPrimeError

try:
    await client.accounts.get("acc_nonexistent")
except LegendPrimeError as e:
    print(e.code)     # "account_not_found"
    print(e.message)  # "Account not found"
    print(e.status)   # 404