AllenHark Relay — Client Integration Guide

Introduction

AllenHark Relay is an ultra-low-latency Solana transaction relay designed for traders, market makers, and automated systems requiring sub-millisecond dispatch.

Your client submits a pre-signed Solana transaction to AllenHark Relay, and we immediately deliver it using a highly optimized, leader-aware pipeline engineered for speed.

Submission Modes

We provide two submission modes:

A) QUIC (Recommended — 0.1ms possible)

Persistent, connection-oriented, extremely low overhead.

B) Standard HTTPS

Simplest integration, but typically 15–25ms latency.

Relay Endpoints

  • QUIC Domain: relay.allenhark.com
  • HTTPS Domain: relay.allenhark.com
  • IP: 151.241.178.21
  • Region: Frankfurt, Germany

[!IMPORTANT] Regional Notice: AllenHark Relay is currently hosted in the Frankfurt region.

  • QUIC Protocol (Recommended): Works efficiently from any location worldwide
  • HTTPS/REST: Only recommended if your services are also in Frankfurt. For all other regions, use QUIC for optimal performance.

API Authentication

AllenHark Relay uses API key authentication for all requests. Contact us to obtain your API key.

Authentication Methods

Option 1: Header Authentication (Recommended)

1const response = await fetch("https://relay.allenhark.com/v1/sendTx", {
2  method: "POST",
3  headers: {
4    "Content-Type": "application/json",
5    "x-api-key": "YOUR_API_KEY"
6  },
7  body: JSON.stringify({
8    tx: "BASE64_ENCODED_TRANSACTION",
9    simulate: false
10  })
11});

Option 2: Query Parameter Authentication

1const response = await fetch("https://relay.allenhark.com/v1/sendTx?api-key=YOUR_API_KEY", {
2  method: "POST",
3  headers: {
4    "Content-Type": "application/json"
5  },
6  body: JSON.stringify({
7    tx: "BASE64_ENCODED_TRANSACTION",
8    simulate: false
9  })
10});

Rate Limits

  • Default: 100 requests per second per API key
  • Custom Limits: Contact us for higher rate limits based on your trading volume
  • Rate limits are applied per API key, not per IP address

Tip Wallets

To ensure priority processing, every transaction must include a tip to one of the AllenHark tip wallets. This economic model ensures fairness and prevents spam.

Available Tip Wallets (Select Random):

1const TIP_WALLETS = [
2  "hark1zxc5Rz3K8Kquz79WPWFEgNCFeJnsMJ16f22uNP",
3  "harkm2BTWxZuszoNpZnfe84jRbQTg6KGHaQBmWzDGQQ",
4  "hark4CwtTnN2y9FaxjcFBAJdJqQrpouu5pgEixfqdEz",
5  "harkoJfnM6dxrJydx5eVmDVwAgwC94KbhuxF69UbXwP",
6  "hark6hUDUTekc1DGxWdJcuyDZwf6pJdCxd4SXAVtta6",
7  "harkoTvFpKSrEQduYrNHXCurARVT19Ud3BnFhVxabos",
8  "harkEpXoJv5qVzHaN7HSuUAd6PHjyMcFMcDYBMDJCEQ",
9  "harkyXDdZSoJGyCxa24t2QXx1poPyp8YfghbtpzGSzK",
10  "harkR2YJ4Dpt4UDJTcBirjnSPBhNpQFcoFkNpCkVqNk",
11  "harkRBygM8pHYe4K8eBjfxyEX19oJn3LepFjvNbLbyi",
12  "harkYFxB6DuUFNwDLvA5CQ66KpfRvFgUoVypMagNcmd",
13];
14
15// Select a random tip wallet for each transaction
16const tipWallet = TIP_WALLETS[Math.floor(Math.random() * TIP_WALLETS.length)];
1// Rust example
2const TIP_WALLETS: [&str; 11] = [
3    "hark1zxc5Rz3K8Kquz79WPWFEgNCFeJnsMJ16f22uNP",
4    "harkm2BTWxZuszoNpZnfe84jRbQTg6KGHaQBmWzDGQQ",
5    "hark4CwtTnN2y9FaxjcFBAJdJqQrpouu5pgEixfqdEz",
6    "harkoJfnM6dxrJydx5eVmDVwAgwC94KbhuxF69UbXwP",
7    "hark6hUDUTekc1DGxWdJcuyDZwf6pJdCxd4SXAVtta6",
8    "harkoTvFpKSrEQduYrNHXCurARVT19Ud3BnFhVxabos",
9    "harkEpXoJv5qVzHaN7HSuUAd6PHjyMcFMcDYBMDJCEQ",
10    "harkyXDdZSoJGyCxa24t2QXx1poPyp8YfghbtpzGSzK",
11    "harkR2YJ4Dpt4UDJTcBirjnSPBhNpQFcoFkNpCkVqNk",
12    "harkRBygM8pHYe4K8eBjfxyEX19oJn3LepFjvNbLbyi",
13    "harkYFxB6DuUFNwDLvA5CQ66KpfRvFgUoVypMagNcmd",
14];
15
16// Select a random tip wallet
17let tip_wallet = TIP_WALLETS[rand::random::<usize>() % TIP_WALLETS.len()];

