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

# Cancel Deposit

> Cancel a pending async deposit and recover the deposited funds

## Overview

For vaults with **async deposits**, a deposit may sit in a pending/queued state before the vault processes it. If the user wants to recover their funds instead of waiting for the vault to process them, the cancel-deposit endpoint generates the transaction to cancel the pending deposit.

<Steps>
  <Step title="Deposit is pending">
    The user previously called [deposit](/sdk/earn-api/actions/deposit) and the funds are queued, waiting to be processed.
  </Step>

  <Step title="Create cancel-deposit action">
    Call `POST /v1/actions/cancel-deposit/{opportunityId}` to generate the cancellation transaction.
  </Step>

  <Step title="Sign & submit transaction">
    The user signs and submits the cancel transaction. Funds are returned to the user.
  </Step>
</Steps>

<Info>
  This endpoint is only relevant for opportunities with async deposits (e.g., Mellow, Lagoon). For standard vaults, deposits are processed immediately and cannot be cancelled.
</Info>

## Create Cancel Deposit

Generate the transaction to cancel a pending async deposit. Like claim-deposit, this is a simplified request — the vault already knows which deposit to cancel based on the user's address.

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

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

  const response = await fetch(
    `https://earn.turtle.xyz/v1/actions/cancel-deposit/${opportunityId}`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        userAddress: '0x1234...',
        distributorId: 'your-distributor-id',
      }),
    }
  );
  const data = await response.json();
  ```
</CodeGroup>

**Path Parameters**

<ParamField path="opportunityId" type="uuid" required>
  The unique identifier of the opportunity with the pending deposit. 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 and must have a pending deposit in this opportunity.
</ParamField>

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

**Response**

```json theme={null}
{
  "actionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "transactions": [
    {
      "type": "cancelDeposit",
      "transaction": {
        "to": "0x...",
        "data": "0x...",
        "value": "0",
        "gasLimit": "200000",
        "chainId": 1
      },
      "description": "Cancel pending deposit"
    }
  ]
}
```

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

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

// 1. Create the cancel-deposit action
const cancelResponse = await fetch(
  `https://earn.turtle.xyz/v1/actions/cancel-deposit/${opportunityId}`,
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      userAddress: walletAddress,
      distributorId: 'your-distributor-id',
    }),
  }
);
const { transactions } = await cancelResponse.json();

// 2. Sign and submit the cancel transaction
const tx = transactions[0];
const txResponse = await wallet.sendTransaction(tx.transaction);
await txResponse.wait();
```

## 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>
</AccordionGroup>

## Related Endpoints

* [Deposit](/sdk/earn-api/actions/deposit) - Generate the initial deposit transactions
* [Claim Deposit](/sdk/earn-api/actions/claim-deposit) - Claim a pending async deposit instead of cancelling
* [Opportunities API](/sdk/opportunities/get-opportunities) - Discover available opportunities and their IDs
