> ## Documentation Index
> Fetch the complete documentation index at: https://docs.legend.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Go from zero to earning yield in 5 minutes

# Quickstart

This guide walks you through creating an account and earning yield on Compound — the most common integration flow. By the end, you'll have a working sub-account earning USDC yield on Base.

## Prerequisites

* A Legend Prime Account with a query key (contact us to get set up)
* Node.js 18+ or Python 3.9+

## 1. Install the SDK

<CodeGroup>
  ```bash TypeScript theme={null}
  npm install legend-prime viem
  ```

  ```bash Python theme={null}
  pip install legend-prime eth-account
  ```

  ```toml Rust theme={null}
  # Cargo.toml
  [dependencies]
  legend-client = "0.1"
  legend-signer = "0.1"
  tokio = { version = "1", features = ["full"] }
  ```
</CodeGroup>

## 2. Generate a signer key

Each sub-account needs a signer — an Ethereum key that authorizes fund movements. For this quickstart, we'll generate a fresh EOA key:

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";

  const privateKey = generatePrivateKey();
  const signer = privateKeyToAccount(privateKey);

  console.log("Private key:", privateKey);       // Save this securely!
  console.log("Signer address:", signer.address);
  ```

  ```python Python theme={null}
  from eth_account import Account

  signer = Account.create()

  print(f"Private key: {signer.key.hex()}")    # Save this securely!
  print(f"Signer address: {signer.address}")
  ```

  ```rust Rust theme={null}
  use legend_signer::{FileSigner, Signer};
  use std::path::Path;

  let signer = FileSigner::generate(Path::new("key.pem"))?;
  println!("Public key: {}", signer.public_key_hex());
  ```
</CodeGroup>

<Warning>
  Save the private key. You'll need it to sign every transaction for this account. If you lose it, funds in the account can't be moved.
</Warning>

## 3. Initialize the client

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { LegendPrime } from "legend-prime";

  const client = new LegendPrime({
    queryKey: process.env.LEGEND_QUERY_KEY,
  });
  ```

  ```python Python theme={null}
  from legend_prime import LegendPrime

  client = LegendPrime(
      query_key=os.environ["LEGEND_QUERY_KEY"],
  )
  ```

  ```rust Rust theme={null}
  use legend_client::{LegendPrime, Config};

  let client = LegendPrime::new(Config {
      query_key: std::env::var("LEGEND_QUERY_KEY").unwrap(),
      base_url: None,
  });
  ```
</CodeGroup>

## 4. Create a sub-account

Pass the signer's address to create a sub-account. Legend creates a **Quark Wallet** — an on-chain smart wallet — for the account.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://prime-api.legend.xyz/accounts \
    -H "Authorization: Bearer $LEGEND_QUERY_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "signer_type": "eoa",
      "signer_address": "'$SIGNER_ADDRESS'"
    }'
  ```

  ```typescript TypeScript theme={null}
  const account = await client.accounts.create({
    signerType: "eoa",
    signerAddress: signer.address,
  });

  console.log(account.account_id);           // "acc_2o0yiljtp378"
  console.log(account.legend_wallet_address); // "0xc408...642f"
  ```

  ```python Python theme={null}
  account = await client.accounts.create(
      signer_type="eoa",
      signer_address=signer.address,
  )

  print(account["account_id"])           # "acc_2o0yiljtp378"
  print(account["legend_wallet_address"]) # "0xc408...642f"
  ```

  ```rust Rust theme={null}
  use legend_client::CreateAccountParams;

  let account = client.accounts.create(&CreateAccountParams {
      signer_type: "eoa".into(),
      ethereum_signer_address: Some(signer_address.into()),
      ..Default::default()
  }).await?;

  println!("{}", account.account_id);
  println!("{}", account.legend_wallet_address);
  ```
</CodeGroup>

The response includes two addresses:

* **`signer_address`** — Your signing key's address (what you generated in step 2)
* **`legend_wallet_address`** — The on-chain smart wallet Legend created for this account

These are different. The wallet address is where funds live.

<Warning>
  **Fund the wallet, not the signer.** To use this account, send assets to the `legend_wallet_address` on a supported network (Base, Ethereum Mainnet, Arbitrum, or Optimism). This is mainnet — start with a small amount (e.g., 1 USDC) to test your integration.
</Warning>

## 5. Create an earn plan

Once the wallet is funded, create a plan. Legend generates the on-chain transaction details and returns an EIP-712 digest for signing.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://prime-api.legend.xyz/accounts/$ACCOUNT_ID/plan/earn \
    -H "Authorization: Bearer $LEGEND_QUERY_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "amount": "1000000",
      "asset": "USDC",
      "network": "base",
      "protocol": "compound"
    }'
  ```

  ```typescript TypeScript theme={null}
  const plan = await client.plan.earn(account.account_id, {
    amount: "1000000",   // 1 USDC (6 decimals)
    asset: "USDC",
    network: "base",
    protocol: "compound",
  });
  ```

  ```python Python theme={null}
  plan = await client.plan.earn(
      account["account_id"],
      amount="1000000",   # 1 USDC (6 decimals)
      asset="USDC",
      network="base",
      protocol="compound",
  )
  ```

  ```rust Rust theme={null}
  use legend_client::EarnParams;

  let plan = client.plan.earn(&account.account_id, &EarnParams {
      amount: "1000000".into(),   // 1 USDC (6 decimals)
      asset: "USDC".into(),
      network: "base".into(),
      protocol: "compound".into(),
      market: None,
  }).await?;
  ```
