Sending Transactions through Carbium RPC
Relay user-signed swap transactions through Carbium RPC with a safer backend flow, cleaner signing boundaries, and confirmation checks that avoid duplicate sends.
Sending Transactions through Carbium RPC
This page is for one specific job: you already have a Carbium-built transaction payload and need to get it from a signer to the chain through Carbium RPC without leaking keys or creating duplicate sends.
Use this page when your flow looks like this:
- your backend requests a quote from
https://api.carbium.io/api/v2/quote - the response includes
txnbecauseuser_accountwas provided - a wallet or backend signer approves that transaction
- your backend submits and confirms it through
https://rpc.carbium.io/?apiKey=YOUR_RPC_KEY
If you still need the full quote-to-confirm walkthrough, use Executing Swaps. If you are designing the broader wallet architecture, use Carbium for Wallet Developers.
Part of the Carbium Solana infrastructure stack.
What this page owns
Keep the intent narrow so the docs do not blur together:
| Question | Best page |
|---|---|
| How do I request an executable swap quote? | Q1 |
| How do I execute the entire swap flow end to end? | Executing Swaps |
| How do I relay a signed transaction through Carbium RPC safely? | This page |
Recommended relay pattern
The safest common pattern is:
%%{init: {"flowchart": {"useMaxWidth": false, "nodeSpacing": 40, "rankSpacing": 50}, "themeVariables": {"fontSize": "18px"}} }%%
flowchart TD
A["1. Backend requests quote<br/>api.carbium.io/api/v2/quote"] --> B["2. Quote returns base64 txn"]
B --> C["3. Wallet or signer approves txn"]
C --> D["4. Backend relay submits via rpc.carbium.io"]
D --> E["5. Backend confirms signature status"]
That split keeps both Carbium keys on infrastructure you control:
- the Swap API key stays on your backend when you request the executable quote
- the RPC key stays on your backend when you submit and confirm
- the wallet signs the transaction without ever receiving either key
Step 1: Request a quote that includes txn
txnCarbium's current executable quote flow is GET /api/v2/quote. The txn field is only returned when user_account is included in the request.
const quoteUrl = new URL("https://api.carbium.io/api/v2/quote");
quoteUrl.searchParams.set("src_mint", "So11111111111111111111111111111111111111112");
quoteUrl.searchParams.set("dst_mint", "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
quoteUrl.searchParams.set("amount_in", "10000000");
quoteUrl.searchParams.set("slippage_bps", "50");
quoteUrl.searchParams.set("user_account", walletAddress);
const quoteRes = await fetch(quoteUrl, {
headers: {
"X-API-KEY": process.env.CARBIUM_API_KEY!,
"Accept": "application/json",
},
});
if (!quoteRes.ok) {
throw new Error(`Quote failed with ${quoteRes.status}`);
}
const quote = await quoteRes.json();
if (!quote.txn) {
throw new Error("Quote response did not include txn");
}If txn is missing, do not jump straight into RPC debugging. That failure usually belongs upstream in the quote request shape. Use Swap API Errors Reference first.
Step 2: Sign on the correct boundary
Once your app has the base64 transaction payload, the signer can deserialize and approve it locally.
import { VersionedTransaction } from "@solana/web3.js";
const unsignedTx = VersionedTransaction.deserialize(
Buffer.from(quote.txn, "base64")
);
const signedTx = await wallet.signTransaction(unsignedTx);
const signedBase64 = Buffer.from(signedTx.serialize()).toString("base64");For wallet apps, this usually happens in the client wallet. For backend execution systems, the signer may be a controlled server-side keypair. The important rule is the same either way: only the signer handles the signature, while Carbium API and RPC credentials stay server-side.
Step 3: Relay the signed payload through Carbium RPC
Once the signed transaction comes back to your backend, submit it through Carbium RPC and confirm it before you decide whether a retry is necessary.
import {
Connection,
VersionedTransaction,
} from "@solana/web3.js";
const connection = new Connection(
`https://rpc.carbium.io/?apiKey=${process.env.CARBIUM_RPC_KEY}`,
"confirmed"
);
async function relaySignedTransaction(signedBase64: string) {
const signedTx = VersionedTransaction.deserialize(
Buffer.from(signedBase64, "base64")
);
const signature = await connection.sendRawTransaction(
signedTx.serialize(),
{
skipPreflight: false,
maxRetries: 3,
}
);
const confirmation = await connection.confirmTransaction(
signature,
"confirmed"
);
return { signature, confirmation };
}This keeps the relay step explicit:
- the client signs
- the backend submits
- RPC confirmation decides whether the app should advance, wait, or investigate
Guardrails that prevent most production mistakes
Do not retry send blindly
If a user refreshes the page or your worker restarts, the dangerous move is to send the same transaction again without checking whether the original signature already landed.
Use this order instead:
- send once
- store the signature with the app-level request ID
- check confirmation status before any replay decision
This matches Carbium's rate-limit guidance: retries are for uncertainty, not for panic.
Keep the relay service backend-only
Do not expose either of these directly in frontend code:
CARBIUM_API_KEYCARBIUM_RPC_KEY
Use a backend route, worker, or relay service instead. The deeper key-handling checklist lives on API Key Security Best Practices.
Keep quote and relay logs connected
For support and debugging, store enough information to trace one execution path:
- app request ID
- quote request parameters
- route metadata returned by the quote
- submitted signature
- final confirmation state
Without that trail, teams often confuse quote failures, signing failures, and RPC submission failures as the same problem.
Validation checklist
Before you ship this flow, verify:
- the quote request includes
user_account - the signer receives a base64
txnpayload, not raw API keys - the backend relays through
rpc.carbium.io, not a client-exposed endpoint - your app stores the submitted signature before retrying or timing out
- confirmation status is checked before any duplicate send
Use the adjacent pages by job:
- Q1 for quote construction
- Executing Swaps for the full swap flow
- API Key Security Best Practices for secret handling
Building a wallet or backend relay on Solana?
Start with the live setup flow at carbium.io.
Updated about 1 month ago