Minimum Tip Amount

AllenHark Relay requires a minimum tip for each transaction:

  • Minimum: 0.001 SOL (1,000,000 lamports)
  • Recommended during congestion: 0.002–0.005 SOL

Transactions without a valid tip to an AllenHark wallet will be rejected with error code tip_missing.


Sending via QUIC (Recommended)

QUIC provides ultra-low latency through:

  • 0-RTT Connection Resumption: Instant reconnection for returning clients
  • Connection Multiplexing: Multiple streams over a single connection
  • No Head-of-Line Blocking: Independent stream processing
  • Built-in TLS 1.3: Encrypted by default
  • 50-80% Latency Reduction compared to HTTP/2

QUIC Endpoint

relay.allenhark.com:4433

TLS Requirements

QUIC requires valid TLS certificates. For production:

1# Clients should use system root certificates for verification

For development with self-signed certificates:

1# Generate self-signed certificate (development only)
2openssl req -x509 -newkey rsa:4096 -nodes \
3  -keyout key.pem -out cert.pem -days 365 \
4  -subj "/CN=localhost"

[!WARNING] Self-signed certificates require disabling certificate verification in your client (not recommended for production).

Stream Protocol

Each transaction uses a bidirectional QUIC stream:

  1. Client sends API key header:

    api-key: YOUR_API_KEY\n
  2. Client sends JSON payload:

    1{"tx": "BASE64_TRANSACTION", "simulate": false}
  3. Client closes write side (signals end of request)

  4. Server responds:

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

Rust Example (Quinn)

1use quinn::{ClientConfig, Endpoint};
2use rustls::RootCertStore;
3use std::sync::Arc;
4
5#[tokio::main]
6async fn main() -> Result<(), Box<dyn std::error::Error>> {
7    // Configure TLS with system root certificates
8    let mut roots = RootCertStore::empty();
9    roots.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| {
10        rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
11            ta.subject,
12            ta.spki,
13            ta.name_constraints,
14        )
15    }));
16
17    let client_config = ClientConfig::with_root_certificates(roots);
18    
19    // Create endpoint
20    let mut endpoint = Endpoint::client("0.0.0.0:0".parse()?)?;
21    endpoint.set_default_client_config(client_config);
22    
23    // Connect to relay
24    let conn = endpoint
25        .connect("relay.allenhark.com:4433".parse()?, "relay.allenhark.com")?
26        .await?;
27    
28    // Open bidirectional stream
29    let (mut send, mut recv) = conn.open_bi().await?;
30    
31    // Send API key
32    send.write_all(b"api-key: YOUR_API_KEY\n").await?;
33    
34    // Send transaction
35    let payload = serde_json::json!({
36        "tx": "BASE64_TRANSACTION",
37        "simulate": false
38    });
39    send.write_all(&serde_json::to_vec(&payload)?).await?;
40    send.finish().await?;
41    
42    // Read response
43    let response = recv.read_to_end(4096).await?;
44    let result: serde_json::Value = serde_json::from_slice(&response)?;
45    println!("Response: {}", result);
46    
47    Ok(())
48}

Python Example (aioquic)

1import asyncio
2import json
3from aioquic.asyncio import connect
4from aioquic.quic.configuration import QuicConfiguration
5
6async def send_transaction(api_key: str, tx_base64: str):
7    configuration = QuicConfiguration(is_client=True)
8    configuration.verify_mode = True
9    
10    async with connect(
11        "relay.allenhark.com",
12        4433,
13        configuration=configuration,
14    ) as client:
15        # Open stream
16        stream_id = client._quic.get_next_available_stream_id()
17        
18        # Send API key
19        client._quic.send_stream_data(
20            stream_id,
21            f"api-key: {api_key}\n".encode()
22        )
23        
24        # Send transaction
25        payload = json.dumps({
26            "tx": tx_base64,
27            "simulate": False
28        })
29        client._quic.send_stream_data(stream_id, payload.encode(), end_stream=True)
30        
31        # Read response
32        response_data = await client._quic.receive_stream_data(stream_id)
33        response = json.loads(response_data.decode())
34        print("Response:", response)
35
36asyncio.run(send_transaction("YOUR_API_KEY", "BASE64_TX"))