</CodeGroup>

<Note>
  Plans expire after 2 minutes. Sign and execute before `expires_at` or create a new plan.
</Note>

## 6. Sign the plan

The signer approves the plan by signing the EIP-712 digest. This happens locally — the private key never leaves your infrastructure.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const digest = plan.details.eip712_data.digest;
  const signature = await signer.sign({ hash: digest });
  ```

  ```python Python theme={null}
  digest = plan["details"]["eip712_data"]["digest"]
  sig = signer.unsafe_sign_hash(bytes.fromhex(digest[2:]))
  signature = "0x" + sig.signature.hex()
  ```

  ```rust Rust theme={null}
  let digest = plan.digest().expect("Plan missing digest");
  // Sign with legend-signer or your own EIP-712 signer
  ```
</CodeGroup>

## 7. Execute the plan

Send the signature back to Legend. This triggers the on-chain transaction.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://prime-api.legend.xyz/accounts/$ACCOUNT_ID/plan/execute \
    -H "Authorization: Bearer $LEGEND_QUERY_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "plan_id": "'"$PLAN_ID"'",
      "signature": "'"$SIGNATURE"'"
    }'
  ```

  ```typescript TypeScript theme={null}
  const result = await client.plan.execute(account.account_id, {
    planId: plan.plan_id,
    signature,
  });

  console.log(result.status); // "executing"
  ```

  ```python Python theme={null}
  result = await client.plan.execute(
      account["account_id"],
      plan_id=plan["plan_id"],
      signature=signature,
  )

  print(result["status"])  # "executing"
  ```

  ```rust Rust theme={null}
  use legend_client::ExecuteParams;

  let result = client.plan.execute(&account.account_id, &ExecuteParams {
      plan_id: plan.plan_id.clone(),
      signature: signature.into(),
  }).await?;
  ```
</CodeGroup>

## 8. Verify the result

