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 — with stake-weighted priority delivery for maximum transaction inclusion rates.

Broadcast Pipeline

Every transaction is broadcast simultaneously through 5 channels:

  1. Stake-Weighted QUIC (Primary) — Priority delivery across multiple global endpoints
  2. QUIC TPU — Direct to current + next 48 Solana leaders via QUIC
  3. UDP TPU — Fire-and-forget UDP to leaders
  4. RPC Fan-out — Parallel sendTransaction to multiple RPC endpoints
  5. ROC Relayers — Jito Block Engine and custom relayers

Submission Modes

We provide three submission modes:

A) QUIC (Recommended — 0.1ms possible)

Persistent, connection-oriented, extremely low overhead.

B) WebSocket (wss://) — persistent, browser-native

Open one socket per region, then stream transactions or atomic bundles for as long as you like. One TLS handshake at connect, none afterwards. Works from browsers and every modern language without a custom client.

C) Standard HTTPS

Simplest integration, but typically 15–25ms latency.


Multi-Region Endpoints

AllenHark Relay operates across multiple regions. Each region runs an independent relay instance with full 5-channel broadcast pipeline.

QUIC Endpoints (Recommended)

QUIC connections use IP addresses directly for lowest latency:

RegionQUIC AddressIP
Frankfurt (Primary)84.32.223.83:443384.32.223.83
Amsterdam84.32.104.38:443384.32.104.38
New York66.94.98.217:443366.94.98.217
Tokyo84.247.153.145:443384.247.153.145

HTTPS Endpoints

HTTP submission uses domain names:

RegionHTTPS EndpointDomain
Frankfurt (Primary)https://fra.relay.allenhark.com/v1/sendTxfra.relay.allenhark.com
Amsterdamhttps://ams.relay.allenhark.com/v1/sendTxams.relay.allenhark.com
New Yorkhttps://ny.relay.allenhark.com/v1/sendTxny.relay.allenhark.com
Tokyohttps://tyo.relay.allenhark.com/v1/sendTxtyo.relay.allenhark.com

WebSocket Endpoints

Persistent wss:// streams. Two paths per region — one for single transactions and one for atomic bundles:

RegionSingle-tx streamBundle stream
Frankfurt (Primary)wss://fra.relay.allenhark.com/v1/stream/txwss://fra.relay.allenhark.com/v1/stream/bundle
Amsterdamwss://ams.relay.allenhark.com/v1/stream/txwss://ams.relay.allenhark.com/v1/stream/bundle
New Yorkwss://ny.relay.allenhark.com/v1/stream/txwss://ny.relay.allenhark.com/v1/stream/bundle
Tokyowss://tyo.relay.allenhark.com/v1/stream/txwss://tyo.relay.allenhark.com/v1/stream/bundle

[!TIP] relay.allenhark.com is an alias for fra.relay.allenhark.com (Frankfurt). You can use either for HTTPS.

[!IMPORTANT] QUIC Protocol (Recommended): Always use the IP address directly for QUIC connections. Works efficiently from any location worldwide. All stake-weighted endpoints are used simultaneously regardless of your region.

HTTPS/REST: Uses domain names. Best when co-located with the relay region. For cross-region, use QUIC.


API Authentication

API keys are optional. You can submit transactions without an API key. Providing one enables rate tracking, transaction history, and dedicated relay features.

Without API Key

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

With API Key (Header)

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});

With API Key (Query Parameter)

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

Rate Limits

  • Without API key: no rate limiting (subject to change)
  • With API key: 100 requests per second (default)
  • 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.

[!NOTE] Jito tips do not count — your transaction may include Jito bundle tips, but a separate tip to an AllenHark wallet is always required.

Dedicated Relay (Tip-Free)

Dedicated relay customers with whitelisted signer pubkeys can skip tip validation entirely. Transactions signed by whitelisted pubkeys are broadcast immediately without requiring tips.

To set up dedicated relay:

  1. Purchase a Dedicated Relay subscription on the console
  2. Verify your wallet pubkey(s) by signing a challenge message
  3. Transactions from verified pubkeys are relayed tip-free

Transaction Support

Supported Transaction Types

  • Legacy (V0) transactions — fully supported
  • Versioned transactions — supported with restrictions

Address Lookup Tables (ALT)

Transactions using Address Lookup Tables are rejected for non-dedicated customers because the relay cannot verify tip destinations without resolving the ALT on-chain. Dedicated relay customers with whitelisted pubkeys are exempt from this restriction.