Node.js Note

Node.js QUIC support is experimental. We recommend using Rust for QUIC integration or the HTTPS endpoint for Node.js applications.


Sending via HTTPS

A simpler integration path using standard REST API.

Endpoints

POST https://relay.allenhark.com/v1/sendTx

Both endpoints are functionally identical.

Request Format

1{
2  "tx": "BASE64_ENCODED_TRANSACTION",
3  "simulate": false
4}

[!IMPORTANT] The simulate parameter must be false. Simulation requests are rejected to prevent abuse.

Node.js Example (fetch)

1const response = await fetch("https://relay.allenhark.com/v1/sendTx", {
2  method: "POST",
3  headers: {
4    "Content-Type": "application/json",
5    "x-api-key": "YOUR_API_KEY"
6  },
7  body: JSON.stringify({
8    tx: "BASE64_ENCODED_TRANSACTION",
9    simulate: false
10  })
11});
12
13const data = await response.json();
14console.log("Response:", data);

Rust Example (reqwest)

1use reqwest::Client;
2use serde_json::json;
3
4#[tokio::main]
5async fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let client = Client::new();
7    
8    let res = client.post("https://relay.allenhark.com/v1/sendTx")
9        .header("x-api-key", "YOUR_API_KEY")
10        .json(&json!({
11            "tx": "BASE64_ENCODED_TRANSACTION",
12            "simulate": false
13        }))
14        .send()
15        .await?;
16
17    let response_text = res.text().await?;
18    println!("Response: {}", response_text);
19    Ok(())
20}

Keep-Alive Best Practices

QUIC Keep-Alive

Recommended settings:

  • Keep-alive ping: every 3 seconds
  • Timeout: 10–15 seconds

Benefits:

  • No reconnection cost
  • Predictable 0.1ms dispatch
  • Session stability for high-frequency bots
1const client = new QuicClient("relay.allenhark.com:4433", {
2  keepAlive: true,
3  keepAliveInterval: 3000,
4  keepAliveTimeout: 15000,
5});

HTTPS Keep-Alive

If you are using Axios:

1import axios from "axios";
2import https from "https";
3
4const agent = new https.Agent({ keepAlive: true });
5
6const api = axios.create({
7  baseURL: "https://relay.allenhark.com",
8  httpsAgent: agent,
9});

This reduces repeated TLS handshakes but cannot match QUIC performance.


Response Format

Success Response

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

The relay returns minimal response data for ultra-low latency. The transaction signature can be retrieved from your transaction payload.

Error Responses

Error CodeDescription
tip_missingTransaction does not include a tip to AllenHark wallet
tip_insufficientTip amount below minimum threshold (1,000,000 lamports)
simulate_forbiddenThe simulate parameter must be false
invalid_api_keyAPI key not found or invalid
rate_limit_exceededRequest rate limit exceeded for this API key
invalid_transactionTransaction deserialization failed

Error Response Format

1{
2  "status": "error",
3  "code": "tip_missing",
4  "message": "Transaction must include tip to AllenHark wallet"
5}

Performance Metrics

Latency Breakdown

ComponentQUICHTTPS
Connection Setup0ms (persistent)15-20ms
Serialization0.1ms0.1ms
Network Transit0.3-0.5ms2-5ms
Relay Processing0.1-0.2ms0.1-0.2ms
Total0.1ms15-25ms

Throughput

  • QUIC: Up to 10,000 tx/s per connection
  • HTTPS: Up to 1,000 tx/s per connection

Co-Locate With Us for True 0.1ms Performance

For the absolute lowest latency, we strongly encourage clients to co-locate their bots or trading engines with us.

Colocation Benefits

  • Direct, private, ultra-fast link to the relay
  • True sub-millisecond transaction dispatch
  • Leader-aware execution
  • Guaranteed throughput
  • Access to private QUIC lanes
  • Priority engineering support

Colocation Locations

  • Frankfurt: TeraSwitch

Get in touch with us to secure a colocation slot.

Contact Us | View Co-Location Details


Monitoring

Ping Service

To verify connectivity to the relay, use the ping endpoint:

1curl https://relay.allenhark.com/ping

Response:

pong

Best Practices

  1. Use QUIC for Production: Always use QUIC for production trading systems
  2. Implement Retry Logic: Handle network errors with exponential backoff
  3. Monitor Tip Amounts: Increase tips during network congestion
  4. Keep Connections Alive: Maintain persistent connections for best performance
  5. Co-locate if Possible: For true 0.1ms, co-locate your infrastructure
  6. Test on Devnet First: Always test integration on devnet before mainnet

Support

For technical support or colocation inquiries: