Dedicated Nodes can optionally use either the Hello Moon Swap API or Jupiter Swap API plug-in. When enabled, this allows you to build transactions and get on-chain prices for any token on major DEXs with slippage protection. Select your preferred Swap API plug-in when you purchase a dedicated node to use it. You then interact with it via HTTP requests or using an SDK. The two Swap APIs are similar but have some differences. The Hello Moon Swap API, for example, allows you to get a quote and submit a transaction in one call, where the Jupiter API requires two calls to do the same.
Swap API Options
Hello Moon Swap API
Using the SDK
Our Typescript SDK for the Hello Moon Swap API is hosted at https://www.npmjs.com/package/@hellomoon/swap-api. It has examples of how to create a connection, get a swap quote, and execute a swap transaction.
Connecting to the Swap API
The Hello Moon Swap API is hosted on your dedicated node at the base URL of <RPC_URL>/api/swap/
. Use this base URL with the endpoints below.
Authorization
The Hello Moon Swap API routes can be accessed with your RPC token in the authorization header of the POST request. For example if your dedicated node RPC URL is https://raging-river.hellomoon.io/hf0e87h7ewh98 you would set an authorization header like { Authorization: "Bearer hf0e87h7ewh98" }
on all routes.
Get a quote
You can get a quote for a token swap by sending a POST request to the /get_quote
endpoint of the Hello Moon Swap API.
The parameters it takes are:
tokenIn: string; // public key of the token you are providing
tokenOut: string; // public key of the token you want to swap for
action: Action; // Set to 'exactIn' or 'exactOut'
amount: string; // Amount specified in Lamports
slippageBps?: number; // Slippage Basis Points. Optional.
maxHops?: number; // Optional.
exemptFees?: boolean; // Optional.
Response
This will return a response in the form of:
type GetQuoteResponse = {
aggregatorFee: string; // u64 as string
slot: string; // u64 as string
timestamp: string; // u64 as string
path: GenericQuote[]; // Vec of quotes
minAmountOutOrMaxIn: string; // u64 as string
};
type GenericQuote = {
pool: string;
swapContext: any; // This might need a more specific type depending on your needs
direction: string;
amountIn: string; // u64 as string
amountOut: string; // u64 as string
feeTaken: string; // u64 as string
token0Impact: string; // Bps as decimal string
token1Impact: string; // Bps as decimal string
};
Create a versioned transaction
Get a versioned transaction by sending a POST request to the /get_transaction
endpoint with the following parameters
tokenIn: string; // public key of the token you are providing
tokenOut: string; // public key of the token you want to swap for
action: Action; // set to 'exactIn' or 'exactOut'
amount: string; // amount in Lamports
userPubkey: string; // public key of your wallet
maxHops?: number; // optional since it has a default
slippageBps?: number; // optional since it has a default
Response
This will return a response in the form:
txn: string; // this is the versioned transaction
Execute the versioned transaction
Once you have a versioned transaction, you need to execute it. This is not specific to the Swap API and you can do this using any library. An example of how to do this in TypeScript might look like:
// Import the libraries we need
import { Connection, VersionedTransaction } from "@solana/web3.js";
import bs58 from "bs58";
// Assume you already have these variables set up
conn = // this is a connection to your RPC
versionedTxn = // this is the versioned transaction returned from the Swap API that you want to execute
// Deserialize the transaction
txn =
VersionedTransaction.deserialize(bs58.decode(versionedTxn));
// Sign the transaction with your wallet
txn.sign([keyPair]);
// Simulate the transation
const sim = await conn.simulateTransaction(txn);
// If there are any problems, bail out
if (sim.value.err) {
console.error(sim.value.err);
console.error(sim.value.logs);
throw new Error("Transaction Sim Response resulted in error");
}
// Send the transaction!
await conn.sendRawTransaction(txn.serialize());
Jupiter Swap API
Using the SDK
Our Jupiter Swap API integration uses the official Jupiter API package available at https://www.npmjs.com/package/@jup-ag/api. This package provides simple methods to retrieve quotes and execute swap transactions.
Connecting to the Jupiter Swap API
The Jupiter Swap API is accessible through your dedicated node at the base URL of <RPC_URL>/api/jup/
. Use this base URL with the endpoints described below.
Authorization
Jupiter Swap API routes use the same authorization method as the Hello Moon Swap API. Include your RPC token in the authorization header of your POST requests. For example, if your dedicated node RPC URL is https://raging-river.hellomoon.io/hf0e87h7ewh98, set an authorization header like { Authorization: "Bearer hf0e87h7ewh98" }
on all routes.
Get a quote
You can retrieve a quote for a token swap by using the quoteGet
method from the Jupiter SDK.
Example Using the SDK
import { createJupiterApiClient } from "@jup-ag/api";
import { inspect } from "util";
const main = async () => {
const jupiter = createJupiterApiClient({
basePath: "https://raging-river.hellomoon.io/api/jup",
headers: {
Authorization: "Bearer hf0e87h7ewh98",
},
});
const quote = await jupiter.quoteGet({
inputMint: "So11111111111111111111111111111111111111112", // SOL
outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
amount: 100000000, // 0.1 SOL (100000000 lamports)
slippageBps: 100, // 1% slippage tolerance
});
console.log(inspect(quote));
};
if (require.main === module) {
main().catch(console.error);
}
Response
This will return a response in the following format:
{
inputMint: 'So11111111111111111111111111111111111111112',
inAmount: '100000000',
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
outAmount: '13778298',
otherAmountThreshold: '13640516',
swapMode: 'ExactIn',
slippageBps: 100,
platformFee: undefined,
priceImpactPct: '0',
routePlan: [
{ swapInfo: [Object], percent: 100 },
{ swapInfo: [Object], percent: 100 }
],
contextSlot: 329349748,
timeTaken: 0.002020169
}
Create a swap transaction
You can create a swap transaction by using the swapPost
method from the Jupiter SDK:
import { createJupiterApiClient } from "@jup-ag/api";
import { Connection, Keypair, VersionedTransaction } from "@solana/web3.js";
import bs58 from "bs58";
import { inspect } from "util";
// Replace with your actual private key
const BS58_PRIVATE_KEY = "YOUR_PRIVATE_KEY";
const main = async () => {
// Initialize Jupiter API client
const jupiter = createJupiterApiClient({
basePath: "https://raging-river.hellomoon.io/api/jup",
headers: {
Authorization: "Bearer hf0e87h7ewh98",
},
});
// Step 1: Get a quote
const quote = await jupiter.quoteGet({
inputMint: "So11111111111111111111111111111111111111112", // SOL
outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
amount: 100000000, // 0.1 SOL (100000000 lamports)
slippageBps: 100, // 1% slippage tolerance
});
console.log("Quote obtained:", inspect(quote, { depth: null }));
// Step 2: Create a wallet for transaction (replace with your actual wallet)
// Note: In production, use a more secure way to handle private keys
const privateKey = bs58.decode(BS58_PRIVATE_KEY);
const wallet = Keypair.fromSecretKey(privateKey);
// Step 3: Connect to Solana
const connection = new Connection(
"https://raging-river.hellomoon.io/hf0e87h7ewh98",
"confirmed",
);
// Step 4: Create the swap transaction
const swapTransaction = await jupiter.swapPost({
swapRequest: {
quoteResponse: quote,
userPublicKey: wallet.publicKey.toString(),
},
});
console.log(
"Swap transaction created:",
inspect(swapTransaction, { depth: null }),
);
// Step 5: Deserialize the transaction
const swapTransactionBuf = Buffer.from(
swapTransaction.swapTransaction,
"base64",
);
const transaction = VersionedTransaction.deserialize(swapTransactionBuf);
// Step 6: Sign the transaction
transaction.sign([wallet]);
// Step 7: Execute the transaction
const signature = await connection.sendTransaction(transaction);
console.log("Transaction submitted:", signature);
// Step 8: Confirm the transaction
const confirmation = await connection.confirmTransaction(
signature,
"confirmed",
);
console.log("Transaction confirmed:", confirmation);
};
if (require.main === module) {
main().catch(console.error);
}
Response
The output from this sample will look something like the following:
Quote obtained: {
inputMint: 'So11111111111111111111111111111111111111112',
inAmount: '100000000',
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
outAmount: '13949101',
otherAmountThreshold: '13809610',
swapMode: 'ExactIn',
slippageBps: 100,
platformFee: undefined,
priceImpactPct: '0',
routePlan: [
{
swapInfo: {
ammKey: '71GHcjkwmtM7HSWBuqzjEp96prcNNwu1wpUywXiytREU',
label: 'Lifinity V2',
inputMint: 'So11111111111111111111111111111111111111112',
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
inAmount: '100000000',
outAmount: '13949101',
feeAmount: '0',
feeMint: 'So11111111111111111111111111111111111111112'
},
percent: 100
}
],
contextSlot: 329537341,
timeTaken: 0.002056727
}
Swap transaction created: {
swapTransaction: '<redacted>',
lastValidBlockHeight: 307787472,
prioritizationFeeLamports: 99999
}
Transaction submitted: <redacted>
Transaction confirmed: { context: { slot: 329537344 }, value: { err: null } }