Sending via QUIC (Recommended)

QUIC provides ultra-low latency through:

  • Persistent Connections: Connection established once, reused for all transactions
  • 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

Use the IP address directly for QUIC connections:

84.32.223.83:4433 # Frankfurt (Primary) 84.32.104.38:4433 # Amsterdam 66.94.98.217:4433 # New York 84.247.153.145:4433 # Tokyo

TLS Configuration

The QUIC server uses standard TLS 1.3. Clients should:

  • Skip server certificate verification (or use system root certs)
  • No ALPN required — do not set any ALPN protocols
  • No client certificate required — anonymous connections accepted
  • API key is optional — sent via the stream header, not TLS
1// Quinn / rustls 0.23 — minimal QUIC client config
2let crypto = rustls::ClientConfig::builder()
3    .dangerous()
4    .with_custom_certificate_verifier(SkipServerVerification::new())
5    .with_no_client_auth();
6
7let client_config = quinn::ClientConfig::new(Arc::new(
8    QuicClientConfig::try_from(crypto).unwrap()
9));

Stream Protocol

Each transaction uses a bidirectional QUIC stream:

  1. Client sends API key header (optional — send \n if no key):

    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  "signature": "5wH...txSig"
    5}

Rust Example (Quinn 0.11 + rustls 0.23)

1use quinn::{Endpoint, crypto::rustls::QuicClientConfig};
2use std::sync::Arc;
3
4// Skip server cert verification (relay uses Let's Encrypt)
5struct SkipVerify;
6impl rustls::client::danger::ServerCertVerifier for SkipVerify {
7    fn verify_server_cert(&self, _: &rustls::pki_types::CertificateDer, _: &[rustls::pki_types::CertificateDer], _: &rustls::pki_types::ServerName, _: &[u8], _: rustls::pki_types::UnixTime) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> { Ok(rustls::client::danger::ServerCertVerified::assertion()) }
8    fn verify_tls12_signature(&self, _: &[u8], _: &rustls::pki_types::CertificateDer, _: &rustls::DigitallySignedStruct) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> { Ok(rustls::client::danger::HandshakeSignatureValid::assertion()) }
9    fn verify_tls13_signature(&self, _: &[u8], _: &rustls::pki_types::CertificateDer, _: &rustls::DigitallySignedStruct) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> { Ok(rustls::client::danger::HandshakeSignatureValid::assertion()) }
10    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> { rustls::crypto::ring::default_provider().signature_verification_algorithms.supported_schemes() }
11}
12
13#[tokio::main]
14async fn main() -> Result<(), Box<dyn std::error::Error>> {
15    // Configure QUIC client — no ALPN, no client cert, skip server verify
16    let crypto = rustls::ClientConfig::builder()
17        .dangerous()
18        .with_custom_certificate_verifier(Arc::new(SkipVerify))
19        .with_no_client_auth();
20
21    let client_config = quinn::ClientConfig::new(Arc::new(
22        QuicClientConfig::try_from(crypto)?
23    ));
24
25    let mut endpoint = Endpoint::client("0.0.0.0:0".parse()?)?;
26    endpoint.set_default_client_config(client_config);
27
28    // Connect to relay via IP (connection persists — reuse for all transactions)
29    let conn = endpoint
30        .connect("84.32.223.83:4433".parse()?, "relay.allenhark.com")?
31        .await?;
32
33    // Open bidirectional stream per transaction
34    let (mut send, mut recv) = conn.open_bi().await?;
35
36    // Send header (API key optional — just send newline if none)
37    send.write_all(b"\n").await?;
38
39    // Send transaction
40    let payload = serde_json::json!({
41        "tx": "BASE64_TRANSACTION",
42        "simulate": false
43    });
44    send.write_all(&serde_json::to_vec(&payload)?).await?;
45    send.finish()?;
46
47    // Read response
48    let response = recv.read_to_end(4096).await?;
49    let result: serde_json::Value = serde_json::from_slice(&response)?;
50    println!("Response: {}", result);
51    
52    Ok(())
53}

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        "84.32.223.83",  # Frankfurt IP
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. API keys are optional — if provided, they enable rate tracking and dedicated relay features.

Endpoints

RegionURL
PrimaryPOST https://relay.allenhark.com/v1/sendTx
FrankfurtPOST https://fra.relay.allenhark.com/v1/sendTx
AmsterdamPOST https://ams.relay.allenhark.com/v1/sendTx
New YorkPOST https://ny.relay.allenhark.com/v1/sendTx
TokyoPOST https://tyo.relay.allenhark.com/v1/sendTx

