FortiBlox LogoFortiBlox Docs
NexusgRPC API

Getting Started with gRPC

Install gRPC clients and start streaming blockchain data in 5 minutes

Getting Started with gRPC

This guide will help you connect to FortiBlox gRPC and start streaming blockchain data in minutes.

Prerequisites

  • API Key - Generate from Nexus Dashboard
  • Network access - Professional tier required for mainnet
  • Development environment - Node.js, Python, Rust, or Go

Quick Start

Install Dependencies

npm install @grpc/grpc-js @grpc/proto-loader

Download Protocol Buffers

curl -O https://raw.githubusercontent.com/rpcpool/yellowstone-grpc/master/yellowstone-grpc-proto/proto/geyser.proto

Create Client

// grpc-client.js
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

// Load protocol buffers
const packageDefinition = protoLoader.loadSync('geyser.proto', {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true
});

const proto = grpc.loadPackageDefinition(packageDefinition);

// Create client
const client = new proto.geyser.Geyser(
  'grpc.fortiblox.com:443',
  grpc.credentials.createSsl()
);

// Add API key metadata
const metadata = new grpc.Metadata();
metadata.add('x-api-key', process.env.FORTIBLOX_API_KEY);

// Create bidirectional stream
const stream = client.subscribe(metadata);

// Subscribe to transactions
stream.write({
  transactions: {
    'all_txs': {
      vote: false,
      failed: false,
      accountInclude: []
    }
  },
  commitment: 'CONFIRMED'
});

// Handle updates
stream.on('data', (update) => {
  if (update.transaction) {
    console.log('Transaction:', update.transaction.transaction.signature);
  }
});

stream.on('error', (err) => {
  console.error('Stream error:', err);
});

stream.on('end', () => {
  console.log('Stream ended');
});

Run

export FORTIBLOX_API_KEY="your_api_key"
node grpc-client.js

Install Dependencies

pip install grpcio grpcio-tools

Generate Python Code from Proto

# Download proto file
curl -O https://raw.githubusercontent.com/rpcpool/yellowstone-grpc/master/yellowstone-grpc-proto/proto/geyser.proto

# Generate Python code
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. geyser.proto

Create Client

# grpc_client.py
import grpc
import os
import geyser_pb2
import geyser_pb2_grpc

# Create channel with SSL
credentials = grpc.ssl_channel_credentials()
channel = grpc.secure_channel(
    'grpc.fortiblox.com:443',
    credentials
)

# Create stub
stub = geyser_pb2_grpc.GeyserStub(channel)

# Prepare metadata
metadata = [('x-api-key', os.getenv('FORTIBLOX_API_KEY'))]

# Create subscription request
def request_generator():
    yield geyser_pb2.SubscribeRequest(
        transactions={
            'all_txs': geyser_pb2.SubscribeRequestFilterTransactions(
                vote=False,
                failed=False,
                account_include=[]
            )
        },
        commitment=geyser_pb2.CommitmentLevel.CONFIRMED
    )

# Subscribe
try:
    for update in stub.Subscribe(request_generator(), metadata=metadata):
        if update.HasField('transaction'):
            tx = update.transaction.transaction
            print(f"Transaction: {tx.signature.hex()}")
        elif update.HasField('slot'):
            print(f"Slot: {update.slot.slot}")

except grpc.RpcError as e:
    print(f"gRPC error: {e.code()} - {e.details()}")

Run

export FORTIBLOX_API_KEY="your_api_key"
python grpc_client.py

Add Dependencies

# Cargo.toml
[dependencies]
tonic = "0.11"
prost = "0.12"
tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1"

[build-dependencies]
tonic-build = "0.11"

Build Script

// build.rs
fn main() -> Result<(), Box<dyn std::error::Error>> {
    tonic_build::compile_protos("proto/geyser.proto")?;
    Ok(())
}

Create Client

// src/main.rs
use tonic::{transport::Channel, metadata::MetadataValue, Request};
use tokio_stream::StreamExt;

pub mod geyser {
    tonic::include_proto!("geyser");
}

use geyser::{geyser_client::GeyserClient, SubscribeRequest};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create channel
    let channel = Channel::from_static("https://grpc.fortiblox.com:443")
        .connect()
        .await?;

    let mut client = GeyserClient::new(channel);

    // Create request with API key
    let api_key = std::env::var("FORTIBLOX_API_KEY")?;
    let token = MetadataValue::try_from(api_key)?;

    let mut request = Request::new(tokio_stream::iter(vec![
        SubscribeRequest {
            transactions: std::collections::HashMap::from([(
                "all_txs".to_string(),
                geyser::SubscribeRequestFilterTransactions {
                    vote: Some(false),
                    failed: Some(false),
                    ..Default::default()
                }
            )]),
            commitment: Some(geyser::CommitmentLevel::Confirmed as i32),
            ..Default::default()
        }
    ]));

    request.metadata_mut().insert("x-api-key", token);

    // Subscribe
    let mut stream = client.subscribe(request).await?.into_inner();

    // Process updates
    while let Some(update) = stream.next().await {
        match update {
            Ok(msg) => {
                if let Some(tx) = msg.transaction {
                    println!("Transaction: {:?}", tx.signature);
                }
            }
            Err(e) => eprintln!("Error: {}", e),
        }
    }

    Ok(())
}

