Authentication
Every connection to MEV Alpha Store is authenticated. Credentials are issued per Client and may not be shared or resold (see Terms).
Credential type
You authenticate with an API key issued for your account, for example mev_live_3f9a2c7e1b8d4f60a5c9e2b7d1f4a8c3. One key covers every product in your offer.
As an additional layer, the key can be restricted to an allowlist of the public IP addresses of your servers. Send the addresses to our support when you request access or when your servers change.
| Interface | How the key is passed |
|---|---|
| gRPC (Shreds) | Metadata entry x-api-key |
| Private Orderflow over gRPC | Reversed: our relayer signs in to your server with its identity key. See gRPC push |
| WebSocket | HTTP header x-api-key on the upgrade request |
| Private TPU Send (HTTPS) | HTTP header x-api-key |
The key is never sent in the URL, so it does not end up in proxy logs or browser history.
gRPC
Add the key as metadata to every call. The easiest way is a client interceptor, so that the key is attached in one place.
use tonic::{metadata::MetadataValue, service::Interceptor, Request, Status};
#[derive(Clone)]
pub struct ApiKey(MetadataValue<tonic::metadata::Ascii>);
impl ApiKey {
pub fn from_env() -> Self {
let key = std::env::var("MEV_ALPHA_KEY").expect("MEV_ALPHA_KEY is not set");
Self(key.parse().expect("invalid API key"))
}
}
impl Interceptor for ApiKey {
fn call(&mut self, mut req: Request<()>) -> Result<Request<()>, Status> {
req.metadata_mut().insert("x-api-key", self.0.clone());
Ok(req)
}
}
// let client = ShredStreamClient::with_interceptor(channel, ApiKey::from_env());import { credentials, Metadata } from "@grpc/grpc-js";
const callCreds = credentials.createFromMetadataGenerator((_params, callback) => {
const md = new Metadata();
md.set("x-api-key", process.env.MEV_ALPHA_KEY!);
callback(null, md);
});
// TLS channel credentials combined with the API key on every call
export const grpcCredentials = credentials.combineChannelCredentials(
credentials.createSsl(),
callCreds,
);WebSocket
Pass the key as a header when you open the connection.
import WebSocket from "ws";
const ws = new WebSocket(process.env.MEV_SHREDS_WS!, {
headers: { "x-api-key": process.env.MEV_ALPHA_KEY! },
});Browsers cannot set custom headers on WebSocket connections. Connect from your server, not from a browser.
Private TPU Send
Send the key as a header with every request.
curl -s "$MEV_SEND_URL" \
-H "Content-Type: application/json" \
-H "x-api-key: $MEV_ALPHA_KEY" \
-d '{"jsonrpc":"2.0","id":1,"method":"getHealth"}'You never need to share the private keys of your trading wallets. Private TPU Send accepts transactions that you have already signed.
Authentication errors
| Situation | gRPC | WebSocket | HTTPS |
|---|---|---|---|
| Missing or invalid key | UNAUTHENTICATED | Upgrade rejected with HTTP 401 | HTTP 401 |
| Key valid, IP address not allowlisted | PERMISSION_DENIED | Upgrade rejected with HTTP 403 | HTTP 403 |
| Product not included in your offer | PERMISSION_DENIED | Upgrade rejected with HTTP 403 | HTTP 403 |
Do not retry authentication errors in a loop. Check the key and your server's public IP address, then contact support. See Errors for all status codes.
Rotating credentials
- Contact our support to rotate or revoke credentials: @ZoriDev.
- Rotate immediately if a credential may have been exposed.
- Store credentials in environment variables or a secret manager. Never commit them to a repository.
- Do not log full keys. If you need to identify a key in logs, log only its last four characters.
Our team will never message you first or ask for private keys. Always verify that you are speaking with @ZoriDev.
Need help or access? Contact our support on Telegram.
Contact