Skip to main content

Quickstart: your first stake on testnet

This guide takes you through a full staking flow end to end (craft → sign → prepare → broadcast) on Solana devnet, so you can validate an integration with no funds at risk. The same four steps apply to every supported network; only the payload fields change (see How it works).

Why devnet

Always build and test against a testnet first. Solana exposes devnet, which you select with the X-NETWORK header. You can fund a devnet wallet for free with solana airdrop 2 <ADDRESS> --url devnet or the Solana faucet.

Prerequisites

  • A Stakely API key: create one from the Staking API dashboard (see Authentication).
  • A funded Solana devnet wallet and its private key (kept in your environment only).
  • Node.js 18+ if you want to run the signing snippet, with @solana/web3.js and bs58 installed:
npm install @solana/web3.js bs58

Set the base URL and your key as environment variables:

export STAKELY_API_BASE_URL="https://staking-api.stakely.io"
export STAKELY_API_KEY="<your-api-key>"

Step 1: Confirm your network

Check which Solana clusters are enabled for your API key:

curl "$STAKELY_API_BASE_URL/api/v1/solana/native/networks" \
-H "X-API-KEY: $STAKELY_API_KEY"
[
{ "name": "solana", "type": "SOLANA", "chain_id": "mainnet-beta", "is_default": true },
{ "name": "solana-devnet", "type": "SOLANA", "chain_id": "devnet", "is_default": false }
]

Use the chain_id you want as the X-NETWORK header. For this guide that is devnet.

Step 2: Craft the stake transaction

Ask the API to build an unsigned stake transaction. On Solana this single call creates the stake account, funds it, and delegates to the Stakely validator.

curl -X POST "$STAKELY_API_BASE_URL/api/v1/solana/native/action/stake" \
-H "X-API-KEY: $STAKELY_API_KEY" \
-H "X-NETWORK: devnet" \
-H "Content-Type: application/json" \
-d '{
"wallet_address": "CgA24Ai2v3Px7vjyaDrQEf2bvT9a2SmQbhzY1dxjsfyv",
"amount": 0.01
}'

Request fields:

FieldRequiredDescription
wallet_addressWallet that will own and fund the stake.
amountAmount to stake, in SOL (minimum 0.01).
nonce_account_addressUse a durable nonce account if the transaction will be signed later (e.g. multisig). Omit for immediate signing.
signDefaults to true: the API partial-signs with the newly created stake-account key, so you only add the wallet signature.

Response (unsigned_tx_hex is truncated here):

{
"unsigned_tx_hex": "0100000000000000000000000000000000000000000000000000…000405000000"
}

Step 3: Sign in your environment

Sign the unsigned payload with your wallet key. Keys never leave your side. This is a minimal local-key example; for a full worked flow including custodians (Fireblocks), see the Solana integration example.

const web3 = require('@solana/web3.js');
const bs58 = require('bs58');

const signStake = (unsigned_tx_hex, walletPrivateKeyBs58) => {
// Recover the transaction (handles both legacy and versioned)
let tx;
const buf = Buffer.from(unsigned_tx_hex, 'hex');
try {
tx = web3.Transaction.from(buf);
} catch {
tx = web3.VersionedTransaction.deserialize(buf);
}

const keypair = web3.Keypair.fromSecretKey(bs58.decode(walletPrivateKeyBs58));

let signatureBytes;
if (tx instanceof web3.VersionedTransaction) {
tx.sign([keypair]);
signatureBytes = tx.signatures[0];
} else {
tx.partialSign(keypair);
signatureBytes = tx.signature;
}

return Buffer.from(signatureBytes).toString('hex');
};

const signature = signStake(unsigned_tx_hex, process.env.SOL_WALLET_PRIVATE_KEY);

Step 4: Prepare the signed transaction

Send the unsigned payload and your signature back to the API to assemble the final signed transaction.

curl -X POST "$STAKELY_API_BASE_URL/api/v1/solana/native/action/prepare" \
-H "X-API-KEY: $STAKELY_API_KEY" \
-H "X-NETWORK: devnet" \
-H "Content-Type: application/json" \
-d '{
"unsigned_tx_hex": "0100000000000000…000405000000",
"signatures": ["b6c291475834980a1db41bad1bcc23e2930295c4ae61b0f419bdd7dd7fd0fd450f4248d4bf3ab5682916504462028f57eac7380f5e7013f0d02c5151deabf80a"]
}'
{
"signed_tx_hex": "01392e8e2d590173daa411c2b5c2cceb943458c30cf53268…000405000000"
}

Step 5: Broadcast

Submit the signed transaction. You can use the Stakely broadcast endpoint or your own RPC.

curl -X POST "$STAKELY_API_BASE_URL/api/v1/solana/native/action/broadcast" \
-H "X-API-KEY: $STAKELY_API_KEY" \
-H "X-NETWORK: devnet" \
-H "Content-Type: application/json" \
-d '{
"signed_tx_hex": "01392e8e2d590173daa411c2b5c2cceb943458c30cf53268…000405000000"
}'
{
"tx_hash": "29JtVkmnVR2EHZN9h79UU1wYs1xhfM7EB9hAL7Zf5Kv1JWFN1F9iUKpqXdVE2GPhGNU7Ywg5sPFVVxrBQk3SLnCk"
}

Step 6: Verify

Look up the returned tx_hash on a devnet explorer, e.g. https://explorer.solana.com/tx/<tx_hash>?cluster=devnet. Once confirmed, the stake account is created and delegated. You can confirm the position with the balance endpoint:

curl "$STAKELY_API_BASE_URL/api/v1/solana/native/stake-balance/CgA24Ai2v3Px7vjyaDrQEf2bvT9a2SmQbhzY1dxjsfyv" \
-H "X-API-KEY: $STAKELY_API_KEY" \
-H "X-NETWORK: devnet"
note

The hex and signature values above are illustrative; your real payloads will differ. The OpenAPI schema is the source of truth for exact request/response fields: OpenAPI schema.

Where to go next

  • Apply the same flow to another chain: pick a network in the sidebar (each has its own Signing and Endpoints pages).
  • Move to mainnet: swap X-NETWORK to the mainnet value from Step 1 and use production keys; see Authentication for key hygiene.
  • Handle failures gracefully: Errors & responses.