> ## 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.

# Create Deposit

> Generate ready-to-sign transactions for depositing into an opportunity

<Note>
  All requests require an API key via the `X-API-Key` header.
  See [Authentication](/sdk/authentication/api-keys) for details.
</Note>

## Overview

The Actions API handles the transactional lifecycle for deposits on Turtle Earn. The typical flow is:

<Steps>
  <Step title="Create deposit action">
    Call `POST /v1/actions/deposit/{opportunityId}` to generate the transactions.
  </Step>

  <Step title="Sign & submit transactions">
    The user signs and submits each transaction in order (e.g., approve + deposit).
  </Step>

  <Step title="Attribution recorded automatically">
    Turtle detects the on-chain transaction and attributes it to your distributor. No manual call required.
  </Step>
</Steps>

<Info>
  All deposit action endpoints require the user to be a [Turtle member](/sdk/authentication/register-wallet). Make sure the user has completed the membership flow before calling these endpoints.
</Info>

## Create Deposit

Generate the transactions needed to deposit into an opportunity. The response contains an ordered list of transactions the user must sign and submit (e.g., approve + deposit).

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST "https://earn.turtle.xyz/v1/actions/deposit/{opportunityId}" \
    -H "X-API-Key: pk_live_xxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "userAddress": "0x1234...",
      "tokenIn": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "amount": "1000000",
      "distributorId": "your-distributor-id",
      "mode": "direct",
      "slippageBps": 50
    }'
  ```

  ```typescript TypeScript theme={null}
  const opportunityId = '550e8400-e29b-41d4-a716-446655440000';

  const response = await fetch(
    `https://earn.turtle.xyz/v1/actions/deposit/${opportunityId}`,
    {
      method: 'POST',
      headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
      body: JSON.stringify({
        userAddress: '0x1234...',
        tokenIn: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
        amount: '1000000', // 1 USDC in wei (6 decimals)
        distributorId: 'your-distributor-id',
        mode: 'direct',
        slippageBps: 50,
      }),
    }
  );
  const data = await response.json();
  ```
</CodeGroup>

**Path Parameters**

<ParamField path="opportunityId" type="uuid" required>
  The unique identifier of the opportunity to deposit into. Get this from the [Opportunities API](/sdk/opportunities/get-opportunities).
</ParamField>

**Body Parameters**

<ParamField body="userAddress" type="string" required>
  The user's EVM wallet address. Must belong to a registered Turtle member.
</ParamField>

<ParamField body="tokenIn" type="string" required>
  The address of the token being deposited. Must be a supported token on the opportunity's chain. Cannot be the vault's receipt token.
</ParamField>

<ParamField body="amount" type="string" required>
  The deposit amount in the token's smallest unit (wei). Must be greater than 0.
</ParamField>

<ParamField body="distributorId" type="string" required>
  Your distributor ID for attribution tracking.
</ParamField>

<ParamField body="mode" type="string" default="direct">
  Deposit mode. Use `direct` for direct deposits into the vault, or `swap` to use a DEX router when the input token differs from the vault's deposit token.
</ParamField>

<ParamField body="slippageBps" type="integer" default="50">
  Slippage tolerance in basis points when using `swap` mode. For example, `50` = 0.5% slippage.
</ParamField>

<ParamField body="referralCode" type="string">
  Optional referral code for deposit attribution.
</ParamField>

**Response**

```json theme={null}
{
  "actionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "transactions": [
    {
      "type": "approve",
      "transaction": {
        "to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        "data": "0x095ea7b3000000000000000000000000...",
        "value": "0",
        "gasLimit": "60000",
        "chainId": 1
      },
      "description": "Approve USDC spending"
    },
    {
      "type": "deposit",
      "transaction": {
        "to": "0x...",
        "data": "0x...",
        "value": "0",
        "gasLimit": "250000",
        "chainId": 1
      },
      "description": "Deposit USDC into vault"
    }
  ]
}
```

### Transaction Object

Each transaction in the `transactions` array contains:

<ResponseField name="type" type="string" required>
  Transaction type, e.g. `approve`, `deposit`, `withdraw`, `claimDeposit`, `cancelDeposit`.
</ResponseField>

<ResponseField name="transaction" type="object" required>
  The raw transaction data to sign and submit.
</ResponseField>

<ResponseField name="transaction.to" type="string" required>
  Target contract address.
</ResponseField>

<ResponseField name="transaction.data" type="string" required>
  Encoded calldata (hex string with `0x` prefix).
</ResponseField>

<ResponseField name="transaction.value" type="string" required>
  Value in wei. Usually `"0"` for token interactions; non-zero for native token deposits.
</ResponseField>

<ResponseField name="transaction.gasLimit" type="string" required>
  Estimated gas limit.
</ResponseField>

<ResponseField name="transaction.chainId" type="integer" required>
  Chain ID for the transaction.
</ResponseField>

<ResponseField name="description" type="string" required>
  Human-readable description of what this transaction does.
</ResponseField>

<ResponseField name="metadata" type="object">
  Optional metadata for swap transactions, including provider info, amount out, gas estimate, and route details.
</ResponseField>

## Complete Example

Here's a full deposit flow from start to finish:

```typescript theme={null}
// 1. Create the deposit action
const depositResponse = await fetch(
  `https://earn.turtle.xyz/v1/actions/deposit/${opportunityId}`,
  {
    method: 'POST',
    headers: { 'X-API-Key': 'pk_live_xxxxx', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      userAddress: walletAddress,
      tokenIn: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
      amount: '1000000000', // 1000 USDC
      distributorId: 'your-distributor-id',
      mode: 'direct',
    }),
  }
);
const { actionId, transactions } = await depositResponse.json();

