NAV
javascript json graphql shell

Introduction

Welcome to the Hgraph.io GraphQL API! You can use the Hgraph.io API to access Hedera mainnet and testnet data.

FAQS

Data Formats

How does the API format data in comparison to the mirror node REST api?

Entity Id Format

Hgraph.io will return entity ids without the "0.0." prefix. The GraphQL API also expects any variable to be a bigint, and not include the "0.0." prefix. This is true for token ids, account ids, and topic ids.

When passing variables into a query, remember to remove the "0.0." from the variable first.

Metadata Format

Metadata values are returned in an encoded hex format. Decoding the metadata string is imperitive in order to interact with the metadata string or stringified JSON object.

Amount / Price Format

All amount values returned are in tiny bars. Be sure to convert the tinybars to HBARs before executing logic or sending back to the user.

const HBAR = amountReturnedFromQuery / 100000000

Timestamps

Timestamps are returned in numeric form, bigint, and do not fit into the standard javascript Number type. One has to take explicit care in conserving the precision of nanoseconds.

The adjacent example demonstrates getting the latest transaction from and fetching a corresponding REST API endpoint utilizing the json-bigint library.

import fetch from 'isomorphic-fetch'
import JSONBigInt from 'json-bigint'

const API_KEY = '<HGRAPH_API_KEY>'

const {parse, stringify} = JSONBigInt({
  useNativeBigInt: true,
  // alwaysParseAsBig: true,
})

BigInt.prototype.toJSON = function () {
  if (Number.MIN_SAFE_INTEGER < this && this < Number.MAX_SAFE_INTEGER) return Number(this)
  else return this.toString()
}

async function patchedFetch(...args) {
  const response = await fetch(...args)
  const text = await response.text()

  const json = parse(text)
  response.json = async () => json

  return response
}

async function main() {
  // return
  const response = await patchedFetch('https://beta.api.hgraph.io/v1/graphql', {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'x-api-key': API_KEY,
    },
    // JSON.stringify is okay here because we have no BigInts that need special treatment
    body: stringify({
      query: `
query LatestTransaction {
  transaction(limit: 1, order_by: {consensus_timestamp: desc}) {
    consensus_timestamp
    valid_start_ns
    payer_account_id
  }
}
`,
    }),
  })

  const json = await response.json()

  console.dir(json, {depth: null})

  console.log(stringify(json)) // can also use JSON.stringify because we declared the `.toJSON()` above

  // Test
  const {valid_start_ns, payer_account_id} = json.data.transaction[0]
  const transactionId = `0.0.${payer_account_id}-${valid_start_ns
    .toString()
    .substring(0, 10)}-${valid_start_ns.toString().substring(10)}`

  const restApiEndpoint = `https://mainnet-public.mirrornode.hedera.com/api/v1/transactions/${transactionId}`
  if (restApiEndpoint) console.log('🤞')

  const restResponse = await patchedFetch(restApiEndpoint)
  if (restResponse.ok) console.log('', response.status)
  else console.log('😕')

  console.dir(await restResponse.json(), {depth: null})
}

main()

Transaction Id

How do I construct a REST API transactionId?

The transactionId follows the format <entity_id>-<seconds>-<nanoseconds>

The GraphQL query to the right will return the latest transaction. An example output is in the json tab to the right. The javascript tab shows the formula for constructing the transaction id from this output.

Corresponding endpoints:

Supporting documentation:

query LatestTransaction {
  transaction(limit: 1, order_by: {consensus_timestamp: desc}) {
    consensus_timestamp
    valid_start_ns
    payer_account_id
  }
}
{
  "data": {
    "transaction": [
      {
        "consensus_timestamp": "1670266835889120003",
        "valid_start_ns": "1670266826039225748",
        "payer_account_id": 41099
      }
    ]
  }
}
const {valid_start_ns, payer_account_id} = json.data.transaction[0]
const transactionId = `0.0.${payer_account_id}-${valid_start_ns.substring(
  0,
  10
)}-${valid_start_ns.substring(10)}`

const restApiEndpoint = `https://mainnet-public.mirrornode.hedera.com/api/v1/transactions/${transactionId}`

Query Tips

Getting Transaction Values

When getting transaction values and aggregate transaction sums, be sure to only get the negative values.

If you don't specify only negative (HBAR leaving the account) the value will always be 0.

This is because the API will total the amount leaving as negative and the amount being received as positive which will always be 0.

In the example below, we remove all values under 1 HBAR (100,000,000 tiny bars). This is a good way to not have the fees of the transaction come back in the query.

transactions {
  crypto_transfer(where: {amount: {_lte: "-100000000"}}) {
    amount
  }
  sender_account_id
}

Authorization

Developer portal

The quickest way to get started is to use the GraphiQL editor on our developer portal.

The editor in our developer portal to help you develop queries specifically for your use case. You can also use whichever GraphQL client you choose.

If using a different client, you can inspect the network tab in your browser to find your current authorization token and add that as a header to your GraphQL IDE.