Keep-Alive

Use the /keepalive endpoint to maintain your HTTP connection and monitor server time:

1curl https://relay.allenhark.com/keepalive
1{
2  "status": "alive",
3  "server_time": "2026-05-02T12:00:00.000Z",
4  "region": "fra",
5  "slot": 312345678
6}

Poll /keepalive every 5–10 seconds to keep your connection warm and avoid repeated TLS handshakes.

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)

1// Without API key
2const response = await fetch("https://relay.allenhark.com/v1/sendTx", {
3  method: "POST",
4  headers: { "Content-Type": "application/json" },
5  body: JSON.stringify({
6    tx: "BASE64_ENCODED_TRANSACTION",
7    simulate: false
8  })
9});
10
11const data = await response.json();
12console.log("Response:", data);
13
14// With API key via query param
15const response2 = await fetch(
16  "https://relay.allenhark.com/v1/sendTx?api-key=YOUR_API_KEY",
17  {
18    method: "POST",
19    headers: { "Content-Type": "application/json" },
20    body: JSON.stringify({ tx: "BASE64_TX", simulate: false })
21  }
22);

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}

Sending via WebSocket

Persistent wss:// connection — open once, stream as many transactions or bundles as you need. The TLS handshake is paid once at connect time and amortized across every subsequent message. Browser-native, language-agnostic, identical validation and tip rules to HTTPS.

Endpoints

StreamURL pattern
Single transactionswss://{region}.relay.allenhark.com/v1/stream/tx
Atomic bundles (≤ 5 txs)wss://{region}.relay.allenhark.com/v1/stream/bundle

{region} is fra, ams, ny, or tyo. relay.allenhark.com is an alias for Frankfurt.

Authentication

Same as HTTPS — auth happens once at the upgrade request, not per message. Choose either form:

1// Header (preferred for non-browser clients)
2new WebSocket("wss://relay.allenhark.com/v1/stream/tx", undefined, {
3  headers: { "x-api-key": "YOUR_API_KEY" }
4});
5
6// Query parameter (works from browsers, where headers can't be set on WS)
7new WebSocket("wss://relay.allenhark.com/v1/stream/tx?api-key=YOUR_API_KEY");

API keys are optional. Without one, public submissions still work; with one, you get rate tracking and dedicated relay features.

Single-Transaction Stream

Each frame you send is one JSON object:

1{ "id": "client-correlation-id", "tx": "BASE64_ENCODED_TRANSACTION" }

The server replies with a matching frame:

1{ "id": "client-correlation-id", "status": "accepted", "request_id": "uuid", "signature": "5xy…" }

On rejection:

1{ "id": "client-correlation-id", "status": "rejected", "error": "Tip 100000 below threshold 1000000" }

The id field is yours — it's echoed back verbatim so you can match each reply to the request that produced it. Replies may arrive out of order; correlate by id.

Bundle Stream

Atomic groups of up to 5 transactions that land together or not at all:

1{ "id": "b1", "txs": ["BASE64_TX_1", "BASE64_TX_2", "BASE64_TX_3"] }

Server reply:

1{ "id": "b1", "status": "accepted", "bundle_id": "uuid", "signatures": ["sig1", "sig2", "sig3"] }

Bundle convention: any single transaction in the bundle paying the standard 0.001 SOL tip covers the whole group. Bundles are forwarded only through bundle-aware paths so atomicity is preserved end-to-end.

Pipelined Sends

You don't have to wait for a reply before sending the next message. Fire as many frames as your rate limit allows; replies stream back asynchronously, identified by id.

1for (const tx of myTxs) {
2  ws.send(JSON.stringify({ id: tx.localId, tx: tx.b64 }));
3}
4// Replies arrive out of order — match by id.

A rate-limit rejection on one frame doesn't close the connection — the next frame goes through normally.

Browser Example

1const ws = new WebSocket(
2  "wss://fra.relay.allenhark.com/v1/stream/tx?api-key=YOUR_API_KEY"
3);
4
5ws.onopen = () => {
6  ws.send(JSON.stringify({ id: "1", tx: BASE64_TX }));
7};
8
9ws.onmessage = (e) => {
10  const r = JSON.parse(e.data);
11  if (r.status === "accepted") {
12    console.log("landed", r.signature);
13  } else {
14    console.error("rejected", r.error);
15  }
16};

Node.js Example (ws)