Run

export FORTIBLOX_API_KEY="your_api_key"
cargo run

Install Dependencies

go get google.golang.org/grpc
go get google.golang.org/protobuf

Generate Go Code

# Install protoc-gen-go
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

# Download proto
curl -O https://raw.githubusercontent.com/rpcpool/yellowstone-grpc/master/yellowstone-grpc-proto/proto/geyser.proto

# Generate code
protoc --go_out=. --go-grpc_out=. geyser.proto

Create Client

// main.go
package main

import (
    "context"
    "fmt"
    "io"
    "log"
    "os"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/metadata"

    pb "your-module/geyser"
)

func main() {
    // Create secure connection
    creds := credentials.NewTLS(nil)
    conn, err := grpc.Dial(
        "grpc.fortiblox.com:443",
        grpc.WithTransportCredentials(creds),
    )
    if err != nil {
        log.Fatalf("Failed to connect: %v", err)
    }
    defer conn.Close()

    // Create client
    client := pb.NewGeyserClient(conn)

    // Add API key to context
    md := metadata.New(map[string]string{
        "x-api-key": os.Getenv("FORTIBLOX_API_KEY"),
    })
    ctx := metadata.NewOutgoingContext(context.Background(), md)

    // Create stream
    stream, err := client.Subscribe(ctx)
    if err != nil {
        log.Fatalf("Failed to subscribe: %v", err)
    }

    // Send subscription request
    req := &pb.SubscribeRequest{
        Transactions: map[string]*pb.SubscribeRequestFilterTransactions{
            "all_txs": {
                Vote:   false,
                Failed: false,
            },
        },
        Commitment: pb.CommitmentLevel_CONFIRMED,
    }

    if err := stream.Send(req); err != nil {
        log.Fatalf("Failed to send request: %v", err)
    }

    // Receive updates
    for {
        update, err := stream.Recv()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatalf("Stream error: %v", err)
        }

        if tx := update.GetTransaction(); tx != nil {
            fmt.Printf("Transaction: %x\n", tx.Transaction.Signature)
        }
    }
}

Run

export FORTIBLOX_API_KEY="your_api_key"
go run main.go

Connection Configuration

TLS/SSL

Always use secure connections in production:

// Enable SSL
const client = new proto.geyser.Geyser(
  'grpc.fortiblox.com:443',
  grpc.credentials.createSsl()
);

Metadata Headers

Required headers for authentication:

const metadata = new grpc.Metadata();
metadata.add('x-api-key', process.env.FORTIBLOX_API_KEY);
metadata.add('x-client-version', '1.0.0'); // Optional

Timeouts and Deadlines

Set appropriate timeouts:

const deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 30);

const call = client.subscribe(metadata, { deadline });

Subscription Patterns

Filter by Account

Monitor specific accounts:

stream.write({
  transactions: {
    'jupiter': {
      accountInclude: ['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'],
      vote: false
    }
  }
});

Filter by Program

Track program interactions:

stream.write({
  transactions: {
    'token_program': {
      accountInclude: ['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'],
      vote: false
    }
  }
});

Multiple Subscriptions

Subscribe to different event types:

stream.write({
  transactions: {
    'swaps': { accountInclude: ['JUP6...'], vote: false }
  },
  slots: {
    'slot_updates': {}
  },
  blocks: {
    'new_blocks': {}
  },
  commitment: 'CONFIRMED'
});

Error Handling

Connection Errors

stream.on('error', (err) => {
  console.error('Stream error:', err.code, err.message);

  // Reconnect logic
  if (err.code === grpc.status.UNAVAILABLE) {
    setTimeout(() => reconnect(), 5000);
  }
});

Automatic Reconnection

function createStream() {
  const stream = client.subscribe(metadata);

  stream.on('error', (err) => {
    console.error('Stream error:', err);
    setTimeout(() => createStream(), 5000);
  });

  stream.on('end', () => {
    console.log('Stream ended, reconnecting...');
    setTimeout(() => createStream(), 1000);
  });

  // Subscribe
  stream.write({
    transactions: { 'all': { vote: false } }
  });

  return stream;
}

let stream = createStream();

Health Checks

Test connection with ping:

client.ping({ count: 1 }, metadata, (err, response) => {
  if (err) {
    console.error('Ping failed:', err);
  } else {
    console.log('Ping successful:', response);
  }
});

Next Steps

Troubleshooting

Connection Refused

  • Check network tier (mainnet requires Professional+)
  • Verify endpoint and port
  • Ensure firewall allows outbound connections

Authentication Errors

  • Verify API key is correct
  • Check metadata header name (x-api-key)
  • Ensure API key has gRPC access enabled

No Data Received

  • Verify subscription filters
  • Check commitment level
  • Ensure events match your filters

Support