Authorization: Bearer <OAUTH_TOKEN>

Programmatic access

Hgraph.io uses API keys to allow programmatic access to the API. You can register for an API key at our developer portal.

Hgraph.io expects for the API key to be included in all API requests to the server in a header that looks like the following:

To authorize, add and x-api-key to each request. Here’s an example demonstrating the use of an API_KEY

curl -X POST "https://beta.api.hgraph.io/v1/graphql" \
-H 'Content-Type: application/json' \
-H 'x-api-key: <API_KEY>' \
-d '{"query":"query LatestTransaction {\\n transaction(limit: 1, order_by: {consensus_timestamp: desc}) {\\n consensus_timestamp\\n }\\n}\\n","variables":null,"operationName":"LatestTransaction"}'
// You can use whatever http client library you prefer for simple queries.
// We recommend using a GraphQL specific client for more robust use cases
import {fetch} from 'undici'

async function authenticateWithHgraph() {
  const response = await fetch('https://beta.api.hgraph.io/v1/graphql', {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'x-api-key': '<API_KEY>',
    },
    body: {
      query:
        'query LatestTransaction {\\n transaction(limit: 1, order_by: {consensus_timestamp: desc}) {\\n consensus_timestamp\\n }\\n}\\n',
    },
  })

  const json = response.json()

  // Do what you like with the data
  console.log(json)
}

authenticateWithHgraph()

Make sure to replace <API_KEY> with your API key.

Common Queries

Get the latest transaction timestamp

curl -X POST "https://beta.api.hgraph.io/v1/graphql" \
-H 'Content-Type: application/json' \
-H 'x-api-key: <API_KEY>' \
-d '{"query":"query LatestTransaction {\\n transaction(limit: 1, order_by: {consensus_timestamp: desc}) {\\n consensus_timestamp\\n }\\n}\\n","variables":null,"operationName":"LatestTransaction"}'

The example query above returns JSON structured like this:

{"data": {"transaction": [{"consensus_timestamp": 1665369499984826092}]}}

This query gets the timestamp of the most rescent transaction.

Get messages from topic id

Getting topic id messages through an api call is helpful to be able to easily read this information without needing to do a transaction through the Hedera SDKs.

// Don't use format 0.0.xxxxxx for account ids, token ids, or topic ids.
// Instead only use the integers after the 0.0. when talking to the API
const topicId = 1319899

const endpoint = 'https://beta.api.hgraph.io/v1/graphql'

// Create query for getting farming topic messages
const headers = {
  'content-type': 'application/json',
  'x-api-key': '<API_KEY> ',
}
const topicMessagesQuery = {
  operationName: 'GetFarmingHCS',
  query: `query GetFarmingHCS($topicId: bigint) {
            topic_message(where: {topic_id: {_eq: $topicId}}, order_by: {consensus_timestamp: desc}) {
                message
                sequence_number
                consensus_timestamp
            }
        }`,
  variables: {
    topicId: topicId,
  },
}

// This example shows how to use axios npm package
// to call Hgraph.io
const queryResponse = await axios({
  url: endpoint,
  method: 'post',
  headers: headers,
  data: topicMessagesQuery,
})

// Map to topic messages
const topicMessages = queryResponse.data.data.topic_message

Get NFT metadata string

When interacting with NFTs, it's important to be able to easily get the metadata string so you can execute logic based off of the metadata object variables.

This query will get the metadata string for a specific NFT by its token id and serial number.

// Example API call for token information
const queryVariables = {
  tokenId: 621100,
  serialNumber: 1,
}

// GraphQL call to get token information
const GetNftInfo = `
  nft(where: {serial_number: {_eq: $serialNumber}, token_id: {_eq: $tokenId}}) {
      metadata
  }
`

const body = {query: GetNftInfo, variables: queryVariables}

// Fetch call to post the GraphQL call to hgraph.io
// Set process.env.HGRAPH_API_KEY in your .env file or replace "process.env.HGRAPH_API_KEY with your key
const response = await fetch('https://beta.api.hgraph.io/v1/graphql', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.HGRAPH_API_KEY,
    'content-type': 'application/json',
  },
  body: JSON.stringify(body),
})

// Get JSON from fetch response
const res = await response.json()

The above command returns JSON structured like this:

{
  "data": {
    "nft": [
      {
        "metadata": "\\x697066733a2f2f6261667972656964747635726472686c727a6c69676f6b6a636577336c7577776d66346e6264746a34757a65686a6d7079366976753466716a76612f6d657461646174612e6a736f6e"
      }
    ]
  }
}

Function to convert encoded metadata strings

Metadata values are returned in an encoded format. This helper function easily decodes that value into the expected string in the message.

// Taking the reponse from the previous example:
// Map new variable to returned data.
const nft = res.data.data.nft

// Function used to convert hex ASCII (encoding of metadata on mainnet) to text
const getMetadataString = (hexx) => {
  let hex = hexx.toString() //force conversion
  hex = hex.split('\\x')[1]
  let str = ''
  for (let i = 0; i < hex.length; i += 2)
    str += String.fromCharCode(parseInt(hex.substr(i, 2), 16))
  return str
}

