Infrastructure

Complete Guide to AllenHark Relay: HTTP & QUIC Integration for Solana Trading

December 11, 2025AllenHark Team

AllenHark Relay is a production-grade transaction relay service designed for traders, market makers, and automated systems that need low-latency transaction dispatch to the Solana network.

This comprehensive integration guide covers everything from API key authentication to advanced QUIC Protocol setup, tip validation requirements, and performance optimization strategies.

What is AllenHark Relay?

AllenHark Relay is a private transaction propagation network that bypasses the public Solana gossip network to deliver your transactions directly to validator TPU (Transaction Processing Unit) ports with:

  • Persistent QUIC connections — no per-request handshake when the transaction is ready
  • MEV protection through private transaction routing
  • Leader-aware delivery to current and upcoming block leaders
  • Multi-RPC broadcasting for maximum delivery reliability
  • API key authentication with configurable rate limits

Why Use a Private Relay?

Standard Solana RPC submission has critical limitations:

  1. Slow: 200-500ms propagation through gossip network
  2. Public: Transactions visible in mempool (vulnerable to front-running)
  3. Unreliable: Packets dropped during congestion
  4. No prioritization: Your high-value trades compete with spam

AllenHark Relay solves these problems with direct validator connections and priority routing.


Service Overview

Two Integration Options

AllenHark Relay supports two protocols to balance simplicity and performance:

Option 1: QUIC Protocol (Recommended)

Best for: Production trading systems, HFT bots, MEV operations

Advantages:

  • No per-request handshake — the connection is already open
  • 0-RTT connection resumption (instant reconnection)
  • Connection multiplexing (multiple transactions over one connection)
  • Consistently lower dispatch overhead than HTTPS

Port: 4433
Endpoint: relay.allenhark.com:4433 (Frankfurt alias — 88.216.36.108:4433)

Other regions: ams.relay.allenhark.com / 84.32.104.38:4433, ny.relay.allenhark.com / 74.214.174.50:4433, tyo.relay.allenhark.com / 88.216.188.28:4433.

Option 2: HTTPS REST API

Best for: Development, testing, low-frequency operations

Advantages:

  • Simple integration (standard HTTP client)
  • Wide language support (any HTTP library)
  • Easy debugging (use curl, Postman, etc.)

Latency: single-digit milliseconds when you're near a region, tens of milliseconds cross-region — use QUIC or WebSocket when latency matters
Endpoint: https://relay.allenhark.com/v1/sendTx

[!TIP] Start with HTTPS for development, migrate to QUIC for production. The API format is identical.


Getting Started

Step 1: Obtain API Credentials

AllenHark Relay uses API key authentication. Contact us to request access:

Request API Access

You'll receive:

  • API Key: an ak_-prefixed key, e.g. ak_1234567890
  • Rate Limit: Default 10 requests/second per key (customizable)
  • Support: Discord community access

The key is required on every request: as an x-api-key header, or as an ?api-key= query parameter. Over QUIC it is the first line of the stream; over WebSocket it is presented at upgrade.

Step 2: Understand Tip Requirements

Every transaction must include a tip transfer to one of the AllenHark tip wallets. The tip is paid inside the transaction itself — a top-level SystemProgram.transfer instruction — so nothing is charged to your account or invoiced for a relayed send. This economic model ensures:

  • Fair resource allocation
  • Spam prevention
  • Priority processing

Versioned (v0) transactions with address lookup tables are supported, provided the tip wallet is present in the static account keys. If the tip account is only reachable through a lookup table, the relay rejects the transaction with tip_hidden_in_alt.

Tip Wallets (select random):

const TIP_WALLETS = [
  "hark1zxc5Rz3K8Kquz79WPWFEgNCFeJnsMJ16f22uNP",
  "harkm2BTWxZuszoNpZnfe84jRbQTg6KGHaQBmWzDGQQ",
  "hark4CwtTnN2y9FaxjcFBAJdJqQrpouu5pgEixfqdEz",
  "harkoJfnM6dxrJydx5eVmDVwAgwC94KbhuxF69UbXwP",
  "hark6hUDUTekc1DGxWdJcuyDZwf6pJdCxd4SXAVtta6",
  "harkoTvFpKSrEQduYrNHXCurARVT19Ud3BnFhVxabos",
  "harkEpXoJv5qVzHaN7HSuUAd6PHjyMcFMcDYBMDJCEQ",
  "harkyXDdZSoJGyCxa24t2QXx1poPyp8YfghbtpzGSzK",
  "harkR2YJ4Dpt4UDJTcBirjnSPBhNpQFcoFkNpCkVqNk",
  "harkRBygM8pHYe4K8eBjfxyEX19oJn3LepFjvNbLbyi",
  "harkYFxB6DuUFNwDLvA5CQ66KpfRvFgUoVypMagNcmd",
];

