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

# Earn API quickstart

> Go from zero to your first attributed deposit with the Turtle Earn API.

This is the shortest path from nothing to a deposit attributed to your distributor: authenticate, register the user's wallet, find an opportunity, generate the deposit, and confirm attribution. Each step links to the full reference where the request bodies and response schemas live.

New to the Turtle API? Start with the [API overview](/sdk/overview) for access and the full product set. This page covers the Earn deposit flow specifically.

<Note>
  Every call requires the `X-API-Key` header. See [API Keys](/sdk/authentication/api-keys).
</Note>

## Prerequisites

You need three things before the first call:

1. A Turtle organization, created in the [Client Portal](https://dashboard.turtle.xyz). New organizations are approved by the Turtle team before keys are issued.
2. An **API key** (`pk_live_` for client-side, `sk_live_` for server-side). See [API Keys](/sdk/authentication/api-keys).
3. Your **distributor ID**, found under Distribution in the [Client Portal](https://dashboard.turtle.xyz).

<Note>
  If your organization has not been approved yet, reach out on [Discord](https://discord.turtle.xyz).
</Note>

## Step 1: Confirm your key works

Fetch the opportunity catalog. A `200` with a `data` array means authentication is set up.

<CodeGroup>
  ```bash curl theme={null}
  curl https://earn.turtle.xyz/v2/opportunities/ \
    -H "X-API-Key: pk_live_xxxxx"
  ```

  ```typescript TypeScript theme={null}
  const res = await fetch('https://earn.turtle.xyz/v2/opportunities/', {
    headers: { 'X-API-Key': 'pk_live_xxxxx' },
  });
  const { data, pagination } = await res.json();
  ```
</CodeGroup>

A `401` means the key is missing or wrong. See [API Keys](/sdk/authentication/api-keys) for key types, the auth header, and rate limits.

## Step 2: Register the user's wallet

Every wallet must be a Turtle member before it can deposit. Membership is a three-step EIP-4361 flow: check membership, request a sign-in message, submit the signature. The full request and response for each step is on [Register Wallet](/sdk/authentication/register-wallet).

<CodeGroup>
  ```bash curl theme={null}
  # 1. Already a member?
  curl "https://earn.turtle.xyz/v2/membership/?address=0xYOUR_WALLET&walletEcosystem=evm" \
    -H "X-API-Key: pk_live_xxxxx"

  # 2. If not, request a message, have the user sign it, and submit the signature.
  #    See Register Wallet for the agreement and create-membership request bodies.
  ```

  ```typescript TypeScript theme={null}
  // 1. Already a member?
  const { isMember } = await (
    await fetch(
      `https://earn.turtle.xyz/v2/membership/?address=${address}&walletEcosystem=evm`,
      { headers: { 'X-API-Key': 'pk_live_xxxxx' } }
    )
  ).json();

  // 2. If not, request a message, have the user sign it, and submit the signature.
  //    See Register Wallet for the agreement and create-membership request bodies.
  ```
</CodeGroup>

Pass your `distributorId` when you create the membership to attribute the signup to your integration.

## Step 3: Find an opportunity

Fetch your distributor's configured set, or browse the full catalog with filters. Each opportunity has an `id` you use in the next step.

<CodeGroup>
  ```bash curl theme={null}
  curl "https://earn.turtle.xyz/v2/opportunities/distributors/YOUR_DISTRIBUTOR_ID" \
    -H "X-API-Key: pk_live_xxxxx"
  ```

  ```typescript TypeScript theme={null}
  const { data } = await (
    await fetch(
      `https://earn.turtle.xyz/v2/opportunities/distributors/${distributorId}`,
      { headers: { 'X-API-Key': 'pk_live_xxxxx' } }
    )
  ).json();

  const opportunity = data[0];
  ```
</CodeGroup>

See [Opportunities](/sdk/opportunities/get-opportunities) for the full object reference, filters, and the distributor-scoped variant.

## Step 4: Generate the deposit

Call the deposit action with the opportunity ID, wallet, token, amount, and your distributor ID. The API returns an ordered `transactions` array (typically an approval followed by the deposit) for the user to sign in order.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://earn.turtle.xyz/v2/actions/deposit/OPPORTUNITY_ID" \
    -H "X-API-Key: pk_live_xxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "userAddress": "0xYOUR_WALLET",
      "tokenIn": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "amount": "1000000",
      "distributorId": "YOUR_DISTRIBUTOR_ID"
    }'
  ```

  ```typescript TypeScript theme={null}
  const { transactions } = await (
    await fetch(`https://earn.turtle.xyz/v2/actions/deposit/${opportunity.id}`, {
      method: 'POST',
      headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
      body: JSON.stringify({
        userAddress: address,
        tokenIn: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
        amount: '1000000', // base units (1 USDC, 6 decimals)
        distributorId: 'YOUR_DISTRIBUTOR_ID',
      }),
    })
  ).json();

  for (const tx of transactions) {
    const sent = await signer.sendTransaction(tx.transaction);
    await sent.wait();
  }
  ```
</CodeGroup>

<Warning>
  The wallet must be a member (Step 2) before this call.
</Warning>

For the full request body, swap mode, async (pending) deposits, and the broadcast loop, see [Deposit](/sdk/earn/deposit).

## Step 5: Confirm attribution

After the deposit confirms on-chain, verify that Turtle attributed it to you.

<CodeGroup>
  ```bash curl theme={null}
  curl "https://earn.turtle.xyz/v2/actions/verify?chainId=1&txHash=0xYOUR_TX_HASH" \
    -H "X-API-Key: pk_live_xxxxx"
  ```

  ```typescript TypeScript theme={null}
  const { metadata, signatureValid } = await (
    await fetch(
      `https://earn.turtle.xyz/v2/actions/verify?chainId=1&txHash=${txHash}`,
      { headers: { 'X-API-Key': 'pk_live_xxxxx' } }
    )
  ).json();
  ```
</CodeGroup>

A `metadata.distributorId` matching yours and `signatureValid: true` means attribution worked. Nothing else is required; attribution is automatic. See [Verify Attribution](/sdk/earn/verify-attribution).

## What's next

* **[Deposit](/sdk/earn/deposit)** - The full deposit reference: request body, swap mode, and broadcasting.
* **[Opportunities](/sdk/opportunities/get-opportunities)** - The opportunity catalog and the full object schema.
* **[Verify Attribution](/sdk/earn/verify-attribution)** - Confirm a transaction was attributed to your distributor.
* **[Distributor Model](/sdk/concepts/distributor-model)** - How attribution and revenue share work end to end.