// Convert metadata string to usable IPFS CID string
const metadataString = getMetadataString(nft.metadata)

Sense token associated with an account id

A very common piece of data needed by developers is knowing whether a certain account id has a token id associated. Without the account id associating a particular token id, a developer cannot send tokens to that account.

This function allows developers to easily determine association by passing in the account id and token id in question.

// Sense if an account has associated the token id.
// If not, create transactions and send to client
const senseTokenAssociation = async (accountId, tokenId) => {
  // Set headers for hgraph.io
  const tokenAssociationEndpoint = 'https://beta.api.hgraph.io/v1/graphql'
  const tokenAssociationHeaders = {
    'content-type': 'application/json',
    'x-api-key': process.env.HGRAPH_SECRET,
  }

  // Call and sense token Association
  // token ids and account ids for queries
  const tokenAssociationQuery = {
    operationName: 'GetTokenAssociation',
    query: `query GetTokenAssociation($accountId: bigint, $tokenId: bigint) {
            token_account(where: {token_id: {_eq: $tokenId}, account_id: {_eq: $accountId}}) {
                associated
            }
        }`,
    variables: {
      accountId: accountId.split('.0.')[1],
      tokenId: tokenId.split('.0.')[1],
    },
  }

  // Example using axios npm package to post GraphQL query
  const userTokenAssociationQueryResponse = await axios({
    url: tokenAssociationEndpoint,
    method: 'post',
    headers: tokenAssociationHeaders,
    data: tokenAssociationQuery,
  })

  // Get data from response
  const data = userTokenAssociationQueryResponse.data
  const tokenAccount = data.data.token_account

  let associated = tokenAccount.length >= 1

  return {associated: associated}
}

Get NFTs held by account id

This query will return all of the NFTs held by a particular account id. In this example, the account id being passed to the function is in the standard entity id format (0.0.XXXXXXX).

// Get all NFTs being held by an account id
// Example input: accountId = "0.0.306412"
const getNftsHeldByAccountId = async (accountId) => {
  // call API to get farming NFTs from accountId
  const endpoint = 'https://beta.api.hgraph.io/v1/graphql'
  const headers = {
    'content-type': 'application/json',
    'x-api-key': process.env.HGRAPH_SECRET,
  }

  const nftsHeldByAccountIdQuery = {
    operationName: 'GetAccountNfts',
    query: `query GetAccountNfts($accountId: bigint) {
            nft(where: {account_id: {_eq: $accountId}}, order_by: {modified_timestamp: desc}) {
              account_id
              serial_number
              metadata
              token_id
              created_timestamp
              token {
                name
                treasury_account_id
              }
            }
          }`,
    variables: {
      accountId: accountId.split('0.0.')[1],
    },
  }
  const nftsHeldByAccountIdQueryResponse = await axios({
    url: endpoint,
    method: 'post',
    headers: headers,
    data: nftsHeldByAccountIdQuery,
  })

  // Get data from response
  const data = nftsHeldByAccountIdQueryResponse.data
  const nftsHeld = data.data.nft

  for (let index = 0; index < nftsHeld.length; index++) {
    const nftHeld = nftsHeld[index]
    // Uses previous metadata string function in example above
    nftHeld.metadata = getMetadataString(nftHeld.metadata)
    nftHeld.name = nftHeld.token.name
    nftHeld.treasury_account_id = nftHeld.token.treasury_account_id
  }

  return nftsHeld
}

Token and hbar balance snapshots

The account_balance node and the token_balance node (in the sense of a GraphQL query node) are balance snapshots. Every 15 minutes, the consensus nodes (Hedera network servers) calculate the hbar and token balances for every account and store those as snapshots. To see the most recent consensus timestamp for token_balances:

query MostRecentTokenBalanceConsensusTimestamp {
  token_balance(
    limit: 1
    order_by: {consensus_timestamp: desc}
    distinct_on: consensus_timestamp
  ) {
    account_id
    balance
    consensus_timestamp
  }
}

Get the top holders of a token

When saving snapshots, the token_balance consensus timestamp may not be updated if there was not a change in token balance for a given timestamp. First, find the most recent snapshot consensus_timestamp that has an entry for a token balance.

query MostRecentTokenBalanceConsensusTimestamp {
  token_balance(
    limit: 1
    order_by: {consensus_timestamp: desc}
    distinct_on: consensus_timestamp
  ) {
    account_id
    balance
    consensus_timestamp
  }
}
query TopHoldersOfToken($token_id: bigint, $consensus_timestamp: bigint) {
  token(where: {token_id: {_eq: $token_id}}) {
    type
    treasury_account_id
    total_supply
    symbol
    name
  }
  token_balance(where: {token_id: {_eq: $token_id}, consensus_timestamp: {_eq: $consensus_timestamp}, balance: {_gt: 0}}, order_by: {balance: desc}) {
    account_id
    balance
    consensus_timestamp
    token_id
  }
}