Overview
Glaive is a high-performance Solana transaction sender. It maintains persistent connections to current and upcoming slot leaders, delivering your transactions directly into the validator processing pipeline.
The API is JSON-RPC compatible. You can use it as a drop-in replacement for your existing RPC endpoint when sending transactions.
Quickstart
Get a transaction submitted through Glaive in under a minute.
1. Get an API key
Contact the Glaive team to get an API key.
2. Send a transaction
curl "http://ams1.glaive.trade?key=YOUR_API_KEY" \
-X POST \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
"<base64-encoded-tx>",
{ "encoding": "base64" }
]
}'
const res = await fetch(
`http://ams1.glaive.trade?key=${process.env.GLAIVE_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "sendTransaction",
params: [
"<base64-encoded-tx>",
{ encoding: "base64" },
],
}),
}
);
const { result: signature } = await res.json();
let client = reqwest::Client::new();
let url = format!("http://ams1.glaive.trade?key={}", api_key);
let res = client.post(&url)
.json(&serde_json::json!({
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
"<base64-encoded-tx>",
{ "encoding": "base64" }
]
}))
.send()
.await?;
let body: serde_json::Value = res.json().await?;
let signature = &body["result"];
body := []byte(`{
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
"<base64-encoded-tx>",
{ "encoding": "base64" }
]
}`)
url := fmt.Sprintf("http://ams1.glaive.trade?key=%s", apiKey)
resp, err := http.Post(url, "application/json", bytes.NewReader(body))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
signature := result["result"]
Authentication
All requests require a key query parameter.
Each API key has an individually configured rate limit (TPS).
http://ams1.glaive.trade?key=your-api-key-here
Keys are UUID v4 strings. Treat them like passwords. Do not commit them to source control or share them in client-side code.
Don't have a key yet? Contact us to get one.
Regions
Glaive runs in multiple regions. Use the endpoint closest to your infrastructure.
| Region | Endpoint | Status |
|---|---|---|
| Amsterdam 1 | ams1.glaive.trade | Live |
| Amsterdam 2 | ams2.glaive.trade | Live |
| Frankfurt | fra.glaive.trade | Live |
| New York (Newark) | ny.glaive.trade | Live |
Endpoint
Glaive runs regional endpoints. Send requests to the nearest region:
POST http://ams1.glaive.trade?key=YOUR_API_KEY
The endpoint accepts standard Solana JSON-RPC format.
sendTransaction
Submit a signed transaction for delivery to current and upcoming leaders. Glaive offers three ways to submit transactions:
Standard Solana JSON-RPC format. Works as a drop-in replacement for your existing RPC endpoint.
POST /
Send a base64-encoded transaction as the raw request body. No JSON wrapping.
POST /plain
Send raw serialized transaction bytes. Zero encoding overhead.
POST /binary
JSON-RPC
POST /
Submit a signed transaction using the standard Solana JSON-RPC format.
Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
"<base64-encoded-transaction>",
{
"encoding": "base64"
}
]
}
Parameters
| Field | Type | Description |
|---|---|---|
params[0] | string | Base64-encoded signed transaction |
encoding | string | Transaction encoding: base64 or base58. Default: base64 |
Response
{
"jsonrpc": "2.0",
"id": 1,
"result": "<transaction-signature>"
}
Example
curl "http://ams1.glaive.trade?key=YOUR_API_KEY" \
-X POST \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
"<base64-encoded-transaction>",
{ "encoding": "base64" }
]
}'
// transaction = a signed VersionedTransaction
const serialized = transaction.serialize();
const base64Tx = Buffer.from(serialized).toString("base64");
const res = await fetch(
`http://ams1.glaive.trade?key=${process.env.GLAIVE_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "sendTransaction",
params: [base64Tx, { encoding: "base64" }],
}),
}
);
const { result, error } = await res.json();
if (error) throw new Error(error.message);
console.log("Signature:", result);
// tx = a signed VersionedTransaction
let serialized = bincode::serialize(&tx)?;
let base64_tx = base64::engine::general_purpose::STANDARD.encode(&serialized);
let client = reqwest::Client::new();
let url = format!("http://ams1.glaive.trade?key={}", api_key);
let res = client.post(&url)
.json(&serde_json::json!({
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [base64_tx, { "encoding": "base64" }]
}))
.send()
.await?;
let body: serde_json::Value = res.json().await?;
println!("Signature: {}", body["result"]);
// serializedTx = signed transaction bytes ([]byte)
base64Tx := base64.StdEncoding.EncodeToString(serializedTx)
body := []byte(`{
"jsonrpc": "2.0",
"id": 1,
"method": "sendTransaction",
"params": [
"` + base64Tx + `",
{ "encoding": "base64" }
]
}`)
url := fmt.Sprintf("http://ams1.glaive.trade?key=%s", apiKey)
resp, err := http.Post(url, "application/json", bytes.NewReader(body))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
if e, ok := result["error"]; ok {
log.Fatalf("Error: %v", e)
}
fmt.Println("Signature:", result["result"])
Plain
POST /plain
A lightweight alternative to JSON-RPC. Post a base64-encoded transaction
as the raw request body to /plain. No JSON wrapping needed.
Request
POST http://ams1.glaive.trade/plain?api-key=YOUR_API_KEY
The request body is the base64-encoded signed transaction as plain text.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
api-key | string | Your API key (required when rate limiting is enabled) |
mev-protect | string | Set to true to enable MEV protection |
Response
{
"result": "<transaction-signature>"
}
Error
Returns HTTP 400 with:
{
"error": "<error-message>"
}
Example
curl "http://ams1.glaive.trade/plain?api-key=YOUR_API_KEY" \
-X POST \
-d '<base64-encoded-transaction>'
// transaction = a signed VersionedTransaction
const serialized = transaction.serialize();
const base64Tx = Buffer.from(serialized).toString("base64");
const res = await fetch(
`http://ams1.glaive.trade/plain?api-key=${process.env.GLAIVE_KEY}`,
{
method: "POST",
body: base64Tx,
}
);
const { result, error } = await res.json();
if (error) throw new Error(error);
console.log("Signature:", result);
// tx = a signed VersionedTransaction
let serialized = bincode::serialize(&tx)?;
let base64_tx = base64::engine::general_purpose::STANDARD.encode(&serialized);
let client = reqwest::Client::new();
let url = format!("http://ams1.glaive.trade/plain?api-key={}", api_key);
let res = client.post(&url)
.body(base64_tx)
.send()
.await?;
let body: serde_json::Value = res.json().await?;
println!("Signature: {}", body["result"]);
// serializedTx = signed transaction bytes ([]byte)
base64Tx := base64.StdEncoding.EncodeToString(serializedTx)
url := fmt.Sprintf("http://ams1.glaive.trade/plain?api-key=%s", apiKey)
resp, err := http.Post(url, "text/plain", strings.NewReader(base64Tx))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
if e, ok := result["error"]; ok {
log.Fatalf("Error: %v", e)
}
fmt.Println("Signature:", result["result"])
Binary
POST /binary
The lowest overhead option. Post the raw binary transaction bytes
to /binary. No encoding, no JSON.
Request
POST http://ams1.glaive.trade/binary?api-key=YOUR_API_KEY
The request body is the raw serialized transaction bytes.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
api-key | string | Your API key (required when rate limiting is enabled) |
mev-protect | string | Set to true to enable MEV protection |
Response
{
"result": "<transaction-signature>"
}
Error
Returns HTTP 400 with:
{
"error": "<error-message>"
}
Example
curl "http://ams1.glaive.trade/binary?api-key=YOUR_API_KEY" \
-X POST \
-H "Content-Type: application/octet-stream" \
--data-binary "$SERIALIZED_TX_BYTES"
// transaction = a signed VersionedTransaction
const serialized = transaction.serialize();
const res = await fetch(
`http://ams1.glaive.trade/binary?api-key=${process.env.GLAIVE_KEY}`,
{
method: "POST",
body: serialized,
}
);
const { result, error } = await res.json();
if (error) throw new Error(error);
console.log("Signature:", result);
// tx = a signed VersionedTransaction
let serialized = bincode::serialize(&tx)?;
let client = reqwest::Client::new();
let url = format!("http://ams1.glaive.trade/binary?api-key={}", api_key);
let res = client.post(&url)
.body(serialized)
.send()
.await?;
let body: serde_json::Value = res.json().await?;
println!("Signature: {}", body["result"]);
// serializedTx = signed transaction bytes ([]byte)
url := fmt.Sprintf("http://ams1.glaive.trade/binary?api-key=%s", apiKey)
resp, err := http.Post(url, "application/octet-stream", bytes.NewReader(serializedTx))
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
if e, ok := result["error"]; ok {
log.Fatalf("Error: %v", e)
}
fmt.Println("Signature:", result["result"])
MEV Protection
Glaive can exclude validators known to sandwich transactions from your
transaction's delivery path. This is disabled by default. To opt in,
add mev_protect=true to the query string:
POST http://ams1.glaive.trade?key=YOUR_API_KEY&mev_protect=true
When enabled, Glaive will skip any leader that appears on its sandwiching validator blacklist. The blacklist is maintained by the Glaive team and updated as new sandwich activity is detected.
Without mev_protect=true, transactions are sent to all
upcoming leaders regardless of known sandwich behavior.
For the /plain and
/binary endpoints, use
mev-protect=true instead.
Minimum Tip
All transactions sent through Glaive must include a transfer of at least
0.001 SOL (1,000,000 lamports) to one of the Glaive tip accounts.
Transactions without a valid tip will be rejected with a -32000 JSON-RPC error.
Tip Accounts
Your transaction must include a SOL transfer to any one of these Glaive tip addresses:
GLaiv4GMRYQmthatDS98uQT4HoucgxWT8NeJz6oSwxeU
GLaivL5uPrDpvd1wTtvat38KGqb5WLhEdqQfnmNd3oNr
GLaivinAWh21NaJMhtExtD5G2gZs1xnvaYVZmwqobWZL
GLaivJSUL71FcocYa8tks5vpVyYzvaDMHtyrzfQF2ABr
GLaivRU6eDKrta3p3psFAWPEFLzCjeMHGpPUuQqTjtyv
GLaivq5dU8qHayz9Qf13LjPfVy3SmUhbmickfGiZdmfh
import { SystemProgram, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
const GLAIVE_TIP_ACCOUNTS = [
"GLaiv4GMRYQmthatDS98uQT4HoucgxWT8NeJz6oSwxeU",
"GLaivL5uPrDpvd1wTtvat38KGqb5WLhEdqQfnmNd3oNr",
"GLaivinAWh21NaJMhtExtD5G2gZs1xnvaYVZmwqobWZL",
"GLaivJSUL71FcocYa8tks5vpVyYzvaDMHtyrzfQF2ABr",
"GLaivRU6eDKrta3p3psFAWPEFLzCjeMHGpPUuQqTjtyv",
"GLaivq5dU8qHayz9Qf13LjPfVy3SmUhbmickfGiZdmfh",
];
const TIP_LAMPORTS = 0.001 * LAMPORTS_PER_SOL; // 1_000_000
const tipAccount = GLAIVE_TIP_ACCOUNTS[Math.floor(Math.random() * GLAIVE_TIP_ACCOUNTS.length)];
tx.add(
SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: new PublicKey(tipAccount),
lamports: TIP_LAMPORTS,
})
);
use solana_sdk::{system_instruction, pubkey::Pubkey};
use rand::seq::SliceRandom;
use std::str::FromStr;
const TIP_LAMPORTS: u64 = 1_000_000; // 0.001 SOL
const GLAIVE_TIP_ACCOUNTS: &[&str] = &[
"GLaiv4GMRYQmthatDS98uQT4HoucgxWT8NeJz6oSwxeU",
"GLaivL5uPrDpvd1wTtvat38KGqb5WLhEdqQfnmNd3oNr",
"GLaivinAWh21NaJMhtExtD5G2gZs1xnvaYVZmwqobWZL",
"GLaivJSUL71FcocYa8tks5vpVyYzvaDMHtyrzfQF2ABr",
"GLaivRU6eDKrta3p3psFAWPEFLzCjeMHGpPUuQqTjtyv",
"GLaivq5dU8qHayz9Qf13LjPfVy3SmUhbmickfGiZdmfh",
];
let tip_account = GLAIVE_TIP_ACCOUNTS
.choose(&mut rand::thread_rng())
.unwrap();
let tip_pubkey = Pubkey::from_str(tip_account).unwrap();
let tip_ix = system_instruction::transfer(
&payer.pubkey(),
&tip_pubkey,
TIP_LAMPORTS,
);
tx.add(tip_ix);
import (
"math/rand"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/programs/system"
)
const TipLamports = 1_000_000 // 0.001 SOL
var GlaiveTipAccounts = []solana.PublicKey{
solana.MustPublicKeyFromBase58("GLaiv4GMRYQmthatDS98uQT4HoucgxWT8NeJz6oSwxeU"),
solana.MustPublicKeyFromBase58("GLaivL5uPrDpvd1wTtvat38KGqb5WLhEdqQfnmNd3oNr"),
solana.MustPublicKeyFromBase58("GLaivinAWh21NaJMhtExtD5G2gZs1xnvaYVZmwqobWZL"),
solana.MustPublicKeyFromBase58("GLaivJSUL71FcocYa8tks5vpVyYzvaDMHtyrzfQF2ABr"),
solana.MustPublicKeyFromBase58("GLaivRU6eDKrta3p3psFAWPEFLzCjeMHGpPUuQqTjtyv"),
solana.MustPublicKeyFromBase58("GLaivq5dU8qHayz9Qf13LjPfVy3SmUhbmickfGiZdmfh"),
}
tipAccount := GlaiveTipAccounts[rand.Intn(len(GlaiveTipAccounts))]
tipIx := system.NewTransferInstruction(
TipLamports,
payer.PublicKey(),
tipAccount,
).Build()
Keep Alive
If you maintain persistent HTTP connections to Glaive (recommended for
lowest latency), send periodic requests to the /health
endpoint to keep them alive.
curl https://<region>.glaive.trade/health
The endpoint returns 200 OK with no authentication required.
A ping every 15 to 30 seconds is enough to prevent idle connection
timeouts.
Rate Limits
Each API key has a configured transactions-per-second (TPS) limit.
When exceeded, requests return 429 Too Many Requests.
Error Codes
HTTP Status Codes
| HTTP Status | Meaning |
|---|---|
200 | Request processed (check JSON-RPC response for result or error) |
401 | Missing or invalid API key |
429 | Rate limit exceeded |
JSON-RPC Error Codes
Validation and processing errors return HTTP 200 with a JSON-RPC error object in the response body.
| Code | Meaning |
|---|---|
-32600 | Invalid request (malformed JSON-RPC) |
-32601 | Method not found (only sendTransaction is supported) |
-32000 | Transaction rejected (invalid encoding, missing tip, etc.) |
FAQ
Does Glaive replace my RPC provider?
Only for sendTransaction. You still need a standard RPC
for reading state, fetching blockhashes, and other queries.
Which encoding formats are supported?
Base64 (default) and base58. We recommend base64 for smaller payload size.
What happens if the leader rotates mid-send?
Glaive fans out to multiple upcoming leaders simultaneously. Leader rotation during delivery is expected and handled automatically.
Is there a testnet endpoint?
Not currently. Glaive targets mainnet-beta only.
Contact
To get an API key or ask questions, reach out to us directly.
- Telegram
- Discord: glaivetrade