Poll the activities endpoint to confirm the transaction landed.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://prime-api.legend.xyz/accounts/$ACCOUNT_ID/activities \
    -H "Authorization: Bearer $LEGEND_QUERY_KEY"
  ```

  ```typescript TypeScript theme={null}
  const { activities } = await client.accounts.activities(account.account_id);

  console.log(activities[0].activity_status); // "pending" → "confirmed"
  ```

  ```python Python theme={null}
  res = await client.accounts.activities(account["account_id"])

  print(res["activities"][0]["activity_status"])  # "pending" → "confirmed"
  ```

  ```rust Rust theme={null}
  let activities = client.accounts.activities(&account.account_id).await?;
  ```
</CodeGroup>

<Tip>
  For real-time updates instead of polling, use the [events endpoint](/api-reference/get-events) with `poll=true` for long-polling.
</Tip>

## Full example

Here's the complete flow in one script:

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { LegendPrime } from "legend-prime";
  import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";

  const client = new LegendPrime({
    queryKey: process.env.LEGEND_QUERY_KEY,
  });

  // 1. Generate a signer
  const privateKey = process.env.SIGNER_PRIVATE_KEY as `0x${string}` ?? generatePrivateKey();
  const signer = privateKeyToAccount(privateKey);

  // 2. Create account
  const account = await client.accounts.create({
    signerType: "eoa",
    signerAddress: signer.address,
  });

  // 3. Fund account.legend_wallet_address with USDC on Base, then...

  // 4. Create earn plan
  const plan = await client.plan.earn(account.account_id, {
    amount: "1000000",
    asset: "USDC",
    network: "base",
    protocol: "compound",
  });

  // 5. Sign
  const signature = await signer.sign({
    hash: plan.details.eip712_data.digest,
  });

  // 6. Execute
  await client.plan.execute(account.account_id, {
    planId: plan.plan_id,
    signature,
  });

  // 7. Poll for confirmation
  for (let i = 0; i < 30; i++) {
    const { activities } = await client.accounts.activities(account.account_id);
    if (activities.length > 0 && activities[0].activity_status === "confirmed") {
      console.log("Transaction confirmed!");
      break;
    }
    await new Promise((r) => setTimeout(r, 2000));
  }
  ```

  ```python Python theme={null}
  import asyncio
  import os
  from eth_account import Account
  from legend_prime import LegendPrime

  async def main():
      async with LegendPrime(
          query_key=os.environ["LEGEND_QUERY_KEY"],
      ) as client:
          # 1. Generate a signer
          signer = Account.from_key(os.environ.get("SIGNER_PRIVATE_KEY") or Account.create().key)

          # 2. Create account
          account = await client.accounts.create(
              signer_type="eoa",
              signer_address=signer.address,
          )

          # 3. Fund account["legend_wallet_address"] with USDC on Base, then...

          # 4. Create earn plan
          plan = await client.plan.earn(
              account["account_id"],
              amount="1000000",
              asset="USDC",
              network="base",
              protocol="compound",
          )

          # 5. Sign
          digest = plan["details"]["eip712_data"]["digest"]
          sig = signer.unsafe_sign_hash(bytes.fromhex(digest[2:]))
          signature = "0x" + sig.signature.hex()

          # 6. Execute
          await client.plan.execute(
              account["account_id"],
              plan_id=plan["plan_id"],
              signature=signature,
          )

          # 7. Poll for confirmation
          for _ in range(30):
              res = await client.accounts.activities(account["account_id"])
              if res["activities"] and res["activities"][0]["activity_status"] == "confirmed":
                  print("Transaction confirmed!")
                  break
              await asyncio.sleep(2)

  asyncio.run(main())
  ```

  ```rust Rust theme={null}
  use legend_client::{LegendPrime, Config, CreateAccountParams, EarnParams, ExecuteParams};
  use legend_signer::{FileSigner, Signer};
  use std::path::Path;

  #[tokio::main]
  async fn main() -> anyhow::Result<()> {
      let client = LegendPrime::new(Config {
          query_key: std::env::var("LEGEND_QUERY_KEY").unwrap(),
          base_url: None,
      });

      // 1. Generate a signer (or load existing)
      let signer = FileSigner::generate(Path::new("key.pem"))?;

      // 2. Create account
      let account = client.accounts.create(&CreateAccountParams {
          signer_type: "eoa".into(),
          ethereum_signer_address: Some(signer.public_key_hex()),
          ..Default::default()
      }).await?;

      // 3. Fund account.legend_wallet_address with USDC on Base, then...

      // 4. Create earn plan
      let plan = client.plan.earn(&account.account_id, &EarnParams {
          amount: "1000000".into(),
          asset: "USDC".into(),
          network: "base".into(),
          protocol: "compound".into(),
          market: None,
      }).await?;

      // 5. Sign
      let digest = plan.digest().expect("Plan missing digest");
      // Sign with legend-signer or your own EIP-712 signer
      let signature = "0x..."; // your signature here

      // 6. Execute
      client.plan.execute(&account.account_id, &ExecuteParams {
          plan_id: plan.plan_id.clone(),
          signature: signature.into(),
      }).await?;

      // 7. Poll for confirmation
      for _ in 0..30 {
          let activities = client.accounts.activities(&account.account_id).await?;
          if !activities.is_empty() {
              println!("Transaction confirmed!");
              break;
          }
          tokio::time::sleep(std::time::Duration::from_secs(2)).await;
      }

      Ok(())
  }
  ```
</CodeGroup>

## Next steps

* [Withdraw funds](/guides/withdraw) from a DeFi position
* [Transfer assets](/guides/transfer) to another wallet
* [Monitor activities](/guides/monitoring) with events and long-polling
* [API Reference](/api-reference/prime-account) for all available endpoints
