Relay a Solana transaction¶
This guide shows how to relay a SOL transfer or a raw Solana instruction through the same submit endpoints used for EVM chains. Photon's relayer acts as the fee payer, so your users never need SOL for fees.
Prerequisites
- An API key — Get API access
- Familiarity with Relay an EVM transaction — the endpoints and status flow are identical
How the fields map on Solana¶
Use POST https://photon.example.com/api/submit-tx (or submit-tx-sync) with:
| Field | Solana meaning |
|---|---|
chainId |
10100001 (Solana Devnet). |
to |
Base58 public key of the recipient (or program, for raw instructions). |
value |
Lamports, as a base-10 integer string. Must fit in an unsigned 64-bit integer. |
callData |
"" or "0x" for a plain SOL transfer; otherwise a base64-encoded JSON instruction (below). |
EVM-only fields — gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, and authorizationList — are ignored on Solana. The network fee is 5000 lamports per signature, and relayed transactions carry a single signature (the relayer's), so the cost estimate is 5000 + value lamports.
1. Relay a plain SOL transfer¶
Leave callData empty (or "0x") and set value to the lamports to send:
const res = await fetch("https://photon.example.com/api/submit-tx", {
method: "POST",
headers: { "api-key": "YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
to: "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde",
callData: "",
chainId: 10100001,
value: "1000000000", // 1 SOL
}),
});
const { data } = await res.json();
console.log(data.txId);
2. Relay a raw instruction¶
To call a program, describe one instruction as JSON, then base64-encode the whole JSON document into callData:
{
"programId": "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr",
"keys": [
{ "pubkey": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde", "isSigner": false, "isWritable": false }
],
"data": "aGVsbG8gZnJvbSBQaG90b24="
}
programId— base58 program address (required).keys— account metas;isSignerandisWritabledefault tofalse.data— the instruction data, itself base64-encoded.
const instruction = {
programId: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr",
keys: [],
data: Buffer.from("hello from Photon").toString("base64"),
};
const res = await fetch("https://photon.example.com/api/submit-tx", {
method: "POST",
headers: { "api-key": "YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
to: instruction.programId, // still required; not used to build the instruction
callData: Buffer.from(JSON.stringify(instruction)).toString("base64"),
chainId: 10100001,
value: "0",
}),
});
Warning
The relayer's fee-payer key is the only signer. Any account marked isSigner: true other than the fee payer will fail signature verification, so raw instructions must not require additional signers.
3. Check status¶
Status flow is identical to EVM: poll GET https://photon.example.com/api/tx?id=<txId>. On Solana, executionTxHash is the base58 transaction signature, and the transaction reports EXECUTED once it reaches confirmed commitment.