Send your first transaction
Discover a live tip account, submit signed bytes and check the transaction outcome.
You need a SWQoS API key and a Solana RPC provider for reads. Keep transaction construction and signing in your existing application. Submitting a transaction does not require sending your wallet's private key to SWQoS.
1. Discover a tip account
Call getTipAccounts before constructing the transaction. Use one of the returned
addresses as the destination of a System transfer. The set can change; cache it for your
sender and refresh it periodically instead of hard-coding addresses.
This helper accepts the API key as an argument and returns the live account list:
export async function getTipAccounts(apiKey: string): Promise<string[]> {
const endpoint = new URL('https://sol.zerocopy.sh')
endpoint.searchParams.set('api-key', apiKey)
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'getTipAccounts' }),
})
if (!response.ok) throw new Error(`Tip discovery failed: HTTP ${response.status}`)
const body: unknown = await response.json()
if (
!body || typeof body !== 'object' || !('result' in body) ||
!Array.isArray(body.result) || !body.result.every((value) => typeof value === 'string')
) {
throw new Error('Tip discovery did not return an account list')
}
if (body.result.length === 0) throw new Error('No tip account is available')
return body.result
}If the list is empty or the service returns not_ready, do not send to a remembered
account. Retry discovery when the service is ready. See tip-account discovery.
2. Build and sign
Using your Solana RPC provider and transaction builder:
- Fetch a recent blockhash, or prepare the durable nonce your transaction uses.
- Add your application's instructions and a tip transfer to a returned account.
- Use at least the minimum configured for your key. A missing-tip reply reports the required amount if a request is insufficient.
- Sign with every required signer and serialize the completed transaction.
The tip is separate from Solana's transaction and priority fees. The transaction's fee payer must be able to pay those fees. A declared tip needs separate eligibility and settlement integration; this quickstart uses an in-transaction tip.
3. Submit the signed transaction
With @solana/kit, pass the already signed transaction to sendTransaction. The helper
below accepts a transaction from your signing flow, not an unsigned template:
import {
createSolanaRpc,
getBase64EncodedWireTransaction,
type Transaction,
} from '@solana/kit'
export async function sendSignedTransaction(apiKey: string, transaction: Transaction) {
const endpoint = new URL('https://sol.zerocopy.sh')
endpoint.searchParams.set('api-key', apiKey)
const rpc = createSolanaRpc(endpoint.toString())
return rpc.sendTransaction(getBase64EncodedWireTransaction(transaction), {
encoding: 'base64',
skipPreflight: true,
}).send()
}The response is the transaction's first signature. skipPreflight: true skips simulation;
it does not make invalid transaction signatures valid. Use
skipPreflight: false when you want preflight simulation.
SWQoS defaults to base58 encoding and skips preflight if you omit the options. Set both explicitly so your client's defaults do not decide them for you.
Use the raw JSON-RPC examples when your application needs structured rejection
details. Solana kit can throw on an HTTP error before exposing the body, and its standard
Solana error-code mapping does not preserve every SWQoS reason. Read error.data from
the HTTP response rather than inferring a SWQoS failure from a kit error number.
4. Check the outcome
Use your Solana RPC provider's getSignatureStatuses or transaction subscription to
check the returned signature. Do not call read methods on the SWQoS send endpoint.
An accepted send can still fail to land or execute with an error. SWQoS does not resubmit
it automatically, and maxRetries does not enable retries here. Decide whether to resend
while the transaction remains valid. Before replacing an expired transaction or advancing
a nonce, check the outcome of the original. See confirmation and retries.
For ordered groups of up to four transactions, use bundles, not a
JSON-RPC batch. For rejected requests, use the structured reason and retryable fields
in errors.