Skip to content

GraphQL API

Full Sui GraphQL RPC with complete chain history - served through a single endpoint.

Overview

Inodra runs the Sui GraphQL RPC service on its own infrastructure, backed by both live indexing and archival storage. You get the exact same schema as Sui's public GraphQL endpoint, with one endpoint covering everything from the genesis checkpoint to the chain tip.

Endpoint: https://mainnet-api.inodra.com/v1/graphql

Key features:

  • Complete history - every checkpoint, transaction, and object version since genesis
  • Schema introspection enabled - works out of the box with GraphiQL, Apollo, and codegen tools

How It Works

Behind the endpoint, Inodra combines two data sources:

  1. Live indexed data - recent checkpoints, transactions, objects, and events are indexed in real time and served with low latency.
  2. Archival storage - older data is served from Inodra's archival storage.

You don't need to think about which source a query hits - point lookups (a checkpoint by sequence number, a transaction by digest, an object at a version) work across the entire chain history through the same endpoint and the same queries.

Quick Start

1. Basic Setup

javascript
const GRAPHQL_URL = 'https://mainnet-api.inodra.com/v1/graphql'
const API_KEY = 'YOUR_API_KEY'

async function queryGraphQL(query, variables = {}) {
  const response = await fetch(GRAPHQL_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': API_KEY
    },
    body: JSON.stringify({ query, variables })
  })

  return response.json()
}

2. Your First Query

javascript
const query = `
  query LatestCheckpoints {
    checkpoints(last: 5) {
      nodes {
        sequenceNumber
        digest
        timestamp
        networkTotalTransactions
      }
    }
  }
`

const result = await queryGraphQL(query)
console.log('Latest checkpoints:', result.data.checkpoints.nodes)

Using the Sui SDK

The official Sui SDK provides SuiGraphQLClient with type-safe queries:

typescript
import { SuiGraphQLClient } from '@mysten/sui/graphql'
import { graphql } from '@mysten/sui/graphql/schema'

const client = new SuiGraphQLClient({
  url: 'https://mainnet-api.inodra.com/v1/graphql',
  headers: { 'x-api-key': 'YOUR_API_KEY' }
})

// Type-safe query with autocomplete
const chainQuery = graphql(`
  query {
    chainIdentifier
  }
`)

const result = await client.query({ query: chainQuery })
console.log('Chain:', result.data?.chainIdentifier)

The graphql() function provides compile-time type checking for your queries, catching errors before runtime.

Querying Historical Data

The same queries work across the full chain history - no separate archival endpoint:

graphql
query HistoricalData {
  # Checkpoint from 2023 - old data served from archival storage
  checkpoint(sequenceNumber: 1000) {
    digest
    timestamp
    epoch {
      epochId
    }
  }

  # The Clock object as it was at a specific checkpoint
  object(address: "0x6", atCheckpoint: 50000000) {
    version
    digest
    asMoveObject {
      contents {
        json
      }
    }
  }

  # Any past epoch, with totals and gas data
  epoch(epochId: 100) {
    startTimestamp
    endTimestamp
    totalTransactions
    referenceGasPrice
  }
}

Pagination

GraphQL uses cursor-based pagination on every connection:

javascript
async function getAllTransactions(address) {
  const allTransactions = []
  let hasNextPage = true
  let cursor = null

  while (hasNextPage) {
    const query = `
      query PaginatedTransactions($address: SuiAddress!, $after: String) {
        transactions(filter: { affectedAddress: $address }, first: 50, after: $after) {
          nodes {
            digest
            effects {
              status
            }
          }
          pageInfo {
            hasNextPage
            endCursor
          }
        }
      }
    `

    const result = await queryGraphQL(query, { address, after: cursor })
    const txData = result.data.transactions

    allTransactions.push(...txData.nodes)
    hasNextPage = txData.pageInfo.hasNextPage
    cursor = txData.pageInfo.endCursor
  }

  return allTransactions
}

Using with GraphQL Clients

Apollo Client

javascript
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'

const httpLink = createHttpLink({
  uri: 'https://mainnet-api.inodra.com/v1/graphql'
})

const authLink = setContext((_, { headers }) => ({
  headers: {
    ...headers,
    'x-api-key': 'YOUR_API_KEY'
  }
}))

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
})

urql

javascript
import { Client, cacheExchange, fetchExchange } from 'urql'

const client = new Client({
  url: 'https://mainnet-api.inodra.com/v1/graphql',
  exchanges: [cacheExchange, fetchExchange],
  fetchOptions: {
    headers: {
      'x-api-key': 'YOUR_API_KEY'
    }
  }
})

Requests exceeding these limits return a GraphQL error rather than partial data.

Credits & Billing

GraphQL billing matches the other gateways:

  • Queries: 1 credit per request, regardless of complexity
  • Transactions: 5 credits for the executeTransaction mutation or a simulateTransaction query - same as send/dry-run/simulate on JSON-RPC and gRPC

Batching multiple lookups into a single query (e.g. with multiGet* fields) still costs 1 credit - a single GraphQL request is a single API call.

Error Handling

javascript
async function safeGraphQLQuery(query, variables = {}) {
  try {
    const result = await queryGraphQL(query, variables)

    if (result.errors) {
      console.error('GraphQL Errors:', result.errors)
      throw new Error(`GraphQL Errors: ${result.errors.map((e) => e.message).join(', ')}`)
    }

    return result.data
  } catch (error) {
    console.error('Query failed:', error)
    throw error
  }
}

GraphQL Schema Reference

Inodra serves the official Sui GraphQL RPC schema. For complete documentation of all types, fields, and arguments, refer to:

  • Sui GraphQL Documentation - Official Sui GraphQL reference
  • Schema introspection - the endpoint has introspection enabled, so any GraphQL IDE (GraphiQL, Altair, Apollo Sandbox) can explore the live schema directly

When to Use GraphQL

Perfect for:

  • Applications needing flexible, complex queries in a single round trip
  • Frontend applications with varying data requirements
  • Historical analysis that mixes point lookups with recent data
  • Projects already using GraphQL in their stack

Consider gRPC instead if you need streaming, maximum throughput, or binary efficiency - see the gRPC gateway.

Next Steps

Released under the MIT License.