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

# Withdrawal

> Withdraw staked ETH with the P2P.org Pooled Staking API.

The **Pooled Staking API** allows users to initiate and complete withdrawal of their staked ETH at any time. Withdrawal is a two-step process due to the Ethereum exit queue and protocol constraints:

1. Prepare the unstake transaction and submit it to the blockchain
2. Withdraw unstaked tokens to the delegator’s wallet after the exit period ends.

Request examples are provided using [cURL](https://curl.se/).

<Warning>
  **Please note**

  The Pooled Staking API does not use base URL switching to differentiate between Mainnet and Testnet as compared to other ETH APIs. It uses path switching in the endpoints.
</Warning>

## 1. Prepare unstaking transaction

1. Create the unstake request for a specific delegator and vault by sending a POST request to [/api/v1/staking/pool/hoodi/staking/unstake](/reference/eth-pool-staking-unstake).

   Example request (for `hoodi` network):

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
       --url https://api.p2p.org/api/v1/staking/pool/hoodi/staking/unstake \
       --header 'accept: application/json' \
       --header 'authorization: Bearer <token>' \
       --header 'content-type: application/json' \
       --data '{
         "delegatorAddress": "0x092Af80778ff3c3D27Fd2744C39f6e9326d9AaEe",
         "vaultAddress": "0xba447498dc4c169f2b4f427b2c4d532320457e89",
         "amount": 0.1
       }'
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.p2p.org/api/v1/staking/pool/hoodi/staking/unstake", {
    method: "POST",
    headers: {
      "authorization": "Bearer <token>",
      "content-type": "application/json",
    },
    body: JSON.stringify({
        "delegatorAddress": "0x092Af80778ff3c3D27Fd2744C39f6e9326d9AaEe",
        "vaultAddress": "0xba447498dc4c169f2b4f427b2c4d532320457e89",
        "amount": 0.1
    }),
  });
  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.p2p.org/api/v1/staking/pool/hoodi/staking/unstake",
      headers={
          "authorization": "Bearer <token>",
          "content-type": "application/json",
      },
      json={
              "delegatorAddress": "0x092Af80778ff3c3D27Fd2744C39f6e9326d9AaEe",
              "vaultAddress": "0xba447498dc4c169f2b4f427b2c4d532320457e89",
              "amount": 0.1
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	payload := map[string]interface{}{
  		"delegatorAddress": "0x092Af80778ff3c3D27Fd2744C39f6e9326d9AaEe",
  		"vaultAddress": "0xba447498dc4c169f2b4f427b2c4d532320457e89",
  		"amount": 0.1,
  	}
  	body, _ := json.Marshal(payload)
  	req, _ := http.NewRequest("POST", "https://api.p2p.org/api/v1/staking/pool/hoodi/staking/unstake", bytes.NewBuffer(body))
  	req.Header.Set("authorization", "Bearer <token>")
  	req.Header.Set("content-type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	respBody, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

* `delegatorAddress` — account address of the user initiating the withdrawal transaction.
* `vaultAddress` — Ethereum address of the vault which keeps the tokens.
* `amount` — amount of tokens in ETH to withdraw. The value must be decimal, e.g., 0.01.

Example response:

<CodeGroup>
  ```json theme={null}
  {
      "error": null,
      "result": {
        "amount": 0.01,
        "vaultAddress": "0xba447498dc4c169f2b4f427b2c4d532320457e89",
        "delegatorAddress": "0x092Af80778ff3c3D27Fd2744C39f6e9326d9AaEe",
        "unsignedTransaction": {
          "serializeTx": "0x02f87683088bb0168459682f0084d16be71082d54e94ba447498dc4c169f2b4f427b2c4d532320457e8987f8b0a10e470000b844f9609f08000000000000000000000000092af80778ff3c3d27fd2744c39f6e9326d9aaee0000000000000000000000000000000000000000000000000000000000000000c0",
          "to": "0xba447498dc4c169f2b4f427b2c4d532320457e89",
          "data": "0xf9609f08000000000000000000000000092af80778ff3c3d27fd2744c39f6e9326d9aaee0000000000000000000000000000000000000000000000000000000000000000",
          "value": "10000000000000000",
          "nonce": 22,
          "chainId": 560048,
          "gasLimit": "54606",
          "type": 2,
          "maxFeePerGas": "3513509648",
          "maxPriorityFeePerGas": "1500000000"
        },
        "createdAt": "2025-07-21T12:05:59.015Z"
      }
    }
  ```
</CodeGroup>

* `amount` — amount of tokens in ETH to unstake.

* `vaultAddress` — Ethereum address of the vault which keeps the tokens.

* `delegatorAddress` — account address of the user initiating the unstake transaction.

* `unsignedTransaction` — unsigned transaction in Base64 encrypted format. Sign the transaction and submit it to the blockchain to perform the called action.

  * `serializeTx` — serialized unsigned transaction.
  * `to` — recipient address for this transaction.
  * `data` — transaction data payload in the hexadecimal format.
  * `value` — amount this transaction is sending in Wei.
  * `nonce` — nonce of the transaction.
  * `chainId` — chain ID this transaction is authorized on, as specified by [EIP-155](https://eips.ethereum.org/EIPS/eip-155).
  * `gasLimit` — maximum <Tooltip tip="A measure of computational effort required to execute a transaction or smart contract on a blockchain. Users must pay a gas fee, usually in the native token, to have their transactions processed by the network.">gas</Tooltip> limit for this block.
  * `type` — [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) type of this transaction envelope.
  * `maxFeePerGas` — maximum price per unit of gas this transaction will pay for the combined [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) block's base fee and this transaction's priority fee in Wei.
  * `maxPriorityFeePerGas` — price per unit of gas in Wei, which is added to the [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) block's base fee. This added fee is used to incentivize miners to prioritize this transaction.

* `createdAt` — timestamp of the transaction in the ISO 8601 format.

2. Use `unsignedTransaction` from the previous step to [sign and send](/docs/signing-transaction-eth) the signed transaction to the Ethereum network.

## 2. Prepare withdrawal transaction

<Note>
  Note that it takes up to 4 days to prepare your tokens for withdrawal as exiting validators from the Beacon Chain takes time. Withdrawal is only available after the exit period ends.
</Note>

1. Once the tokens become claimable, prepare the withdrawal transaction to return ETH to the delegator’s wallet by sending a POST request to [/api/v1/staking/pool/hoodi/staking/withdraw](/reference/eth-pool-staking-withdraw).

   Example request (for `hoodi` network):

<CodeGroup>
  ```bash curl theme={null}
  curl --request POST \
       --url https://api.p2p.org/api/v1/staking/pool/hoodi/staking/withdraw \
       --header 'accept: application/json' \
       --header 'authorization: Bearer <token>' \
       --header 'content-type: application/json' \
       --data '{
         "delegatorAddress": "0x092Af80778ff3c3D27Fd2744C39f6e9326d9AaEe",
         "vaultAddress": "0xba447498dc4c169f2b4f427b2c4d532320457e89"
       }'
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch("https://api.p2p.org/api/v1/staking/pool/hoodi/staking/withdraw", {
    method: "POST",
    headers: {
      "authorization": "Bearer <token>",
      "content-type": "application/json",
    },
    body: JSON.stringify({
        "delegatorAddress": "0x092Af80778ff3c3D27Fd2744C39f6e9326d9AaEe",
        "vaultAddress": "0xba447498dc4c169f2b4f427b2c4d532320457e89"
    }),
  });
  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.p2p.org/api/v1/staking/pool/hoodi/staking/withdraw",
      headers={
          "authorization": "Bearer <token>",
          "content-type": "application/json",
      },
      json={
              "delegatorAddress": "0x092Af80778ff3c3D27Fd2744C39f6e9326d9AaEe",
              "vaultAddress": "0xba447498dc4c169f2b4f427b2c4d532320457e89"
      },
  )
  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	payload := map[string]interface{}{
  		"delegatorAddress": "0x092Af80778ff3c3D27Fd2744C39f6e9326d9AaEe",
  		"vaultAddress": "0xba447498dc4c169f2b4f427b2c4d532320457e89",
  	}
  	body, _ := json.Marshal(payload)
  	req, _ := http.NewRequest("POST", "https://api.p2p.org/api/v1/staking/pool/hoodi/staking/withdraw", bytes.NewBuffer(body))
  	req.Header.Set("authorization", "Bearer <token>")
  	req.Header.Set("content-type", "application/json")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	respBody, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

* `delegatorAddress` — account address of the user initiating the withdrawal transaction.
* `vaultAddress` — Ethereum address of the vault which keeps the tokens.

The example response is the same as in the prepare unstaking transaction step.

2. Use `unsignedTransaction` from the previous step to [sign and send](/docs/signing-transaction-eth) the signed transaction to the Ethereum network.


## Related topics

- [Sign and Send Transaction](/docs/pooled-staking-signing-transaction.md)
- [Pooled Staking API reference](/reference/eth-pool-staking-vaults-list.md)
