Skip to main content
The hive-tx library provides three methods for querying the Hive blockchain: callRPC, callREST, and callWithQuorum. This guide shows you how to use each one effectively.

RPC API Calls

Use callRPC to call JSON-RPC 2.0 methods on Hive nodes.

Basic RPC Calls

import { callRPC } from 'hive-tx'

// Get account information
const accounts = await callRPC('condenser_api.get_accounts', [['alice', 'bob']])
console.log(accounts[0].name) // 'alice'
console.log(accounts[0].balance) // '1000.000 HIVE'

// Get dynamic global properties
const props = await callRPC('condenser_api.get_dynamic_global_properties', [])
console.log('Head block:', props.head_block_number)
console.log('Total HIVE:', props.current_supply)

// Get post content
const post = await callRPC('condenser_api.get_content', ['alice', 'my-post-permlink'])
console.log('Title:', post.title)
console.log('Body:', post.body)
console.log('Upvotes:', post.net_votes)

Common RPC Methods

Account APIs

// Get accounts
callRPC('condenser_api.get_accounts', [['alice']])

// Get account history
callRPC('condenser_api.get_account_history', [
  'alice',
  -1,    // start (most recent)
  1000   // limit
])

// Get followers
callRPC('condenser_api.get_followers', [
  'alice',
  '',      // start follower
  'blog',  // type
  100      // limit
])

Content APIs

// Get post
callRPC('condenser_api.get_content', [
  'author',
  'permlink'
])

// Get discussions (feed)
callRPC('condenser_api.get_discussions_by_blog', [{
  tag: 'alice',
  limit: 20
}])

// Get active votes
callRPC('condenser_api.get_active_votes', [
  'author',
  'permlink'
])

Blockchain APIs

// Get block
callRPC('condenser_api.get_block', [12345678])

// Get block header
callRPC('condenser_api.get_block_header', [12345678])

// Get config
callRPC('condenser_api.get_config', [])

Witness APIs

// Get witnesses
callRPC('condenser_api.get_witnesses', [['witness1']])

// Get witness by account
callRPC('condenser_api.get_witness_by_account', [
  'witness1'
])

// Get witness schedule
callRPC('condenser_api.get_witness_schedule', [])

Custom Timeout and Retry

import { callRPC } from 'hive-tx'

// Default: 4000ms timeout, 3 retries
const data1 = await callRPC('condenser_api.get_accounts', [['alice']])

// Custom timeout (10 seconds)
const data2 = await callRPC(
  'condenser_api.get_content',
  ['author', 'permlink'],
  10_000  // 10 second timeout
)

// Custom retry count (8 attempts)
const data3 = await callRPC(
  'condenser_api.get_dynamic_global_properties',
  [],
  4000,  // timeout
  8      // retry attempts
)
The library automatically switches to the next node in the list on failure and retries the request.

Error Handling

import { callRPC, RPCError } from 'hive-tx'

try {
  const accounts = await callRPC('condenser_api.get_accounts', [['nonexistent']])
  
  if (accounts.length === 0) {
    console.log('Account not found')
  }
  
} catch (error) {
  if (error instanceof RPCError) {
    console.error('RPC Error:', error.message)
    console.error('Error code:', error.code)
    console.error('Error data:', error.data)
  } else {
    console.error('Network or other error:', error)
  }
}

REST API Calls

Use callREST for type-safe REST API calls to specialized Hive APIs.

Available REST APIs

  • balance - Account balance and history
  • hafah - HAF Account History
  • hafbe - HAF Block Explorer
  • hivemind - Social layer (follows, communities)
  • hivesense - Analytics and statistics
  • reputation - Account reputation
  • nft-tracker - NFT tracking
  • hafsql - SQL queries
  • status - Node status

Balance API

import { callREST } from 'hive-tx'

// Get account balances
const balances = await callREST(
  'balance',
  '/accounts/{account-name}/balances',
  { 'account-name': 'alice' }
)
console.log('HIVE balance:', balances.hive)
console.log('HBD balance:', balances.hbd)

// Get aggregated history
const history = await callREST(
  'balance',
  '/accounts/{account-name}/aggregated-history',
  {
    'account-name': 'alice',
    'coin-type': 'HBD',
    'from-block': 0,
    'to-block': 10000000
  }
)

Status API

import { callREST } from 'hive-tx'

// Get node status
const status = await callREST('status', '/status')
console.log('Node version:', status.version)
console.log('Head block:', status.head_block_num)
console.log('Synced:', status.sync_status)

Path and Query Parameters

import { callREST } from 'hive-tx'

// Path parameters are replaced in the URL
const data1 = await callREST(
  'balance',
  '/accounts/{account-name}/balances',
  { 'account-name': 'alice' }  // Replaces {account-name} in path
)

// Remaining parameters become query strings
const data2 = await callREST(
  'balance',
  '/accounts/{account-name}/aggregated-history',
  {
    'account-name': 'alice',    // Path parameter
    'coin-type': 'HIVE',        // Query parameter: ?coin-type=HIVE
    'from-block': 0,            // Query parameter: &from-block=0
    'to-block': 1000000         // Query parameter: &to-block=1000000
  }
)

Custom Timeout and Retry

import { callREST } from 'hive-tx'

// With custom timeout and retry
const data = await callREST(
  'status',
  '/status',
  undefined,  // no parameters
  10_000,     // 10 second timeout
  5           // 5 retry attempts
)

REST Error Handling

import { callREST } from 'hive-tx'

try {
  const balances = await callREST(
    'balance',
    '/accounts/{account-name}/balances',
    { 'account-name': 'alice' }
  )
  
} catch (error) {
  if (error.message.includes('HTTP 404')) {
    console.error('Endpoint not found or wrong parameters')
  } else {
    console.error('Request failed:', error.message)
  }
}
REST API 404 errors often indicate incorrect parameters rather than missing data. Double-check your path and query parameters.

Quorum Calls for Critical Operations

Use callWithQuorum for critical operations that require consensus from multiple nodes:
import { callWithQuorum } from 'hive-tx'

// Get account balance with 2-node consensus (default)
const accounts = await callWithQuorum(
  'condenser_api.get_accounts',
  [['alice']]
)

// Require 3-node consensus for critical operation
const props = await callWithQuorum(
  'condenser_api.get_dynamic_global_properties',
  [],
  3  // quorum size
)

How Quorum Works

From call.ts:267-309:
  1. Calls random nodes in parallel batches
  2. Compares results using JSON.stringify
  3. Returns the first result that appears in at least quorum responses
  4. Automatically tries additional nodes if consensus not reached
// Example: Check if account exists with high confidence
import { callWithQuorum } from 'hive-tx'

try {
  const accounts = await callWithQuorum(
    'condenser_api.get_accounts',
    [['alice']],
    3  // require 3 nodes to agree
  )
  
  if (accounts.length > 0) {
    console.log('Account exists (confirmed by 3 nodes)')
  }
  
} catch (error) {
  if (error.message.includes("Couldn't reach quorum")) {
    console.error('Could not get consensus from nodes')
  } else if (error.message.includes('No more nodes available')) {
    console.error('All nodes failed')
  }
}
Use quorum calls for:
  • Account balance checks before large transfers
  • Verifying witness votes
  • Confirming proposal data
  • Any operation where data accuracy is critical
Quorum calls are slower because they query multiple nodes. Use them only when you need guaranteed data accuracy.

Configuring Nodes

Configure RPC and REST nodes globally:
import { config } from 'hive-tx'

// Configure RPC nodes
config.nodes = [
  'https://api.hive.blog',
  'https://api.deathwing.me',
  'https://api.openhive.network'
]

// Configure REST nodes
config.restNodes = [
  'https://rest.hive.blog',
  'https://rest.api.openhive.network'
]

// Configure timeout (milliseconds)
config.timeout = 10_000  // 10 seconds

// Configure retry attempts
config.retry = 5
The library automatically cycles through nodes on failure. Configure multiple nodes for high availability.

Complete Examples

Check Account Balance Before Transfer

import { callRPC, Transaction, PrivateKey } from 'hive-tx'

async function safeTransfer(
  from: string,
  to: string,
  amount: string,
  privateKey: PrivateKey
) {
  // Get account info
  const accounts = await callRPC('condenser_api.get_accounts', [[from]])
  
  if (accounts.length === 0) {
    throw new Error('Account not found')
  }
  
  // Parse balance
  const balance = parseFloat(accounts[0].balance.split(' ')[0])
  const transferAmount = parseFloat(amount.split(' ')[0])
  
  if (balance < transferAmount) {
    throw new Error(`Insufficient balance: ${balance} HIVE`)
  }
  
  // Create and broadcast transaction
  const tx = new Transaction()
  await tx.addOperation('transfer', {
    from,
    to,
    amount,
    memo: ''
  })
  
  tx.sign(privateKey)
  return await tx.broadcast(true)
}

// Usage
const key = PrivateKey.fromLogin('alice', 'password', 'active')
const result = await safeTransfer('alice', 'bob', '10.000 HIVE', key)
console.log('Transfer successful:', result.tx_id)

Get Post with Full Details

import { callRPC } from 'hive-tx'

async function getPostDetails(author: string, permlink: string) {
  // Get post content
  const post = await callRPC('condenser_api.get_content', [author, permlink])
  
  // Get active votes
  const votes = await callRPC('condenser_api.get_active_votes', [author, permlink])
  
  return {
    title: post.title,
    body: post.body,
    created: post.created,
    author: post.author,
    permlink: post.permlink,
    upvotes: votes.filter((v: any) => v.percent > 0).length,
    downvotes: votes.filter((v: any) => v.percent < 0).length,
    payout: post.pending_payout_value,
    replies: post.children
  }
}

// Usage
const details = await getPostDetails('alice', 'my-first-post')
console.log(details)

Monitor New Blocks

import { callRPC } from 'hive-tx'

async function watchBlocks(callback: (block: any) => void) {
  let lastBlock = 0
  
  setInterval(async () => {
    try {
      const props = await callRPC('condenser_api.get_dynamic_global_properties', [])
      const currentBlock = props.head_block_number
      
      if (currentBlock > lastBlock && lastBlock > 0) {
        // Get new blocks
        for (let i = lastBlock + 1; i <= currentBlock; i++) {
          const block = await callRPC('condenser_api.get_block', [i])
          callback(block)
        }
      }
      
      lastBlock = currentBlock
    } catch (error) {
      console.error('Error fetching blocks:', error)
    }
  }, 3000)  // Check every 3 seconds
}

// Usage
watchBlocks((block) => {
  console.log('New block:', block.block_id)
  console.log('Transactions:', block.transactions.length)
})

Next Steps

Build docs developers (and LLMs) love