Generate a Solana stake transaction payload

Builds a Solana staking transaction message for the caller to sign and submit. Building a payload does not broadcast a transaction or confirm an on-chain change.

Choose Mainnet or Devnet from the Base URL dropdown on the right before using Try It. Devnet is the Solana test environment. Use an API key and any required account addresses for your selection. Changing Base URL does not change the API key or addresses you have entered.

Supply your API credentials in the api-key header and send the request body as JSON. Instructions operating on an existing stake account must provide a top-level stakePubkey alongside feePayer and instructions.

After building, sign the transaction through your wallet or custody integration, submit it to the selected Solana network, and confirm execution.

Instruction inputs

These sketches illustrate individual instruction inputs. They are not complete JSON requests.

Create and delegate new stake account

{
  type: 'createAndDelegate'
  input: {
    fromPubkey: pubkey of funding address,
    stakeAuthority: address authorized to delegate and undelegate stake,
    withdrawAuthority: address authorized to withdraw stake,
    lamports: amount of lamports to stake (1 sol = 1000000000 lamports),
    reference: an arbitrary reference used to identify/group the stake within the MAVAN platform,
    label: an arbitrary label/memo for use within the MAVAN platform
  }  
}

Create a new stake account (same input data as 'createAndDelegate')

{
  type: 'create'
  input: {
    fromPubkey: pubkey of funding address,
    stakeAuthority: address authorized to delegate and undelegate stake,
    withdrawAuthority: address authorized to withdraw stake,
    lamports: amount of lamports to stake (1 sol = 1000000000 lamports),
    reference: an arbitrary reference used to identify/group the stake within the MAVAN platform,
    label: an arbitrary label/memo for use within the MAVAN platform
  }  
}

Delegate an existing stake account

{
  type: 'delegate'
  input: {
    authorizedPubkey: address authorized to delegate and undelegate stake
  }  
}

Undelegate (deactivate) an existing stake account

{
  type: 'undelegate'
  input: {
    authorizedPubkey: address authorized to delegate and undelegate stake
  }  
}

Withdraw inactive stake (deactivated stake balance or any other excess SOL held by account)

{
  type: 'withdraw'
  input: {
    toPubkey: recipient of withdrawn funds,
    authorizedPubkey: address authorized to withdraw stake,
    lamports: amount of lamports to withdraw (1 sol = 1000000000 lamports),
  }  
}

Change withdraw or stake authority address of an existing stake account

This must be signed by the existing authority address of the stake account

{
  type: 'authorize'
  input: {
    authorizedPubkey: the current authority address of the stake account,
    newAuthorizedPubkey: the new authority address of the stake account,
    stakeAuthorizationType: the authority type to change (0 for stake authority, 1 for withdraw authority),
  }  
}

Split an existing stake account

Creates a new child stake account and moves the requested amount from the source account into it. The child inherits the source account's stake and withdraw authorities and, for delegated stake, its delegation history.

To split one source account into several new accounts, supply one split instruction per new account in the same request. Split instructions cannot be combined with other instruction types.

For production integrations, use an active source account. Requests involving undelegated or activating accounts may fail. For a partial split of active stake, each child's delegated stake and the parent's remaining delegated stake must meet the network's current minimum delegation.

The stake authority (authorizedPubkey) funds each new account's rent-exempt reserve separately from the split amount, and feePayer pays transaction fees. feePayer can be a different address from authorizedPubkey; in that case, collect both signatures before submitting. The examples use the same address for both roles. Rent and minimum delegation are network parameters; do not hard-code them.

To try a split, first call Get Solana Stake Accounts (GET /solana/stakes) with the same API key. Choose an eligible ACTIVE account and copy its stakePubkey into the request. Set instructions[0].input.authorizedPubkey to that account's stakeAuthority; the example below also uses that authority as feePayer, which must have enough SOL for rent and fees. Confirm the current parent balance and delegation state through Solana RPC, then choose a valid split amount; the listing can be stale. Replace every <...> placeholder in the example with a real public key; entering an API key does not replace them automatically.

