Stake Go Account Assets

Overview

Offer your clients the ability to stake assets held in Go Accounts. Your clients earn rewards by delegating assets to a validator on-chain. BitGo manages the staking process on your behalf. Staking from a Go Account uses a three-step manual flow: generate a staking request, sign the payload, and finalize by sending the half-signed payload to BitGo.

Staking protocols differ by asset. For example, some assets may require you to specify a staking time limit, require separate transactions to claim your rewards, or have a cooldown period after unstaking before the assets are available for further transactions. To learn asset-specific staking details, you can call the List coins available for staking endpoint.

Note: Go Account staking is currently in beta and is only available in the test environment.

Prerequisites

Stake Assets

1. Create Staking Request

Create a staking request by specifying the staking details and sending them to BitGo.

Endpoint: Generate staking request for Go Account

export COIN="<ASSET_ID>"
export GO_ACCOUNT_ID="<YOUR_GO_ACCOUNT_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"

curl -X POST \
  https://app.bitgo-test.com/api/go-staking/v1/$COIN/accounts/$GO_ACCOUNT_ID/requests/preview \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "amount": "'"$AMOUNT"'"
  }'

Step Result

BitGo uses the data you pass to build an unsigned staking request. The following example is the response when previewing a staking request for 0.01 TSOL.

{
  "payload": "{\"coin\":\"ofctsol\",\"recipients\":[{\"address\":\"BpkMFStkryPDkVYqTbEGLqWD3FLoPLCwTV4sdN1XKBPF\",\"amount\":\"1000000\"}],\"fromAccount\":\"62182dc6685f820007002502234b4dfc\",\"nonce\":\"8d819cce-a7e1-4e24-a29d-22f4b003130f\",\"timestamp\":\"2025-07-25T20:26:52.574Z\",\"feeString\":\"0\",\"shortCircuitBlockchainTransfer\":false,\"isIntraJXTransfer\":false}",
  "feeInfo": {
    "feeString": "0"
  },
  "coin": "ofc",
  "token": "ofctsol"
}

2. Sign Staking Request

Use your Go Account passphrase to authenticate the transaction. To ensure your passphrase isn't passed over the Internet, you must use BitGo Express in external-signing mode or the JavaScript SDK.

export BITGO_EXPRESS_HOST="<YOUR_LOCAL_HOST>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export WALLET_ID="<YOUR_WALLET_ID>"

curl -X POST \
  http://$BITGO_EXPRESS_HOST/api/v2/ofc/signPayload \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "walletId": "'"$WALLET_ID"'",
    "walletPassphrase": "<YOUR_GO_ACCOUNT_PASSPHRASE>",
    "payload": "<PAYLOAD_FROM_PREVIOUS_STEP>"
  }'
const halfSignedTransaction = (await wallet.prebuildAndSignTransaction({
  walletPassphrase: '<WALLET_PASSPHRASE>',
  prebuildTx: {
    payload: '<PAYLOAD_OBJECT>',
  }
}));

Step Result

{
  "payload": "<ORIGINAL_PAYLOAD_STRING>",
  "signature": "1f8e22206d9c95cff29154679f9d0b03bbb33e38b1f801090d0fb4f2e9464b969c263497689af974d13915dc72e00ffb3dfdac05c312ba9711e77014ffe2431c75"
}

3. Send Staking Request

Send the half-signed staking request to BitGo for final signing with the BitGo key.

Endpoint: Finalize staking request for Go Account

export COIN="<ASSET_ID>"
export GO_ACCOUNT_ID="<YOUR_GO_ACCOUNT_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"
export HALF_SIGNED_PAYLOAD="<HALF_SIGNED_PAYLOAD>"

curl -X POST \
  https://app.bitgo-test.com/api/go-staking/v1/$COIN/accounts/$GO_ACCOUNT_ID/requests/finalize \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "type": "STAKE",
    "amount": "'"$AMOUNT"'",
    "frontTransferSendRequest": {
      "halfSigned": "'"$HALF_SIGNED_PAYLOAD"'"
    }
  }'

Step Result

If your staking request doesn't require approval, BitGo applies the final signature using the BitGo key and broadcasts the transaction to the blockchain, transferring assets on-chain from your Go Account to the validator. If you Create Policy Rules to require approvals, the staking request remains in a PENDING_APPROVAL status until an admin approves it.