// 2. Sign and submit each transaction in order
for (const tx of transactions) {
  console.log(`Signing: ${tx.description}`);
  const txResponse = await wallet.sendTransaction(tx.transaction);
  await txResponse.wait(); // Wait for on-chain confirmation
}

// 3. Attribution is automatic — Turtle detects the tracking signature
//    in the transaction calldata and attributes the deposit to your
//    distributor. No manual call required.
```

## Error Handling

<AccordionGroup>
  <Accordion title="User is not a Turtle member">
    **Status Code:** 403 Forbidden

    ```json theme={null}
    {
      "error": "not_a_member",
      "message": "User is not a Turtle member. Please complete the membership flow first.",
      "docsUrl": "https://docs.turtle.xyz/sdk/authentication/register-wallet"
    }
    ```

    **Solution:** Complete the [membership flow](/sdk/authentication/register-wallet) before calling action endpoints.
  </Accordion>

  <Accordion title="Distributor not found">
    **Status Code:** 404 Not Found

    ```json theme={null}
    {
      "error": "distributor_not_found",
      "message": "Distributor not found with the provided ID"
    }
    ```

    **Solution:** Verify your distributor ID is correct and active.
  </Accordion>

  <Accordion title="Opportunity not found">
    **Status Code:** 404 Not Found

    ```json theme={null}
    {
      "error": "opportunity_not_found",
      "message": "Opportunity not found"
    }
    ```

    **Solution:** Check the opportunity ID using the [Opportunities API](/sdk/opportunities/get-opportunities).
  </Accordion>

  <Accordion title="Deposits disabled">
    **Status Code:** 400 Bad Request

    ```json theme={null}
    {
      "error": "deposits_disabled",
      "message": "Deposits are disabled for this opportunity"
    }
    ```

    **Solution:** This opportunity has temporarily disabled deposits. Try a different opportunity.
  </Accordion>

  <Accordion title="Unsupported token">
    **Status Code:** 400 Bad Request

    ```json theme={null}
    {
      "error": "invalid_token",
      "message": "Token 0x... not supported for chain 1"
    }
    ```

    **Solution:** Use a supported deposit token. Check the opportunity's `depositTokens` array.
  </Accordion>
</AccordionGroup>

## Related Endpoints

* [Withdraw](/sdk/earn-api/actions/withdraw) - Generate withdraw transactions to redeem shares
* [Claim Deposit](/sdk/earn-api/actions/claim-deposit) - Claim a pending async deposit
* [Cancel Deposit](/sdk/earn-api/actions/cancel-deposit) - Cancel a pending async deposit
* [Verify](/sdk/earn-api/actions/verify) - Verify that a transaction contains valid Turtle tracking data
* [Opportunities API](/sdk/opportunities/get-opportunities) - Discover available opportunities and their IDs
* [Membership API](/sdk/authentication/register-wallet) - Register users before they can deposit
* [Get Activity](/sdk/earn-api/deposits) - Track deposits after they're completed
