Skip to main content
POST
/
Transaction
/
send
Send Transaction
curl --request POST \
  --url https://api.altude.so/api/Transaction/send \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: <x-api-key>' \
  --data '
{
  "signedTransaction": "<string>"
}
'
{
  "status": "Queued",
  "message": "Transaction sent successfully",
  "signature": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d"   
}
Submit a signed transaction to be processed on the Solana network.

headers

X-API-Key
string
required
The API key created from Altude

Request Body

signedTransaction
string
required
The base64-encoded signed transaction to send
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.

Response

success
boolean
Indicates if the transaction was sent successfully
signature
string
The transaction signature
{
  "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 (the authority) 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.

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(mint: 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 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);

   const tx = new Transaction();
   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, cfg, ata };
 }

 // 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(mint: string, source: string, destination: string, amount: number) {
  const { tx, cfg } = await buildTransferTx(mint, source, destination, amount);
  return signAndSubmit(tx, sourceSignerSecretKey, API_KEY);
}

createTransferTransaction("mintAddress", "sourceAddress", "destinationAddress", 1000).then(res => {
  console.log('Transaction successful:', res);
})