{
  "id": "5bdeed2f-a173-4ca1-936b-a36399af8152",
  "type": "STAKE",
  "coin": "tsol",
  "status": "NEW",
  "goSpecificStatus": "NEW",
  "statusModifiedDate": "2025-07-25T20:30:57.046379144Z",
  "createdDate": "2025-07-25T20:30:57.046365Z",
  "amount": 1000000,
  "frontTransferSendRequest": {
    "halfSigned": {
      "payload": "{\"coin\":\"ofctsol\",\"recipients\":[{\"address\":\"BpkMFStkryPDkVYqTbEGLqWD3FLoPLCwTV4sdN1XKBPF\",\"amount\":\"1000000\"}],\"fromAccount\":\"62182dc6685f820007002502234b4dfc\",\"nonce\":\"8d819cce-a7e1-4e24-a29d-22f4b003130f\",\"timestamp\":\"2025-07-25T20:26:52.574Z\",\"feeString\":\"0\",\"shortCircuitBlockchainTransfer\":false,\"isIntraJXTransfer\":false}",
      "signature": "1f8e22206d9c95cff29154679f9d0b03bbb33e38b1f801090d0fb4f2e9464b969c263497689af974d13915dc72e00ffb3dfdac05c312ba9711e77014ffe2431c75"
    }
  }
}

4. Approve Request (Optional)

If you have a policy that requires approval, you must approve the staking request before BitGo adds the final signature with the BitGo key.

Note: If you configure an approval requirement for staking requests, you can't approve your own transactions - another admin must approve them.

Endpoint: Update Pending Approval

export APPROVAL_ID="<APPROVAL_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export OTP="<YOUR_OTP>"

curl -X PUT \
  https://app.bitgo-test.com/api/v2/pendingApprovals/$APPROVAL_ID \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "state": "approved",
    "otp": "'"$OTP"'"
  }'

Step Result

{
  "id": "e055adbc-66a3-4ccd-9a9d-726a05bca0cf",
  "coin": "hteth",
  "wallet": "2032e75g451052000636831abd797bd3",
  "enterprise": "1032e75c451052000436831deb797af1",
  "creator": "62ab90e06dfda30007974f0a52a12995",
  "createDate": "2022-01-10T14:32:28Z",
  "state": "approved",
  "scope": "wallet",
  "userIds": [
    "62ab90e06dfda30007974f0a52a12995",
    "621d08a634ad8a0007fcddffd7c429cc"
  ],
  "approvalsRequired": 1
}

Unstake Assets

When you submit an unstaking request, BitGo makes a series of transfers. However, you only need to create the initial unstaking request - no signatures are required.

1. Create Unstaking Request

Create an unstaking request by specifying the unstaking details and sending them to BitGo.

Endpoint: Finalize staking request for Go Account

export COIN="<ASSET_ID>"
export GO_ACCOUNT_ID="<YOUR_GO_ACCOUNT_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"

curl -X POST \
  https://app.bitgo-test.com/api/go-staking/v1/$COIN/accounts/$GO_ACCOUNT_ID/requests/finalize \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "type": "UNSTAKE",
    "amount": "'"$AMOUNT"'"
  }'

Step Result

BitGo generates an unstaking request.

{
  "id": "487fb12a-e11e-4c3d-9f6c-4c85214af88d",
  "type": "UNSTAKE",
  "coin": "tsol",
  "status": "NEW",
  "goSpecificStatus": "NEW",
  "statusModifiedDate": "2025-08-15T19:36:15.560401474Z",
  "createdDate": "2025-08-15T19:36:15.560363Z",
  "amount": 3000000
}

View Rewards

After staking, you can view your overall positions, including active delegations, pending amounts, and accrued rewards.

Endpoint: Get staking wallet attributes for Go Account

export GO_ACCOUNT_ID="<YOUR_GO_ACCOUNT_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"

curl -X GET \
  "https://app.bitgo-test.com/api/go-staking/v1/accounts/$GO_ACCOUNT_ID/coins" \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Step Result

{
  "coins": [
    {
      "coin": "ofctsol",
      "activeStake": 0,
      "pendingStake": 0,
      "pendingUnstake": 0,
      "rewards": 0,
      "attributes": {
        "permissionAttributes": {
          "staking": {
            "enabled": true,
            "allowClientToUseOwnValidator": false
          },
          "unstaking": {
            "enabled": false,
            "disabledReason": "Not actively staking TSOL"
          }
        },
        "spendableAttributes": {
          "staking": {
            "fee": 0,
            "max": 0,
            "min": 0,
            "netMax": 46000000,
            "netMin": 0,
            "minStakeMore": 0
          },
          "unstaking": {
            "max": 0,
            "min": 0,
            "multipleDelegations": false,
            "requiresAmount": true,
            "requiresDelegationId": false,
            "requiresDelegationIds": false
          }
        },
        "disclaimerAttributes": {
          "staking": {
            "info": [
              "Staking takes up to the next epoch to activate (~2.1 days) and earn rewards."
            ],
            "rewardPercentageRate": 7,
            "stakeWarmupPeriodDesc": "1 epoch (2.1 days)"
          },
          "unstaking": {
            "info": [
              "Unstaking takes up to the next epoch to deactivate (~2.1 days) and withdraw."
            ],
            "unStakeCooldownPeriodDesc": "1 epoch (2.1 days)"
          },
          "nextRewards": {
            "rewardCycle": 181440
          }
        }
      }
    }
  ],
  "page": 1,
  "totalPages": 1,
  "totalElements": 1
}

See Also