1import WebSocket from "ws";
2
3const ws = new WebSocket("wss://fra.relay.allenhark.com/v1/stream/tx", {
4  headers: { "x-api-key": "YOUR_API_KEY" },
5});
6
7ws.on("open", () => {
8  ws.send(JSON.stringify({ id: "1", tx: BASE64_TX }));
9});
10
11ws.on("message", (data) => {
12  const r = JSON.parse(data.toString());
13  console.log(r);
14});

Python Example (websockets)

1import asyncio, json, websockets
2
3async def submit(tx_b64_list):
4    async with websockets.connect(
5        "wss://fra.relay.allenhark.com/v1/stream/tx",
6        additional_headers={"x-api-key": "YOUR_API_KEY"},
7    ) as ws:
8        # Pipeline: fire all txs, collect replies as they arrive
9        for i, tx in enumerate(tx_b64_list):
10            await ws.send(json.dumps({"id": str(i), "tx": tx}))
11        for _ in tx_b64_list:
12            print(json.loads(await ws.recv()))

Rust Example (tokio-tungstenite)

1use futures_util::{SinkExt, StreamExt};
2use tokio_tungstenite::{connect_async, tungstenite::Message};
3
4#[tokio::main]
5async fn main() -> anyhow::Result<()> {
6    let url = "wss://fra.relay.allenhark.com/v1/stream/tx?api-key=YOUR_API_KEY";
7    let (mut ws, _) = connect_async(url).await?;
8
9    let frame = serde_json::json!({ "id": "1", "tx": tx_base64 });
10    ws.send(Message::Text(frame.to_string())).await?;
11
12    while let Some(msg) = ws.next().await {
13        if let Message::Text(text) = msg? {
14            println!("{}", text);
15            break;
16        }
17    }
18    Ok(())
19}

Connection Lifecycle

  • Idle behavior: streams stay alive aggressively — no idle timeout you need to design around. A connection opened at process boot will stay hot through quiet periods.
  • Reconnect: on transient drops (network blip, server restart), reconnect immediately and resume sending. There's no session state to recover — each frame is independent.
  • Close: send a close frame when you're done; the server will flush any in-flight replies and finish the close handshake.

[!IMPORTANT] Tip and validation rules are identical to HTTPS and QUIC — minimum 0.001 SOL to a registered tip wallet, no transactions using Address Lookup Tables (ALT), max ~1.6KB per transaction. Bundles inherit the same threshold; one tx in the bundle paying the tip covers the whole bundle.


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

Use the /keepalive endpoint to keep your HTTP connection warm and monitor server status:

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});
10
11// Poll every 5-10 seconds to maintain connection
12setInterval(async () => {
13  const { data } = await api.get("/keepalive");
14  console.log("Server time:", data.server_time, "Slot:", data.slot);
15}, 5000);

Response:

1{
2  "status": "alive",
3  "server_time": "2026-05-02T12:00:00.000Z",
4  "region": "fra",
5  "slot": 312345678
6}

This keeps the TCP connection alive, avoids repeated TLS handshakes, and gives you real-time server status.


Response Format

Success Response

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

The relay returns the transaction signature for immediate confirmation tracking.

Error Responses

Error CodeDescription
tip_missingTransaction does not include a tip to AllenHark wallet
tip_insufficientTip amount below minimum threshold (1,000,000 lamports)
tip_hidden_in_altTransaction uses Address Lookup Table — cannot verify tip
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": "rejected",
3  "error": "Transaction uses ALT — cannot verify tip"
4}

Performance Metrics

Broadcast Pipeline

Every transaction is delivered through 5 parallel channels for maximum inclusion probability:

ChannelProtocolDescription
Stake-Weighted QUICQUICPriority delivery across multiple global endpoints
QUIC TPUQUICDirect to next 48 validator leaders
UDP TPUUDPFire-and-forget to leaders
RPC Fan-outHTTPSParallel sendTransaction to all RPC nodes
ROC RelayersHTTPSJito Block Engine + custom relayers

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:

1# Primary (Frankfurt)
2curl https://relay.allenhark.com/ping
3
4# Regional
5curl https://fra.relay.allenhark.com/ping
6curl https://ams.relay.allenhark.com/ping
7curl https://ny.relay.allenhark.com/ping
8curl https://tyo.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. Use Nearest Region: Connect to the relay region closest to your infrastructure
  6. Co-locate if Possible: For true 0.1ms, co-locate your infrastructure
  7. Test on Devnet First: Always test integration on devnet before mainnet

Support

For technical support or colocation inquiries: