Skip to main content
POST
/
v1
/
delegation
/
solana
/
post-approval
curl --request POST \
  --url 'https://dev.api.baanx.com/v1/delegation/solana/post-approval' \
  --header 'x-client-key: YOUR_PUBLIC_KEY' \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "address": "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
    "network": "solana",
    "currency": "usdc",
    "amount": "5000",
    "txHash": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
    "sigHash": "2Uhj5WqpLvZmJqKGx3WKvSC5K1m4YCp1eK3jcGY7GgRqNnBQEXhP9XjWCv4M3nZKF7RqWpLvZmJqKGx3WKvSC5K1",
    "sigMessage": "Prove wallet ownership for delegation",
    "token": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebc"
  }'
{
  "success": true
}

Overview

This endpoint finalizes the delegation of spending authority from a user’s Solana wallet. After the user has completed wallet connection and token account delegation transaction in your frontend, call this endpoint to register the wallet with the platform.
When to Use: Call this endpoint after the user has successfully completed the token account delegation transaction on Solana in your frontend application (Step 2). This is the final step in the delegation workflow for Solana wallets.

Solana-Specific Validation

This endpoint performs strict validation for Solana blockchain:
  • Address Format: Must be a valid Solana public key (base58-encoded, 32-44 characters)
  • Transaction Signature: Must be a valid Solana transaction signature (base58-encoded, 87-88 characters)
  • Message Signature: Must be a valid Solana signature (base58-encoded, 87-88 characters)
  • Network: Must be solana

Authentication

x-client-key
string
required
Your public client key for API authentication
Authorization
string
required
Bearer token format: Bearer {access_token}
Content-Type
string
required
Must be application/json

Query Parameters

region
string
Region identifier for environment routing. Use us for US-specific routing.Example: ?region=usNote: Alternatively, you can use the x-us-env: true header instead of the region query parameter.

Request Body

address
string
required
Solana wallet public key that will be delegated. Must be a valid base58-encoded Solana public key (32-44 characters).Pattern: ^[1-9A-HJ-NP-Za-km-z]{32,44}$Example: DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKKThis address must match the one that signed the delegation transaction.
network
string
required
Must be solana for Solana blockchain.Allowed values:
  • solana - Solana mainnet
currency
string
required
SPL token that was approved for delegation.Allowed values:
  • usdc - USD Coin (SPL)
  • usdt - Tether USD (SPL)
amount
string
required
Spending limit approved in the delegation. Specified in the currency’s base unit (e.g., 5000 for 5000 USDC). This is the maximum amount the platform can spend from the delegated wallet.Pattern: ^\d+(\.\d+)?$Example: "5000" or "5000.50"
txHash
string
required
Solana transaction signature of the token account delegation. Must be a valid base58-encoded signature (87-88 characters).Pattern: ^[1-9A-HJ-NP-Za-km-z]{87,88}$Example: 5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUWThe API verifies this transaction exists on-chain and is confirmed.
sigHash
string
required
Solana signature hash proving wallet ownership. Result of signing sigMessage with the wallet’s private key. Must be a valid base58-encoded signature (87-88 characters).Pattern: ^[1-9A-HJ-NP-Za-km-z]{87,88}$Example: 2Uhj5WqpLvZmJqKGx3WKvSC5K1m4YCp1eK3jcGY7GgRqNnBQEXhP9XjWCv4M3nZKF7RqWpLvZmJqKGx3WKvSC5K1
sigMessage
string
required
The message that was signed by the Solana wallet to prove ownership. Can be any string that proves ownership, but should be meaningful.Minimum length: 10 charactersExample: "Prove wallet ownership for delegation"Recommended format: Include purpose, timestamp, and nonce for security
token
string
required
Single-use delegation token obtained from GET /v1/delegation/token (Step 1). Must be a valid UUID.Format: UUID v4Example: 100a99cf-f4d3-4fa1-9be9-2e9828b20ebcNote: Token expires after ~10 minutes or after successful use.

Response

success
boolean
required
Indicates whether the wallet delegation was completed successfully.
curl --request POST \
  --url 'https://dev.api.baanx.com/v1/delegation/solana/post-approval' \
  --header 'x-client-key: YOUR_PUBLIC_KEY' \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "address": "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
    "network": "solana",
    "currency": "usdc",
    "amount": "5000",
    "txHash": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
    "sigHash": "2Uhj5WqpLvZmJqKGx3WKvSC5K1m4YCp1eK3jcGY7GgRqNnBQEXhP9XjWCv4M3nZKF7RqWpLvZmJqKGx3WKvSC5K1",
    "sigMessage": "Prove wallet ownership for delegation",
    "token": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebc"
  }'
{
  "success": true
}

Response Codes

CodeDescription
201Wallet delegation completed successfully
400Bad request - invalid data format or verification failed
401Authentication failed - invalid or expired access token
422Validation error - invalid request parameters
498Invalid client key
499Missing client key
500Internal server error

What Happens After Success

When this endpoint returns successfully:
  1. Wallet Registration: The external wallet is registered and linked to the user’s account
  2. Card Payments Enabled: User can now make card purchases using delegated wallet funds
  3. Wallet Visibility: Wallet appears in GET /v1/wallet/external endpoint response
  4. Priority Assignment: Wallet is assigned a default priority for transaction processing
  5. Balance Tracking: Platform begins tracking wallet balance and allowance

Solana Token Delegation

On Solana, delegation uses SPL Token’s approve instruction to delegate token account authority:
import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';
import { Connection, PublicKey } from '@solana/web3.js';

const connection = new Connection('https://api.mainnet-beta.solana.com');

// Create approve instruction
const approveInstruction = Token.createApproveInstruction(
  TOKEN_PROGRAM_ID,
  tokenAccountAddress,      // User's token account
  delegateAddress,          // Platform's delegate address
  walletPublicKey,          // User's wallet
  [],                       // Signers (empty for wallet adapter)
  amount                    // Amount to approve
);

Complete Implementation Example

Here’s a full end-to-end example of the Solana delegation flow:
import { Connection, PublicKey, Transaction } from '@solana/web3.js';
import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';
import bs58 from 'bs58';

async function delegateSolanaWallet(delegationToken: string, amount: string) {
  try {
    // Step 1: Check if Phantom is installed
    const provider = (window as any).solana;
    if (!provider?.isPhantom) {
      throw new Error('Phantom wallet not found');
    }

    // Step 2: Connect wallet
    await provider.connect();
    const walletPublicKey = new PublicKey(provider.publicKey.toString());
    console.log('Connected to wallet:', walletPublicKey.toBase58());

    // Step 3: Setup connection and token accounts
    const connection = new Connection('https://api.mainnet-beta.solana.com');
    const tokenMintAddress = new PublicKey(
      'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' // USDC mint
    );

    // Get user's token account
    const tokenAccounts = await connection.getParsedTokenAccountsByOwner(
      walletPublicKey,
      { mint: tokenMintAddress }
    );

    if (tokenAccounts.value.length === 0) {
      throw new Error('No USDC token account found');
    }

    const tokenAccountAddress = tokenAccounts.value[0].pubkey;

    // Step 4: Create delegation transaction
    const delegateAddress = new PublicKey('YOUR_PLATFORM_DELEGATE_ADDRESS');
    const amountLamports = parseFloat(amount) * 1_000_000; // USDC has 6 decimals

    const transaction = new Transaction().add(
      Token.createApproveInstruction(
        TOKEN_PROGRAM_ID,
        tokenAccountAddress,
        delegateAddress,
        walletPublicKey,
        [],
        amountLamports
      )
    );

    // Set recent blockhash
    const { blockhash } = await connection.getRecentBlockhash();
    transaction.recentBlockhash = blockhash;
    transaction.feePayer = walletPublicKey;

    // Step 5: Sign and send delegation transaction
    const signedTx = await provider.signTransaction(transaction);
    const txSignature = await connection.sendRawTransaction(
      signedTx.serialize()
    );

    console.log('Delegation transaction sent:', txSignature);

    // Wait for confirmation
    await connection.confirmTransaction(txSignature, 'confirmed');
    console.log('Delegation transaction confirmed');

    // Step 6: Sign message for ownership proof
    const message = `Prove wallet ownership for delegation\nTimestamp: ${Date.now()}\nNonce: ${Math.random().toString(36).substring(7)}`;
    const encodedMessage = new TextEncoder().encode(message);
    const signedMessage = await provider.signMessage(encodedMessage, 'utf8');
    const signature = bs58.encode(signedMessage.signature);

    console.log('Message signed successfully');

    // Step 7: Submit to API
    const response = await fetch(
      'https://dev.api.baanx.com/v1/delegation/solana/post-approval',
      {
        method: 'POST',
        headers: {
          'x-client-key': 'YOUR_PUBLIC_KEY',
          'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          address: walletPublicKey.toBase58(),
          network: 'solana',
          currency: 'usdc',
          amount: amount,
          txHash: txSignature,
          sigHash: signature,
          sigMessage: message,
          token: delegationToken
        })
      }
    );

    const result = await response.json();

    if (response.ok) {
      console.log('Delegation completed successfully!');
      return { success: true, data: result };
    } else {
      console.error('Delegation failed:', result);
      return { success: false, error: result };
    }

  } catch (error) {
    console.error('Error during delegation:', error);
    return { success: false, error: (error as Error).message };
  }
}

// Usage
const result = await delegateSolanaWallet(
  '100a99cf-f4d3-4fa1-9be9-2e9828b20ebc',
  '5000'
);

Message Signing

For Solana, the sigMessage should be a clear, descriptive message. Here’s a recommended format:
function generateSolanaMessage(): string {
  const timestamp = Date.now();
  const nonce = Math.random().toString(36).substring(7);

  return `Prove wallet ownership for delegation
Timestamp: ${timestamp}
Nonce: ${nonce}
Action: Delegate spending authority to Baanx platform`;
}

// Sign the message
const message = generateSolanaMessage();
const encodedMessage = new TextEncoder().encode(message);
const signedMessage = await wallet.signMessage(encodedMessage, 'utf8');
const signature = bs58.encode(signedMessage.signature);

Redelegation

To update an existing delegation (change allowance, upgrade contracts, etc.), simply call this endpoint again with the same wallet address. The new delegation will replace the previous one. Common redelegation scenarios:
  • Increase spending limit: User wants to approve a higher amount
  • Contract upgrade: Platform deploys new smart contracts
  • Token account change: User wants to delegate a different token account
When redelegating, the user must complete a new token account delegation transaction with the updated parameters before calling this endpoint.

Verification After Delegation

After successful delegation, verify the wallet was registered:
curl --request GET \
  --url 'https://dev.api.baanx.com/v1/wallet/external' \
  --header 'x-client-key: YOUR_PUBLIC_KEY' \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'

Common Error Scenarios

Invalid Transaction Signature

{
  "message": "Transaction not found on blockchain"
}
Causes:
  • Transaction hasn’t been confirmed yet
  • Invalid transaction signature format
  • Wrong network (e.g., devnet instead of mainnet)
Solutions:
  • Wait for transaction confirmation (typically 10-30 seconds)
  • Verify signature is base58-encoded and 87-88 characters
  • Ensure transaction was sent to mainnet

Signature Verification Failed

{
  "message": "Signature verification failed"
}
Causes:
  • sigHash doesn’t match the wallet that signed
  • sigMessage was modified after signing
  • Wrong encoding used for signature
Solutions:
  • Ensure the same wallet signs both the delegation and message
  • Don’t modify sigMessage after user signs it
  • Use bs58.encode() for signature encoding

Invalid Address Format

{
  "message": "Invalid Solana address format"
}
Causes:
  • Address is not base58-encoded
  • Address length is incorrect
  • Contains invalid base58 characters (0, O, I, l)
Solutions:
  • Use publicKey.toBase58() to get correct format
  • Verify address is 32-44 characters
  • Don’t include prefixes or suffixes

Expired Delegation Token

{
  "message": "Delegation token has expired or already been used"
}
Causes:
  • More than 10 minutes passed since token generation
  • Token was already used in a previous request
Solutions:
  • Generate a new delegation token from Step 1
  • Complete the flow more quickly
  • Don’t reuse tokens

SPL Token Addresses

Common SPL token addresses on Solana mainnet:
TokenMint Address
USDCEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
USDTEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB
Always verify token addresses with official sources before using them in production.

Best Practices

Always wait for transaction confirmation before calling this endpoint:
  • Wait for ‘confirmed’ commitment level minimum
  • For higher security, wait for ‘finalized’ commitment
  • Display transaction status to users
  • Implement timeout handling (typically 60 seconds)
  • Provide transaction link to Solana Explorer
Support popular Solana wallets:
  • Phantom (most popular)
  • Solflare
  • Backpack
  • Glow
  • Use @solana/wallet-adapter for easy integration
  • Handle wallet not installed gracefully
Implement comprehensive error handling:
  • Handle user rejection gracefully
  • Retry failed transactions with same parameters
  • Provide clear error messages to users
  • Log errors for debugging (without exposing sensitive data)
  • Implement exponential backoff for API retries
Follow security best practices:
  • Never store private keys
  • Validate all addresses before submission
  • Use HTTPS only for all API calls
  • Implement rate limiting on your backend
  • Verify transaction on blockchain before submitting to API
  • Use recent blockhashes (prevent replay attacks)
Create a smooth user experience:
  • Show progress indicators during each step
  • Display transaction fees before approval
  • Explain delegation in simple terms
  • Provide transaction links to Solana Explorer
  • Allow users to easily retry on failure
  • Show estimated confirmation time

Solana-Specific Considerations

Transaction Fees

Solana transactions require SOL for transaction fees:
  • Typical fee: 0.000005 SOL (~$0.0001)
  • Ensure user has small amount of SOL for fees
  • Display estimated fee before transaction

Token Accounts

Users must have a token account for the SPL token:
  • Check if token account exists before delegation
  • Create token account if needed (costs ~0.002 SOL)
  • Handle associated token account vs regular token account

Network Congestion

During high network activity:
  • Transactions may take longer to confirm
  • Consider using higher priority fees
  • Implement retry logic with exponential backoff
  • Display status updates to user

Further Reading

External Resources