{
  "feePayer": "<FEE_PAYER_AND_STAKE_AUTHORITY>",
  "stakePubkey": "<PARENT_STAKE_ACCOUNT>",
  "instructions": [
    {
      "type": "split",
      "input": {
        "authorizedPubkey": "<FEE_PAYER_AND_STAKE_AUTHORITY>",
        "lamports": "1050000000",
        "reference": "client-split-1",
        "label": "Split child"
      }
    }
  ]
}
  • authorizedPubkey is the source account's stake authority and must sign.
  • lamports must be a positive base-10 integer string, without leading zeros, and must not exceed 9007199254740991. The example moves 1.05 SOL; check the remaining delegation before using that amount.
  • reference and label are optional. Omitted metadata is inherited or defaulted by the service. A supplied parent label normally gains " (split)" when inherited; a blank parent can produce "Split stake".
  • Supply an explicit child label to override inheritance. An empty string is accepted.

Example success response, HTTP 201:

{
  "data": {
    "serialized": "<HEX_ENCODED_V0_MESSAGE>",
    "stakePubkey": "<NEW_CHILD_STAKE_ACCOUNT>",
    "stakePubkeys": ["<NEW_CHILD_STAKE_ACCOUNT>"],
    "signatures": []
  }
}

The request's stakePubkey identifies the parent. The response's data.stakePubkeys lists every new child in instruction order, and data.stakePubkey is the first of them. Each child address is derived from authorizedPubkey with a seed (createWithSeed), so the gateway returns no child key and no additional account signature is needed. The empty signatures array does not remove the caller's signing requirement.

Each build can generate a different child address. Keep the returned address paired with the exact payload from that response. The new account exists on-chain only after the transaction is submitted and succeeds.

Decode, sign, submit and confirm the returned message as described in Signing and submitting split and merge payloads below.

Merge compatible stake accounts

Merges the source account into a surviving destination account. The source account is closed when the transaction succeeds on-chain.

The top-level stakePubkey is the destination that survives. input.sourceStakePubkey is the source account that closes. authorizedPubkey is the stake authority and must sign.

Accounts must have compatible stake and withdraw authorities, lockup settings and delegation state. Active-stake merges also require compatible validator and vote-credit state. Matching authorities alone does not establish eligibility.

A child split from active stake inherits delegation history and can be merged back without waiting an additional epoch, provided the accounts remain compatible.

The example below uses the same address for the fee payer and stake authority. Replace every <...> placeholder with a real public key before submitting a request.

{
  "feePayer": "<FEE_PAYER_AND_STAKE_AUTHORITY>",
  "stakePubkey": "<SURVIVING_STAKE_ACCOUNT>",
  "instructions": [
    {
      "type": "merge",
      "input": {
        "authorizedPubkey": "<FEE_PAYER_AND_STAKE_AUTHORITY>",
        "sourceStakePubkey": "<STAKE_ACCOUNT_TO_CLOSE>"
      }
    }
  ]
}

The response's data.stakePubkey identifies the surviving destination. Decode, sign, submit and confirm the returned message as described in Signing and submitting split and merge payloads below.

The stake-account listing may retain the source as DISSOLVED with its historical balance. Exclude that row when calculating current holdings.

Signing and submitting split and merge payloads

data.serialized is a hexadecimal-encoded Solana v0 message, not a serialized transaction including its signature envelope.

For split and merge payloads, construct a transaction using @solana/web3.js v1.x:

import { MessageV0, VersionedTransaction } from '@solana/web3.js';

const message = MessageV0.deserialize(
  Buffer.from(response.data.serialized, 'hex'),
);
const transaction = new VersionedTransaction(message);

Use your wallet or custody integration to sign the required message signers, submit the transaction to the matching Solana network, and confirm execution. Do not pass data.serialized directly to VersionedTransaction.deserialize().

Current integration limitations

The split and merge examples each use one instruction per request and the same address for the fee payer and stake authority. Requests involving undelegated or activating accounts may fail to build through the production gateway.

Building a transaction can create a provisional REQUESTED record, including on some failed builds. A listing row is not proof of execution.

Some invalid inputs and unsupported account states currently return HTTP 500 rather than a specific validation error. Verify the request fields and account state before rebuilding.

Devnet can reject a repeated split build while a child remains pending. Do not assume Mainnet and Devnet behave identically in that case.

Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…
Body Params
Headers
string
required

mavan api key

Responses

400

Invalid request. Some invalid inputs and unsupported account states currently return HTTP 500 instead.

500

Transaction message could not be built. This can also indicate invalid inputs or unsupported account state. A provisional stake-account record may have been created.

Language
URL
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/json