Getting Started
Relay pre-signed Solana transactions via the Relayer API. The relayer appends the fee-payer signature before broadcasting.
For EVM workflows, see EVM Getting Started.
Overview
- Build and sign a Solana transaction (base64 wire format) with your authority key; leave the fee-payer slot empty.
- POST the signed transaction under the
solanapayload alongsidecallbackandtimestamp. - The relayer signs as fee-payer, submits to the selected cluster, and posts callbacks to your URL.
Request Format
solana: object containing your pre-signed transaction and metadata.txBase64: base64-encoded wire transaction signed by the authority.
callback:{ url }for execution updates.timestamp: unix epoch ms for replay protection.
Authentication and Callbacks
- Each API request must include an ed25519 public client key and a signature generated by the corresponding private key.
- Share the public key with Upside to whitelist the client; rotate it periodically.
- Callbacks include
X-Callback-Sig-B64, a base64-encoded ed25519 signature of the canonicalized callback body. - Verify callbacks using the public key from
GET /api/v1/callback_pk.
Example Request
Build a transaction with your Solana SDK of choice, then sign and send the API request:
import { createReqSignature } from './createReqSignature'
import { sign } from 'tweetnacl'
const requestBody = {
solana: {
txBase64: 'BASE64_WIRE_TX_WITH_AUTHORITY_SIGNATURE',
},
callback: { url: 'https://example.org/tx-updates/1/receive' },
timestamp: Date.now(),
}
const keyPair = sign.keyPair.fromSecretKey(
Buffer.from('ED_25519_SECRET_IN_BASE64', 'base64'),
)
const signature = createReqSignature(requestBody, keyPair.secretKey)
const sigB64 = Buffer.from(signature).toString('base64')
const pkB64 = Buffer.from(keyPair.publicKey).toString('base64')
const resp = await fetch('https://relayer.upside.gg/api/v1/relay_meta_tx', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Request-Pk-B64': pkB64,
'X-Request-Sig-B64': sigB64,
},
body: JSON.stringify(requestBody),
})
if (resp.status !== 201) {
throw new Error(`Failed to submit meta tx: ${await resp.text()}`)
}