Getting Started
P2P.ORG provides a secure gateway to the SSV network, allowing you to deploy decentralized validators. This guide covers the end-to-end lifecycle of a validator, from initial setup to ongoing maintenance.
1. Prerequisites
Before starting, ensure your environment meets the following requirements:
- Stake: Minimum 32 ETH per validator.
- SSV Tokens: A cluster balance sufficient to cover network fees. Get SSV Testnet tokens here.
- Authentication: A valid P2P.ORG API Token.
- Infrastructure: An arbitrary UUID (id) to track your request status.
2. Choose your workflow
| Workflow | Best For | Logic |
|---|---|---|
| Simplified Smart Contract | Most Users | Uses P2P proxy contract to handle registration and deposit in one flow. |
| Direct Interaction | Power Users | Manually interacting with the Ethereum Deposit Contract for fine-grained control. |
Please noteOn May 7, 2025, the major Ethereum network upgrade was carried out that brought many benefits for clients who use ETH or SSV validators. P2P.ORG recommends upgrading to the
0x02withdrawal credentials to enhance your functionality. It can be done in two ways:
- By consolidating multiple existing validators into a single one
- By creating a new
0x02-enabled validator via simplified 3.1 smart contract flowFor more details, see Pectra Upgrade overview.
However, upgrading to the new address format is not necessary, all existing endpoints remain supported. You can follow the
0x01creation flow below, if you need fine-grained control over validator count, effective balance per validator, or you intend to manually broadcast deposit transactions.
3. Set up staking nodes
Set up staking SSV nodes through P2P infrastructure by sending a POST request to create the initial request.
curl --request POST \
--url https://api.p2p.org/api/v1/eth/staking/ssv/request/create \
--header 'accept: application/json' \
--header 'authorization: Bearer <token>' \
--header 'content-type: application/json' \
--data '{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa5",
"validatorsCount": "1",
"amountPerValidator": "32000000000",
"withdrawalCredentialsType": "0x01",
"withdrawalAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
"feeRecipientAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
"ssvOwnerAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
"type": "without-encrypt-key",
"operationPeriodInDays": 30,
"ecdhPublicKey": null
}'id— arbitrary UUID. You can later use that UUID to check the status of the set-up operation.validatorsCount— number of validators. One validator is equal to 32 ETH.amountPerValidator— amount of tokens to stake in Gwei per validator. Note that if the amount is more than 32 ETH (1 ETH = 10⁹ Gwei), thewithdrawalCredentialsTypeparameter defaults to0x02.withdrawalCredentialsType— withdrawal credentials preferred format:0x01or0x02.withdrawalAddress— 0x01 prefixed withdrawal address for the client. This address is also used as the validator owner's address and must be used to sign the transaction to register the SSV validator at step 6.feeRecipientAddress— Eth1 address that receives priority fees and MEV rewards that are not related to Beacon chain partial withdrawal sweeps.ssvOwnerAddress— address that acts as the owner of the SSV cluster. The cluster owner can register the validator, update the fee recipient address, top-up the cluster balance, and claim SSV incentives rewards.type— type of operation:without-encrypt-key(available) — validator's private key is returned encrypted to the client.with-encrypt-key(not available) — validator private key is instead maintained by P2P to initiate withdrawals when requested by the client. If selected, fill theecdhPublicKeyfield.
operationPeriodInDays— the duration (in days) for which the initial deposit covers the network fees for the SSV cluster..ecdhPublicKey— your ECDH public key to obtain an encrypted validator private key.
Example response:
{
"error": null,
"result": true
}4. Check request status
Check the node set-up operation status. You must poll this until status is ready.
curl --request GET \
--url https://api.p2p.org/api/v1/eth/staking/ssv/request/status/{id} \
--header 'accept: application/json' \
--header 'authorization: Bearer <token>'id— UUID that was specified in the SSV set-up request.
Example response:
{
"result": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "ready",
"validatorsCount": 1,
"amountPerValidator": "32000000000",
"withdrawalCredentialsType": "0x01",
"withdrawalAddress": "0x338EF19fA2eC0fc4d1277B1307a613fA1FBbc0cb",
"feeRecipientAddress": "0x338EF19fA2eC0fc4d1277B1307a613fA1FBbc0cb",
"ssvOwnerAddress": "0x338EF19fA2eC0fc4d1277B1307a613fA1FBbc0cb",
"type": "without-encrypt-key",
"operationPeriodInDays": 31556952,
"liquidationPeriodInDays": 2629746,
"ecdhPublicKey": null,
"validatorRegistrationTxs": {
"serializeTx": "0x02f84405800210830186a094c3cd9a0ae89fff83b71b58b6512d43f8a41f363d...",
"to": "0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D",
"gasLimit": "0.0000000000001",
"data": "0x68b64d8a000000000000000000000000...",
"value": "0.0",
"chainId": 5,
"type": 2,
"maxFeePerGas": "0.000000000000000016",
"maxPriorityFeePerGas": "2"
},
"feeRecipientTx": {
"serializeTx": "0x02f84405800210830186a094c3cd9a0ae89fff83b71b58b6512d43f8a41f363d...",
"to": "0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D",
"gasLimit": "0.0000000000001",
"data": "0xdbcdc2cc000000000000000000000000338EF19fA2eC0fc4d1277B1307a613fA1FBbc0cb...",
"value": "0.0",
"chainId": 5,
"type": 2,
"maxFeePerGas": "0.000000000000000016",
"maxPriorityFeePerGas": "2"
},
"approveTx": {
"serializeTx": "0x02f8....",
"to": "0x3a9f01091C446bdE031E39ea8354647AFef091E7",
"gasLimit": "0.0000000000001",
"data": "0x095e....",
"value": "0.0",
"chainId": 5,
"type": 2,
"maxFeePerGas": "0.000000000000000016",
"maxPriorityFeePerGas": "2"
},
"ssvFeeTxs": [
{
"serializeTx": "0x02f901c605800210830186a094c3cd9a0ae89fff83b71b58b6512d43f8a41f363d...",
"to": "0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D",
"gasLimit": "0.0000000000001",
"data": "0xbc26e7e50000000000000000000000009c7d4b4595402ed44167c74f9f7c7720ab5528e...",
"value": "0.0",
"chainId": 5,
"type": 2,
"maxFeePerGas": "0.000000000000000016",
"maxPriorityFeePerGas": "2"
}
],
"encryptedShares": [
{
"publicKey": "0xb632ad4ebec8594ec8f2fbacc6df53dec180f8bae6561d70bf74c19520a35beff99cd92513058da6a22a75b9570ab31d",
"nonce": "12345",
"sharesData": "0xaf823de...",
"ecdhEncryptedPrivateKey": "0x7d2e91..."
}
],
"clusters": [
{
"operators": [0, 1, 2, 3]
}
]
},
"error": {}
}Response schema
| Field | Type | Description |
|---|---|---|
| id | String | UUID specified in the SSV set-up request. |
| status | String | init (stored), processing (in progress), ready (ready for use), validator-ready (registered), validator-error (invalid data), cancel (timeout/error). |
| validatorsCount | Integer | Number of validators. |
| amountPerValidator | String | Stake in Gwei per validator. |
| withdrawalCredentialsType | String | Format: 0x01 or 0x02. |
| withdrawalAddress | String | Withdrawal address of the cluster owner. |
| feeRecipientAddress | String | Address receiving fee recipient rewards. |
| ssvOwnerAddress | String | Owner of the SSV cluster; can register/top-up/claim rewards. |
| type | String | without-encrypt-key (encrypted key returned) or with-encrypt-key (maintained by P2P). |
| operationPeriodInDays | Integer | The duration (in days) for which the initial deposit covers the network fees for the SSV cluster. At expiration, duties cease and inactivity penalties apply unless the balance is replenished. |
| liquidationPeriodInDays | Integer | The minimum period (in days) a cluster's balance must cover its burn rate to avoid being flagged for liquidation. |
| ecdhPublicKey | String/Null | Your public key for getting the encrypted validator private key. |
| validatorRegistrationTxs | Object | Data to register the validator on the SSV network. |
| feeRecipientTx | Object | Data to set the fee recipient address. |
| approveTx | Object | Data to approve SSV token transfers. |
| ssvFeeTxs | Array | List of transaction data to deposit SSV fees into the cluster balance. |
| encryptedShares | Array | List of objects containing validator key shares and encrypted private keys. |
| clusters | Array | List of cluster objects containing operators indices. |
Transaction object details for validatorRegistrationTxs, ssvFeeTxs, feeRecipientTx, and approveTx
| Field | Type | Description |
|---|---|---|
| serializeTx | String | Serialized unsigned transaction hex. |
| to | String | Recipient address for this transaction. |
| gasLimit | String | Maximum gas limit for this block. |
| data | String | Transaction input data. |
| value | String | Amount in Wei. |
| chainId | Integer | Authorized chain ID (EIP-155). |
| type | Integer | Envelope type (EIP-2718). |
| maxFeePerGas | String | Max price (Base + Priority) in Wei (EIP-1559). |
| maxPriorityFeePerGas | String | Priority fee (tip) in Wei. |
Transaction object details for encryptedShares
| Field | Type | Description |
|---|---|---|
| publicKey | String | Validator public key. |
| nonce | String | Key owner's nonce for the sharesData signature. |
| sharesData | String | Threshold shares and signature to prove ownership. |
| ecdhEncryptedPrivateKey | String | Validator's private key, encrypted via ECDH. |
5. Sign and send transaction
Before any staking happens, you must authorize the SSV network to manage your validator. Use the transaction objects found in the example response (/api/v1/eth/staking/ssv/request/status/[id]).
5.1 Initialize SSV account (One-time)
Token Approval (approveTx): Sign and broadcast the serializeTxor construct a signature using the unserialized data inside approveTx. This allows the SSV contract to transfer SSV tokens on your behalf to fund and pay the cluster node operators.
Set Fee Recipient (feeRecipientTx): Sign and broadcast the serializeTxor construct a signature using the unserialized data inside feeRecipientTx. This sets the fee recipient address for the validator on the SSV network. This address will be the recipient of the Execution Layer rewards accrued. Only applicable for validator with 0x01 withdrawal credentials.
5.2 Register validator on SSV
Registration (validatorRegistrationTxs): Sign and broadcast the serializeTxor construct a signature using the unserialized data inside validatorRegistrationTxs. This officially registers the validators on the SSV network and notifies the node operators (Allnodes, Huobi, P2P, and Stakeley) of the cluster to start looking for your validator's duty assignments.
6. Choose your deposit method
Once registration is broadcasted, wait ~10 minutes, then retrieve your deposit data:
GET /api/v1/eth/staking/ssv/request/deposit-data/[id].
curl --request GET \
--url https://api.p2p.org/api/v1/eth/staking/ssv/request/deposit-data/{id} \
--header 'accept: application/json' \
--header 'authorization: Bearer <token>'id— UUID that was specified in the SSV set-up request.
Example response
{
"error": null,
"result": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "ready",
"depositData": [
{
"pubkey": "0xb632ad4ebec8594ec8f2fbacc6df53dec180f8bae6561d70bf74c19520a35beff99cd92513058da6a22a75b9570ab31d",
"signature": "0x836e....",
"depositDataRoot": "0x1667....",
"withdrawalCredentials": "01000....",
"amount": "32000000000",
"depositMessageRoot": "6a572....",
"forkVersion": "00001020",
"eth2NetworkName": "goerli",
"depositCliVersion": "2.3.0"
}
]
}
}-
id— UUID that was specified in the SSV set-up request. -
status— current status of the SSV request:init— request is stored.processing— request in progress, please wait.ready— request is ready.validator-ready— validator is registered on the SSV network.validator-error— validator data is not valid.cancel— request canceled due to an error or timeout.
Whenready, the validator data is ready to be used in the validator registration step.
-
depositData:-
pubkey— validator public key. -
signature— validator signature. -
depositDataRoot— SHA-256 hash of the SSZ-encoded DepositData object. They are used as a protection against malformed input. -
withdrawalCredentials— withdrawal address credentials, passed in the expected format by the Ethereum deposit smart contract. -
amount— amount of ETH, denominated in gwei, that is being deposited. -
depositMessageRoot— cryptographic hash of the Merkle tree’s root, ensuring the integrity and authenticity of the deposit data. -
forkVersion— version of the network fork that the deposit is intended for. It helps in aligning the deposit with a specific version of the protocol. -
eth2NetworkName— name of the Ethereum 2.0 network where the deposit is made. -
depositCliVersion— version of the deposit command-line interface (CLI) tool that was used to generate the deposit data.
-
6.1 P2P Proxy deposit
Create a serialized transaction for depositing the stake amount by sending a POST request to /api/v1/eth/staking/direct/tx/deposit.
curl --request POST \
--url https://api.p2p.org/api/v1/eth/staking/direct/tx/deposit \
--header 'accept: application/json' \
--header 'authorization: Bearer <token>' \
--header 'content-type: application/json' \
--data '
{
"withdrawalAddress": "0x39D02C253dA1d9F85ddbEB3B6Dc30bc1EcBbFA17",
"depositData": [
{
"pubkey": "0xac1e9969d7b87f3102549ab41558136674a7306b85b9f73cfbd7d9fdb7db85724569da3ebd4d7de9689f6ac058d7e2a3",
"signature": "0xb656f9c771166c82a7891b930e6a920878d9736eb3f9f241753a15ea69d8e2f20a3740dfaf546c70e31bd323e14b341205d04e3227dd4cf2923644a375f6792875ac02c5f256f7a17c96b09bafcbce7e4443e1862356b1e90d78875d78e9a742",
"depositDataRoot": "0xba013b4950b9aff0c3c19017ec5b6e0ed5b957b36f6ff03a545e5cc5605baff8"
}
]
}
'-
withdrawalAddress— withdrawal address for the validators. -
depositData:pubkey— validator public key.signature— validator signature.depositDataRoot— SHA-256 hash of the SSZ-encoded DepositData object. Used as a protection against malformed input.
Example response:
{
"error": null,
"result": {
"serializeTx": "0x02f9....",
"to": "0x681a1b3441c6BFb12f91651EFD9F02c83c070293",
"gasLimit": "0.0000000000001",
"data": "0x4f49....",
"value": "32.0",
"chainId": 5,
"type": 2,
"maxFeePerGas": "0.00000000000000003",
"maxPriorityFeePerGas": "2"
}
}serializeTx— serialized unsigned transaction.to— recipient address for this transaction.gasLimit— maximum gas limit for this block.data— transaction data.value— amount this transaction is sending in Wei.chainId— chain ID this transaction is authorized on, as specified by EIP-155.type— EIP-2718 type of this transaction envelope.maxFeePerGas— maximum price per unit of gas this transaction will pay for the combined 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 block's base fee. This added fee is used to incentivize miners to prioritize this transaction.
Use serializeTx generated to sign and send the signed transaction to the Ethereum network.
By broadcasting this transaction, you are depositing the required stake amount in the Ethereum deposit smart contract by using the P2P smart contract as a proxy.
6.2 Ethereum direct deposit
Use this if you prefer to interact with the official Ethereum contract without a proxy.
- Take the pubkey, signature, and depositDataRoot from the deposit-data response.
- Go to the Official Ethereum Deposit Contract
- Manually execute the
depositfunction with your 32 ETH and the provided data.
After your deposit is successful, your validator will enter the activation queue and soon start performing the validator tasks. You can check the status of your validator on the SSV network explorer.
What's Next?
- DVT Staking API reference.
Updated about 1 hour ago