A stateless SDK and REST API server for interacting with Fireblocks and the Stacks Network, enabling secure operations on Stacks using Fireblocks services.
The SDK Typedocs can be found here: https://fireblocks.github.io/stacks-fireblocks-sdk/
Stacks Fireblocks SDK lets you securely execute Stacks transactions using Fireblocks vaults and raw signing. It's designed to simplify integration with Fireblocks for secure Stacks transactions, supporting both direct SDK use and a REST API interface.
git clone https://github.com/fireblocks/stacks-fireblocks-sdk
cd stacks-fireblocks-sdk
npm install
cp .env.example .env
Edit .env to include your API key, private key path, and Stacks network config.
To start the SDK in dev mode:
npm run dev
cp .env.example .env # or create your .env manually
# Make sure your Fireblocks secret key is in ./secrets/fireblocks_secret.key
docker-compose up --build #(Dev Mode)
docker-compose -f docker-compose.yml up --build #(Prod Mode)
API will run on port
3000by default. Change viaPORTin.env.
Environment variables (via .env) control SDK behavior:
| Variable | Required | Default | Description |
|---|---|---|---|
| FIREBLOCKS_API_KEY | Yes | — | Your Fireblocks API key |
| FIREBLOCKS_SECRET_KEY_PATH | Yes | — | Path to your Fireblocks secret key file |
| FIREBLOCKS_BASE_PATH | No | BasePath.US from "@fireblocks/ts-sdk" | Base URL of the Fireblocks API |
| NETWORK | No | MAINNET | Stacks mainnet or testnet |
| PORT | No | 3000 | Port to run the REST API server |
.env:FIREBLOCKS_BASE_PATH=https://api.fireblocks.io/v1
FIREBLOCKS_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
FIREBLOCKS_SECRET_KEY_PATH=./secrets/fireblocks_secret.key
STACKS_NETWORK=TESTNET
PORT=3000
Note: Setting STACKS_NETWORK to anything other than TESTNET (or testnet) will set the network as mainnet.
🔒 Never commit your
.envfile or secret key to source control.
./secrets/fireblocks_secret.key
.env should reference this file relative to the project root:FIREBLOCKS_SECRET_KEY_PATH=./secrets/fireblocks_secret.key
volumes:
- ./secrets/fireblocks_secret.key:/app/secrets/fireblocks_secret.key:ro
import { StacksSDK } from "./StacksSDK";
import { FireblocksConfig } from "./services/types";
const fireblocksConfig: FireblocksConfig = {
apiKey: process.env.FIREBLOCKS_API_KEY!,
apiSecret: fs.readFileSync(process.env.FIREBLOCKS_SECRET_KEY_PATH!, "utf8"),
testnet: true, // or false for mainnet
};
const sdk = await StacksSDK.create("YOUR_VAULT_ID", fireblocksConfig);
// Get Stacks address
const address = sdk.getAddress();
console.log("Stacks Address:", address);
// Get public key
const publicKey = sdk.getPublicKey();
console.log("Public Key:", publicKey);
// Get BTC rewards address (for stacking)
const btcAddress = sdk.getBtcRewardsAddress();
console.log("BTC Rewards Address:", btcAddress);
// Get native STX balance
const balanceResponse = await sdk.getBalance();
if (balanceResponse.success) {
console.log("STX Balance:", balanceResponse.balance);
}
// Get fungible token balances
const ftBalances = await sdk.getFtBalances();
if (ftBalances.success) {
ftBalances.data?.forEach((token) => {
console.log(`${token.token}: ${token.balance}`);
});
}
// Basic STX transfer
const transferResponse = await sdk.createNativeTransaction(
"ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG", // recipient
10.5, // amount in STX
false, // grossTransaction (if true, fee is deducted from amount)
"Payment for services", // optional note
);
if (transferResponse.success) {
console.log("Transaction Hash:", transferResponse.txHash);
}
// Gross transaction (fee deducted from recipient)
const grossTransfer = await sdk.createNativeTransaction(
"ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG",
10.5,
true, // fee will be deducted from the 10.5 STX
);
import { TokenType } from "./services/types";
// Transfer sBTC
const ftTransfer = await sdk.createFTTransaction(
"ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG",
0.1, // amount in token units
TokenType.sBTC,
"sBTC payment",
);
if (ftTransfer.success) {
console.log("Transaction Hash:", ftTransfer.txHash);
}
const status = await sdk.checkStatus();
if (status.success) {
console.log("Balance Information:");
console.log(" Total STX:", status.data?.balance.stx_total);
console.log(" Locked STX:", status.data?.balance.stx_locked);
console.log(" Unlock Height:", status.data?.balance.burnchain_unlock_height);
console.log("\nDelegation Status:");
console.log(" Is Delegated:", status.data?.delegation.is_delegated);
console.log(" Delegated To:", status.data?.delegation.delegated_to);
console.log(" Amount:", status.data?.delegation.amount_delegated);
}
// Stack 150,000 STX for 6 cycles
const stackResponse = await sdk.stackSolo(
150000, // amount in STX
6, // lock period in cycles (1-12)
BigInt(Date.now()), // optional authId
);
if (stackResponse.success) {
console.log("Stacking Transaction Hash:", stackResponse.txHash);
console.log("BTC rewards will be sent to:", sdk.getBtcRewardsAddress());
} else {
console.error("Stacking failed:", stackResponse.error);
}
// Delegate to a stacking pool
const delegateResponse = await sdk.delegateToPool(
"SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP", // pool address
"stacking-pool-v1", // pool contract name
50000, // amount to delegate
12, // lock period in cycles
);
// Allow a pool to lock your STX
const allowCallerResponse = await sdk.allowContractCaller(
"SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP",
"stacking-pool-v1",
);
// Revoke delegation
const revokeResponse = await sdk.revokeDelegation();
// Get transaction status with error code mapping
const txStatus = await sdk.getTxStatusById("0xabcd1234...");
if (txStatus.success) {
console.log("Status:", txStatus.data?.tx_status);
if (txStatus.data?.tx_status !== "success") {
console.log("Error:", txStatus.data?.tx_error);
console.log("Error Code:", txStatus.data?.tx_result?.repr);
}
}
// Get transaction history (cached)
const history = await sdk.getTransactionHistory(true);
// Get fresh transaction history with pagination
const freshHistory = await sdk.getTransactionHistory(
false, // don't use cache
50, // limit
0, // offset
);
history.forEach((tx) => {
console.log(`${tx.transaction_hash}: ${tx.tx_type} - ${tx.tx_status}`);
});
| Method | Route | Description |
|---|---|---|
| GET | /api/:vaultId/address |
Fetch the Stacks address associated with the given vault |
| GET | /api/:vaultId/publicKey |
Retrieve the public key for the vault account |
| GET | /api/:vaultId/btc-rewards-address |
Get the BTC rewards address associated with the given vault (for stacking) |
| Method | Route | Description |
|---|---|---|
| GET | /api/:vaultId/balance |
Get the native STX balance |
| GET | /api/:vaultId/ft-balances |
Get all fungible token balances for the vault |
| Method | Route | Description |
|---|---|---|
| GET | /api/:vaultId/transactions |
List recent transactions for this vault |
| GET | /api/:vaultId/transactions/:txId |
Get detailed transaction status with error code mapping |
| POST | /api/:vaultId/transfer |
Transfer STX or Fungible Tokens to another address |
| Method | Route | Description |
|---|---|---|
| GET | /api/:vaultId/check-status |
Check account stacking status and delegation info |
| POST | /api/:vaultId/stacking/solo |
Solo stack STX with automatic signer signature |
| POST | /api/:vaultId/stacking/pool/delegate |
Delegate amonunt of STX to a stacking pool |
| POST | /api/:vaultId/stacking/pool/allow-contract-caller |
Allow a pool contract to lock your STX |
| POST | /api/:vaultId/revoke-delegation |
Revoke any active STX delegation |
| Method | Route | Description |
|---|---|---|
| GET | /api/metrics |
Prometheus-compatible service metrics |
/api/:vaultId/transactions/:txId endpoint.Expected ≈(Your STX / Total Stacked) × Total BTC from MinersPool Stacking:
✅ Lower minimum (pool operators set their own minimum)
✅ No signer infrastructure required
✅ Pool handles all technical operations
❌ Pool takes a commission
❌ Less control over reward address
Note: For pool stacking, delegate the amount you want to stack to the pool and allow the pool contract as contract-caller to lock your STX, the pool will handle the rest and lock STX when ready and distirbute rewards at the end of locking period.
Solo Stacking:
curl -X 'GET' \
'http://localhost:3000/api/123/address' \
-H 'accept: application/json'
curl -X 'GET' \
'http://localhost:3000/api/123/balance' \
-H 'accept: application/json'
curl -X 'POST' \
'http://localhost:3000/api/123/transfer/stx' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"recipientAddress": "ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG",
"amount": 100.5,
"grossTransaction": false,
"note": "Payment for services"
}'
curl -X 'POST' \
'http://localhost:3000/api/123/stack/solo' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"amount": 150000,
"lockPeriod": 6
}'
curl -X 'GET' \
'http://localhost:3000/api/123/status' \
-H 'accept: application/json'
curl -X 'GET' \
'http://localhost:3000/api/123/tx/0xabcd1234...' \
-H 'accept: application/json'
npm run dev
npm test
npm run build
Swagger UI API Documentation will be available at http://localhost:3000/api-docs after running the project.
.env or secrets.https://api.hiro.soSP000000000000000000002Q6VF78.pox-4https://api.testnet.hiro.soST000000000000000000002AMW42H.pox-4