function getRandomTipWallet() {
  return TIP_WALLETS[Math.floor(Math.random() * TIP_WALLETS.length)];
}

Minimum tip amount: 0.001 SOL (1,000,000 lamports)
Recommended during congestion: 0.002-0.005 SOL


Integration Guide: HTTPS REST API

The simplest way to get started. Perfect for development and testing.

API Specification

Endpoint: POST https://relay.allenhark.com/v1/sendTx
Alternative: POST https://relay.allenhark.com/broadcast

Request format:

{
  "tx": "BASE64_ENCODED_TRANSACTION",
  "simulate": false
}

Authentication Methods

Option 1: Header Authentication (Recommended)

curl -X POST https://relay.allenhark.com/v1/sendTx \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "tx": "BASE64_ENCODED_TRANSACTION",
    "simulate": false
  }'

Option 2: Query Parameter

curl -X POST "https://relay.allenhark.com/v1/sendTx?api-key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tx": "BASE64_ENCODED_TRANSACTION",
    "simulate": false
  }'

JavaScript/TypeScript Example

import fetch from 'node-fetch';
import { Transaction, Keypair, SystemProgram, LAMPORTS_PER_SOL, Connection } from '@solana/web3.js';
import bs58 from 'bs58';

const ALLENHARK_API_KEY = process.env.ALLENHARK_API_KEY!;
const TIP_WALLETS = [
  "hark1zxc5Rz3K8Kquz79WPWFEgNCFeJnsMJ16f22uNP",
  // ... (include all tip wallets)
];

