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 txn because user_account was 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:

QuestionBest 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

Carbium'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:

  1. send once
  2. store the signature with the app-level request ID
  3. 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_KEY
  • CARBIUM_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 txn payload, 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:

🔶

Building a wallet or backend relay on Solana?

Start with the live setup flow at carbium.io.