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

> Generate ready-to-sign transactions for withdrawing from an opportunity

## Overview

The withdraw endpoint generates transactions to redeem shares from a vault/opportunity. The typical flow is:

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

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

<Info>
  All 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 Withdraw

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

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

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

  const response = await fetch(
    `https://earn.turtle.xyz/v1/actions/withdraw/${opportunityId}`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        userAddress: '0x1234...',
        amount: '1000000000000000000', // shares to redeem in smallest unit
        distributorId: 'your-distributor-id',
        tokenOut: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
        slippageBps: 50,
      }),
    }
  );
  const data = await response.json();
  ```
</CodeGroup>

**Path Parameters**

<ParamField path="opportunityId" type="uuid" required>
  The unique identifier of the opportunity to withdraw from. 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="amount" type="string" required>
  The number of shares to redeem in the smallest unit. Must be greater than 0.
</ParamField>

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

<ParamField body="tokenOut" type="string">
  The address of the token to receive after withdrawal. Required for some providers (e.g., Midas, Mellow, Veda). If not provided, the vault's default withdraw token is used.
</ParamField>

<ParamField body="slippageBps" type="integer">
  Slippage tolerance in basis points. For example, `50` = 0.5% slippage. Only applied to opportunities that require it.
</ParamField>

**Response**

```json theme={null}
{
  "actionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "transactions": [
    {
      "type": "approve",
      "transaction": {
        "to": "0x...",
        "data": "0x095ea7b3000000000000000000000000...",
        "value": "0",
        "gasLimit": "60000",
        "chainId": 1
      },
      "description": "Approve shares spending"
    },
    {
      "type": "withdraw",
      "transaction": {
        "to": "0x...",
        "data": "0x...",
        "value": "0",
        "gasLimit": "300000",
        "chainId": 1
      },
      "description": "Withdraw from 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 withdraw flow from start to finish:

```typescript theme={null}
const opportunityId = '550e8400-e29b-41d4-a716-446655440000';
const walletAddress = '0x1234...';

// 1. Create the withdraw action
const withdrawResponse = await fetch(
  `https://earn.turtle.xyz/v1/actions/withdraw/${opportunityId}`,
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      userAddress: walletAddress,
      amount: '1000000000000000000', // shares to redeem
      distributorId: 'your-distributor-id',
      tokenOut: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // receive USDC
    }),
  }
);
const { transactions } = await withdrawResponse.json();

// 2. Sign and submit each transaction in order
for (const tx of transactions) {
  const txResponse = await wallet.sendTransaction(tx.transaction);
  await txResponse.wait(); // Wait for confirmation
}
```

## 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="Invalid tokenOut address">
    **Status Code:** 400 Bad Request

    ```json theme={null}
    {
      "error": "INVALID_ARGUMENT",
      "message": "invalid tokenOut address format"
    }
    ```

    **Solution:** Provide a valid EVM address for the `tokenOut` field.
  </Accordion>
</AccordionGroup>

## Related Endpoints

* [Deposit](/sdk/earn-api/actions/deposit) - Generate deposit transactions
* [Opportunities API](/sdk/opportunities/get-opportunities) - Discover available opportunities and their IDs