async function sendTransactionViaRelay(
  transaction: Transaction,
  payer: Keypair
): Promise<{ status: string; request_id: string }> {
  // Add tip instruction
  const tipWallet = TIP_WALLETS[Math.floor(Math.random() * TIP_WALLETS.length)];
  const tipAmount = 0.001 * LAMPORTS_PER_SOL; // 0.001 SOL

  transaction.add(
    SystemProgram.transfer({
      fromPubkey: payer.publicKey,
      toPubkey: new PublicKey(tipWallet),
      lamports: tipAmount,
    })
  );

  // Get recent blockhash
  const connection = new Connection('https://api.mainnet-beta.solana.com');
  transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
  transaction.feePayer = payer.publicKey;

  // Sign transaction
  transaction.sign(payer);

  // Serialize to base64
  const txBase64 = transaction.serialize().toString('base64');

  // Submit to relay
  const response = await fetch('https://relay.allenhark.com/v1/sendTx', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': ALLENHARK_API_KEY,
    },
    body: JSON.stringify({
      tx: txBase64,
      simulate: false,
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Relay error: ${error.code} - ${error.message}`);
  }

  return await response.json();
}

// Usage
const tx = new Transaction();
// ... add your instructions ...

const result = await sendTransactionViaRelay(tx, myKeypair);
console.log(`Transaction relayed: ${result.request_id}`);

Rust Example

use reqwest::Client;
use serde_json::json;
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
    signature::{Keypair, Signer},
    system_instruction,
    transaction::Transaction,
    pubkey::Pubkey,
};
use std::str::FromStr;

const TIP_WALLETS: [&str; 11] = [
    "hark1zxc5Rz3K8Kquz79WPWFEgNCFeJnsMJ16f22uNP",
    // ... (include all)
];

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("ALLENHARK_API_KEY")?;
    let payer = Keypair::new(); // Your keypair

    // Create your transaction
    let rpc_client = RpcClient::new("https://api.mainnet-beta.solana.com");
    let recent_blockhash = rpc_client.get_latest_blockhash()?;

    // Add tip instruction
    let tip_wallet = Pubkey::from_str(
        TIP_WALLETS[rand::random::<usize>() % TIP_WALLETS.len()]
    )?;
    
    let tip_instruction = system::transfer(
        &payer.pubkey(),
        &tip_wallet,
        1_000_000, // 0.001 SOL in lamports
    );

    let mut transaction = Transaction::new_with_payer(
        &[tip_instruction /* , ...your other instructions */],
        Some(&payer.pubkey()),
    );
    
    transaction.sign(&[&payer], recent_blockhash);

    // Serialize to base64
    let tx_bytes = bincode::serialize(&transaction)?;
    let tx_base64 = base64::encode(&tx_bytes);

    // Send to relay
    let client = Client::new();
    let response = client
        .post("https://relay.allenhark.com/v1/sendTx")
        .header("x-api-key", api_key)
        .json(&json!({
            "tx": tx_base64,
            "simulate": false
        }))
        .send()
        .await?;

    if response.status().is_success() {
        let result: serde_json::Value = response.json().await?;
        println!("✓ Transaction relayed: {}", result["request_id"]);
    } else {
        let error: serde_json::Value = response.json().await?;
        eprintln!("✗ Error: {} - {}", error["code"], error["message"]);
    }

    Ok(())
}

Response Handling

Success response:

{
  "status": "accepted",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Error responses:

Error CodeDescriptionSolution
tip_missingNo tip to AllenHark walletAdd tip transfer instruction
tip_insufficientTip below 0.001 SOLIncrease tip amount
simulate_forbiddensimulate: true not allowedSet simulate: false
invalid_api_keyAPI key invalid or missingCheck API key value
rate_limit_exceededToo many requestsReduce request rate or contact us
invalid_transactionTransaction deserialization failedVerify transaction format
tip_hidden_in_altTip account only reachable via an address lookup tablePut the tip wallet in the static account keys

[!NOTE] Unknown keys are currently reported as rate_limit_exceeded; invalid_api_key is being rolled out.


Integration Guide: QUIC Protocol

For production systems where dispatch overhead matters.

QUIC Advantages Over HTTPS

  • 0-RTT Connection Resumption: No handshake overhead after first connection
  • Independent Stream Processing: No head-of-line blocking
  • Connection Multiplexing: many concurrent streams over one connection

Tradeoff: More complex implementation (requires QUIC library)

Rust Example (Quinn - Production Ready)

use quinn::{ClientConfig, Endpoint};
use rustls::RootCertStore;
use serde_json::json;
use std::sync::Arc;

struct RelayClient {
    endpoint: Endpoint,
    api_key: String,
}

impl RelayClient {
    pub async fn new(api_key: String) -> Result<Self, Box<dyn std::error::Error>> {
        // Configure TLS with system root certificates
        let mut roots = RootCertStore::empty();
        roots.add_trust_anchors(
            webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| {
                rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
                    ta.subject,
                    ta.spki,
                    ta.name_constraints,
                )
            }),
        );

        let client_config = ClientConfig::with_root_certificates(roots);
        
        let mut endpoint = Endpoint::client("0.0.0.0:0".parse()?)?;
        endpoint.set_default_client_config(client_config);

        Ok(Self { endpoint, api_key })
    }

    pub async fn send_transaction(
        &self,
        tx_base64: &str,
    ) -> Result<String, Box<dyn std::error::Error>> {
        // Connect to relay (uses 0-RTT on subsequent connections)
        let conn = self
            .endpoint
            .connect("relay.allenhark.com:4433".parse()?, "relay.allenhark.com")?
            .await?;

        // Open bidirectional stream
        let (mut send, mut recv) = conn.open_bi().await?;

        // Send API key header
        send.write_all(format!("api-key: {}\n", self.api_key).as_bytes())
            .await?;

        // Send transaction payload
        let payload = json!({
            "tx": tx_base64,
            "simulate": false
        });
        send.write_all(&serde_json::to_vec(&payload)?).await?;
        send.finish().await?;

        // Read response
        let response_bytes = recv.read_to_end(4096).await?;
        let response: serde_json::Value = serde_json::from_slice(&response_bytes)?;

        Ok(response["request_id"].as_str().unwrap().to_string())
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = RelayClient::new(std::env::var("ALLENHARK_API_KEY")?).await?;
    
    // First request: pays the QUIC handshake
    let request_id = client.send_transaction("BASE64_TX_1").await?;
    println!("Transaction 1: {}", request_id);
    
    // Subsequent requests: 0-RTT resumption, no handshake
    let request_id = client.send_transaction("BASE64_TX_2").await?;
    println!("Transaction 2: {} (0-RTT)", request_id);
    
    Ok(())
}

Python Example (aioquic)

import asyncio
import json
import os
from aioquic.asyncio import connect
from aioquic.quic.configuration import QuicConfiguration

class RelayClient:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.host = "relay.allenhark.com"
        self.port = 4433
    
    async def send_transaction(self, tx_base64: str) -> dict:
        """Send transaction via QUIC and return response."""
        config = QuicConfiguration(is_client=True)
        config.verify_mode = True
        
        async with connect(
            self.host,
            self.port,
            configuration=config,
        ) as client:
            # Open stream
            stream_id = client._quic.get_next_available_stream_id()
            
            # Send API key
            client._quic.send_stream_data(
                stream_id,
                f"api-key: {self.api_key}\n".encode()
            )
            
            # Send transaction
            payload = json.dumps({
                "tx": tx_base64,
                "simulate": False
            })
            client._quic.send_stream_data(
                stream_id,
                payload.encode(),
                end_stream=True
            )
            
            # Read response
            response_data = await client._quic.receive_stream_data(stream_id)
            return json.loads(response_data.decode())

async def main():
    client = RelayClient(os.environ["ALLENHARK_API_KEY"])
    
    # Send transaction
    response = await client.send_transaction("BASE64_TX")
    print(f"✓ Transaction relayed: {response['request_id']}")

if __name__ == "__main__":
    asyncio.run(main())

Rate Limits and Best Practices

Default Rate Limits

  • Default: 10 requests/second per API key
  • Daily limit: Unlimited

Custom Rate Limits

For high-volume trading (>1,000 tx/day), contact us for:

  • Dedicated rate limits
  • Custom SLA agreements
  • Priority support

Best Practices

1. Connection Pooling

QUIC: Maintain persistent connection

// Good: Reuse connection
let client = RelayClient::new(api_key).await?;
for tx in transactions {
    client.send_transaction(&tx).await?;
}

// Bad: New connection per TX (loses 0-RTT benefit)
for tx in transactions {
    let client = RelayClient::new(api_key).await?;
    client.send_transaction(&tx).await?;
}

HTTPS: Use HTTP keep-alive

// Good: Reuse HTTP agent
const agent = new https.Agent({ keepAlive: true });
const api = axios.create({
  baseURL: 'https://relay.allenhark.com',
  httpsAgent: agent,
});

// Use for all requests
await api.post('/v1/sendTx', payload);

2. Error Handling with Retry Logic

async function sendWithRetry(
  transaction: string,
  maxRetries: number = 3
): Promise<any> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fetch('https://relay.allenhark.com/v1/sendTx', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-api-key': API_KEY,
        },
        body: JSON.stringify({ tx: transaction, simulate: false }),
      });
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
      
      // Exponential backoff
      await new Promise(resolve => 
        setTimeout(resolve, 100 * Math.pow(2, attempt))
      );
    }
  }
}

3. Dynamic Tip Adjustment

Increase tips during network congestion:

const TIP_LEVELS = {
  LOW: 0.001,      // Normal conditions
  MEDIUM: 0.003,   // High congestion
  HIGH: 0.005,     // Extreme congestion
};

function getTipAmount(networkCongestion: 'low' | 'medium' | 'high'): number {
  return TIP_LEVELS[networkCongestion.toUpperCase()] * LAMPORTS_PER_SOL;
}

4. Monitor Request Latency

use std::time::Instant;

let start = Instant::now();
let response = client.send_transaction(&tx).await?;
let latency = start.elapsed();

// Log slow requests
if latency.as_millis() > 10 {
    warn!("High latency: {}ms", latency.as_millis());
}

Performance Optimization

Colocation

For the lowest latency we can offer, colocate your trading infrastructure alongside AllenHark Relay.

Benefits:

  • Direct private link to the relay — the public internet leaves the path
  • Guaranteed network throughput
  • Priority engineering support

Learn more about colocation

Remote vs Colocated

The rule of thumb is simple, and it's about geography rather than protocol tricks: over HTTPS expect single-digit milliseconds when you're near a region and tens of milliseconds cross-region. If you're far from every region, no amount of protocol tuning recovers the transit time — either move closer (pick the nearest of Frankfurt, Amsterdam, New York, Tokyo) or colocate. When latency matters, use QUIC or WebSocket rather than HTTPS.


Monitoring and Health Checks

Ping Endpoint

Verify relay connectivity:

curl https://relay.allenhark.com/ping
# Response: {"status": "ok", "ts": 1701234567890}

Monitoring Dashboard

Track your relay usage:

  • Request count
  • Error rates
  • Latency percentiles
  • Rate limit status

Access Dashboard (coming soon)


Pricing

AllenHark Relay uses a pay-per-transaction model via on-chain tips.

The tip is carried inside your transaction as a SystemProgram.transfer to a hark… wallet. There is no invoice, no subscription and no account charge for a relayed send — you pay the network, in the same transaction you're already signing.

Cost structure:

  • Base fee: None (free to obtain API key)
  • Per-transaction: 0.001 SOL minimum tip, paid in-transaction
  • High volume: Discounts available for >10,000 tx/month

Calculate your monthly cost:

Daily transactions: 1,000
Monthly cost: 1,000 tx/day × 30 days × 0.001 SOL = 30 SOL (~$3,000 at $100/SOL)

Compare to:

  • Jito bundles: 0.0001-0.01 SOL per transaction (variable)
  • Public RPC: Free but 10-100x slower

For high-volume traders, contact us for volume pricing.


Getting Help

Documentation

Support Channels

Emergency Support

For production issues affecting trading operations:

  • Priority support: Available for high-volume customers
  • Response time: <2 hours during trading hours

Next Steps

  1. Request API access - Get your credentials
  2. Test on devnet - Validate integration without risk
  3. Deploy to production - Start with HTTP, migrate to QUIC
  4. Monitor performance - Track latency and success rates
  5. Optimize tips - Adjust based on network conditions

Ready to upgrade your Solana trading infrastructure?

Request Access | View Documentation