Send Batch Transactions
curl --request POST \
--url https://api.altude.so/api/Transaction/sendbatch \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <x-api-key>' \
--data '
{
"signedTransaction": "<string>"
}
'import requests
url = "https://api.altude.so/api/Transaction/sendbatch"
payload = { "signedTransaction": "<string>" }
headers = {
"X-API-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({signedTransaction: '<string>'})
};
fetch('https://api.altude.so/api/Transaction/sendbatch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.altude.so/api/Transaction/sendbatch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'signedTransaction' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.altude.so/api/Transaction/sendbatch"
payload := strings.NewReader("{\n \"signedTransaction\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.altude.so/api/Transaction/sendbatch")
.header("X-API-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"signedTransaction\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.altude.so/api/Transaction/sendbatch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"signedTransaction\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": "Queued",
"message": "Transaction sent successfully",
"signature": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d"
}
Transaction
Send Batch Transactions
Send multiple transactions as a batch to the Solana network
POST
/
Transaction
/
sendbatch
Send Batch Transactions
curl --request POST \
--url https://api.altude.so/api/Transaction/sendbatch \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <x-api-key>' \
--data '
{
"signedTransaction": "<string>"
}
'import requests
url = "https://api.altude.so/api/Transaction/sendbatch"
payload = { "signedTransaction": "<string>" }
headers = {
"X-API-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({signedTransaction: '<string>'})
};
fetch('https://api.altude.so/api/Transaction/sendbatch', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.altude.so/api/Transaction/sendbatch",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'signedTransaction' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.altude.so/api/Transaction/sendbatch"
payload := strings.NewReader("{\n \"signedTransaction\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.altude.so/api/Transaction/sendbatch")
.header("X-API-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"signedTransaction\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.altude.so/api/Transaction/sendbatch")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"signedTransaction\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": "Queued",
"message": "Transaction sent successfully",
"signature": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d"
}
Submit multiple signed transactions to be processed together on the Solana network.
For a step-by-step example that builds and partially signs a transaction to send SPL tokens—including creating the ATA if missing, setting any required authorities, partial local signing, and submission to Altude’s signing endpoint—see the Send example: Send example. This Send example is provided as an example only.
headers
Request Body
string
required
The base64-encoded signed batch transaction containing multiple operations
Response
boolean
Indicates if the batch transaction was sent successfully
array
Array of transaction signatures for each transaction in the batch
{
"status": "Queued",
"message": "Transaction sent successfully",
"signature": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d"
}
Example
This example demonstrates how to build a Solana transaction that transfers SPL tokens for a given mint and sets the associated token account (ATA) owner (theauthority) to a specified public key. The fee payer covers account creation and transaction fees. The sample walks through building the transaction, partially signing it locally, and submitting the partially-signed transaction to the Altude signing endpoint for final submission.
- TypeScript
Install library
npm install @solana/web3.js @solana/spl-token
Copy and paste this to your project
import { Connection, Keypair, PublicKey, Transaction } from '@solana/web3.js';
import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction, createSetAuthorityInstruction, AuthorityType, TOKEN_PROGRAM_ID, getAccount, createTransferInstruction } from '@solana/spl-token';
const sourceSignerSecretKey: any[] = [/* your fee payer secret key array here */];
const API_KEY = 'your-api-key-here';
// --- Helper functions (inline for docs-only usage) ---
// Compact helpers used only for this example: connection factory,
// idempotent ATA creator, serialization helpers, and a signing POST helper.
function getConnection(rpcUrl: string, commitment: any = 'confirmed') {
return new Connection(rpcUrl, commitment);
}
async function ensureCreateAtaInstruction(connection: Connection, feePayer: PublicKey, mint: PublicKey, owner: PublicKey) {
// Compute the associated token account (ATA) for the owner + mint.
const ata = await getAssociatedTokenAddress(mint, owner);
// If the ATA does not exist on-chain, return an instruction to create it.
// Caller should add the returned `ix` to the transaction to make creation idempotent.
const info = await connection.getAccountInfo(ata);
if (!info) {
const ix = createAssociatedTokenAccountInstruction(feePayer, ata, owner, mint);
return { ata, ix };
}
return { ata, ix: null };
}
function uint8ArrayToBase64(bytes: Uint8Array) {
// Convert a Uint8Array into a base64 string for JSON transport.
let binary = '';
const chunkSize = 0x8000;
for (let i = 0; i < bytes.length; i += chunkSize) {
const chunk = bytes.subarray(i, i + chunkSize);
binary += String.fromCharCode(...chunk);
}
return btoa(binary);
}
function serializePartialSigned(tx: Transaction, feePayerSecret: number[]) {
// Partially sign the transaction with the local fee payer key.
// Use `requireAllSignatures: false` so a remote signer can complete signatures.
const keypair = Keypair.fromSecretKey(Uint8Array.from(feePayerSecret));
tx.partialSign(keypair);
const raw = tx.serialize({ requireAllSignatures: false });
return uint8ArrayToBase64(raw);
}
async function postToSigningServer(url: string, signedBase64: string, apiKey?: string) {
// POST the partially-signed transaction to Altude. The server is expected
// to append remaining signatures (if any) and broadcast the transaction.
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
if (apiKey) headers['X-API-Key'] = apiKey;
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ SignedTransaction: signedBase64 }) });
return res.json();
}
// STEP 1 — Build transaction Transfer (idempotent create + set close authority)
export async function buildTransferTx(mints: string[], source: string, destination: string, amount: number , configUrl = 'https://api.altude.so/api/transaction/config') {
// Load network config (RPC URL and FeePayer public key) from Altude.
const cfg = await (await fetch(configUrl)).json();
const connection = getConnection(cfg.RpcUrl);
const feePayerPub = new PublicKey(cfg.FeePayer);
const sourcePub = new PublicKey(source);
const destinationPub = new PublicKey(destination);
const tx = new Transaction();
for (const mint in mints) {
const mintPub = new PublicKey(mint);
// Prepare an idempotent create-if-missing instruction for the ATA.
// `ix` will be non-null when the ATA must be created.
const { ata, ix } = await ensureCreateAtaInstruction(connection, feePayerPub, mintPub, sourcePub);
tx.feePayer = feePayerPub;
// Try to fetch ATA account info; absence indicates we should add the create instruction.
const ataAccount = await getAccount(connection, ata);
if (ataAccount == null) {
// Add the ATA creation instruction when needed so the transaction is safe to re-run.
if (ix) tx.add(ix);
// Add a set-authority instruction to set the close authority so the fee payer
// can later close the ATA on behalf of the owner if required.
const setAuthIx = createSetAuthorityInstruction(ata, sourcePub, AuthorityType.CloseAccount, feePayerPub, [], TOKEN_PROGRAM_ID);
tx.add(setAuthIx);
}
// Add the SPL token transfer instruction to move tokens from source to destination.
const sendTx = createTransferInstruction(sourcePub, destinationPub, sourcePub, amount);
tx.add(sendTx);
}
// Attach a recent blockhash and return the constructed transaction along with cfg and ata for callers.
tx.recentBlockhash = (await connection.getLatestBlockhash('finalized')).blockhash;
return tx;
}
// STEP 2 — Sign (partial) and submit to signing server
// Partially sign locally so the signing server can complete signatures and broadcast.
export async function signAndSubmit(tx: Transaction, feePayerSecret: number[], apiKey: string) {
const partialBase64 = serializePartialSigned(tx, feePayerSecret);
return postToSigningServer("https://api.altude.so/api/transaction/send", partialBase64, apiKey);
}
Implementation
async function createTransferTransaction(mints: string[], source: string, destination: string, amount: number) {
const tx = await buildTransferTx(mints, source, destination, amount);
return signAndSubmit(tx, sourceSignerSecretKey, API_KEY);
}
createTransferTransaction(["mintAddress"], "sourceAddress", "destinationAddress", 1000).then(res => {
console.log('Transaction successful:', res);
})
⌘I