Crypto-as-a-Service

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>"
  }'

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