> ## Documentation Index
> Fetch the complete documentation index at: https://v1-docs.zcombinator.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Examples

> Complete working examples for different programming languages and frameworks

## Complete Token Launch Flow

### JavaScript/TypeScript (Web)

A complete example using modern web technologies:

<CodeGroup>
  ```typescript full-example theme={null}
  import { Connection, PublicKey, Transaction } from '@solana/web3.js';
  import bs58 from 'bs58';

  interface TokenData {
    name: string;
    symbol: string;
    description?: string;
    image?: string;
    website?: string;
    twitter?: string;
    caEnding?: string;
    quoteToken?: string;
  }

  class TokenLaunchClient {
    private baseURL = 'https://api.zcombinator.io';
    private requestCount = 0;
    private windowStart = Date.now();

    constructor(private wallet: any) {}

    private async makeRequest(endpoint: string, options: RequestInit) {
      // Simple rate limiting
      const now = Date.now();
      if (now - this.windowStart >= 2 * 60 * 1000) {
        this.requestCount = 0;
        this.windowStart = now;
      }

      if (this.requestCount >= 4) {
        const waitTime = 2 * 60 * 1000 - (now - this.windowStart);
        throw new Error(`Rate limited. Wait ${Math.ceil(waitTime / 1000)} seconds.`);
      }

      const response = await fetch(`${this.baseURL}${endpoint}`, options);
      this.requestCount++;

      if (response.status === 429) {
        throw new Error('Rate limited by server. Please wait 2 minutes.');
      }

      const data = await response.json();

      if (!response.ok) {
        throw new Error(data.error || 'API request failed');
      }

      return data;
    }

    async launchToken(tokenData: TokenData): Promise<any> {
      if (!this.wallet.publicKey) {
        throw new Error('Wallet not connected');
      }

      // Step 1: Validate inputs
      this.validateTokenData(tokenData);

      // Step 2: Create unsigned transaction
      console.log('Creating launch transaction...');
      const launchResult = await this.makeRequest('/launch', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          ...tokenData,
          payerPublicKey: this.wallet.publicKey.toString(),
          quoteToken: tokenData.quoteToken || "SOL" // Defaults to SOL if not specified
        })
      });

      // Step 3: Sign transaction
      console.log('Signing transaction...');
      const transaction = Transaction.from(bs58.decode(launchResult.transaction));
      const signedTransaction = await this.wallet.signTransaction(transaction);

      // Step 4: Confirm launch
      console.log('Confirming launch...');
      const confirmResult = await this.makeRequest('/confirm-launch', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          signedTransaction: bs58.encode(signedTransaction.serialize()),
          baseMint: launchResult.baseMint,
          metadataUrl: launchResult.metadataUrl,
          name: tokenData.name,
          symbol: tokenData.symbol,
          payerPublicKey: this.wallet.publicKey.toString()
        })
      });

      console.log('Token launched successfully!', confirmResult.transactionSignature);
      return confirmResult;
    }

    async checkClaimEligibility(tokenAddress: string, walletAddress: string) {
      const result = await this.makeRequest(
        `/claims/${tokenAddress}?wallet=${walletAddress}`,
        { method: 'GET' }
      );
      return result;
    }

    async claimTokens(tokenAddress: string, amount: string): Promise<any> {
      if (!this.wallet.publicKey) {
        throw new Error('Wallet not connected');
      }

      // Step 1: Check eligibility
      const eligibility = await this.checkClaimEligibility(
        tokenAddress,
        this.wallet.publicKey.toString()
      );

      if (!eligibility.canClaimNow) {
        throw new Error(`Cannot claim now. Next claim: ${eligibility.nextInflationTime}`);
      }

      if (BigInt(amount) > BigInt(eligibility.availableToClaim)) {
        throw new Error(`Amount ${amount} exceeds available ${eligibility.availableToClaim}`);
      }

      // Step 2: Create claim transaction
      console.log('Creating claim transaction...');
      const mintResult = await this.makeRequest('/claims/mint', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          tokenAddress,
          userWallet: this.wallet.publicKey.toString(),
          claimAmount: amount
        })
      });

      // Step 3: Sign transaction
      console.log('Signing claim transaction...');
      const transaction = Transaction.from(bs58.decode(mintResult.transaction));
      const signedTransaction = await this.wallet.signTransaction(transaction);

      // Step 4: Confirm claim
      console.log('Confirming claim...');
      const confirmResult = await this.makeRequest('/claims/confirm', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          signedTransaction: bs58.encode(signedTransaction.serialize()),
          transactionKey: mintResult.transactionKey
        })
      });

      console.log('Tokens claimed successfully!', confirmResult.transactionSignature);
      return confirmResult;
    }

    async verifyToken(address: string) {
      return this.makeRequest(`/verify-token/${address}`, { method: 'GET' });
    }

    async getHealth() {
      return this.makeRequest('/health', { method: 'GET' });
    }

    private validateTokenData(data: TokenData) {
      if (!data.name?.trim()) throw new Error('Token name is required');
      if (!data.symbol?.trim()) throw new Error('Token symbol is required');
      if (data.caEnding && data.caEnding.length > 3) {
        throw new Error('CA ending must be 3 characters or less');
      }
      if (data.caEnding && /[0OIl]/.test(data.caEnding)) {
        throw new Error('CA ending contains invalid Base58 characters');
      }
    }
  }

  // Usage example
  async function example() {
    // Assume wallet is connected (Phantom, Solflare, etc.)
    const wallet = window.solana;
    await wallet.connect();

    const client = new TokenLaunchClient(wallet);

    try {
      // Check API health
      const health = await client.getHealth();
      console.log('API Health:', health);

      // Launch a token
      const launchResult = await client.launchToken({
        name: "My Awesome Token",
        symbol: "MAT",
        description: "A demonstration token",
        image: "https://example.com/token-logo.png",
        website: "https://mytoken.com",
        twitter: "https://twitter.com/mytoken",
        caEnding: "MAT",
        quoteToken: "SOL" // Optional: "SOL" or "ZC"
      });

      console.log('Launched token:', launchResult.baseMint);

      // Verify the token was created
      const verification = await client.verifyToken(launchResult.baseMint);
      console.log('Token exists:', verification.exists);

      // Check claim eligibility
      const eligibility = await client.checkClaimEligibility(
        launchResult.baseMint,
        wallet.publicKey.toString()
      );
      console.log('Can claim:', eligibility.canClaimNow);

      // Claim tokens if eligible
      if (eligibility.canClaimNow && BigInt(eligibility.availableToClaim) > 0) {
        const claimResult = await client.claimTokens(
          launchResult.baseMint,
          eligibility.availableToClaim
        );
        console.log('Claimed tokens:', claimResult.transactionSignature);
      }

    } catch (error) {
      console.error('Error:', error.message);
    }
  }
  ```

  ```javascript react-hook theme={null}
  // useTokenLauncher.js
  import { useState, useCallback } from 'react';
  import { useWallet } from '@solana/wallet-adapter-react';
  import { Transaction } from '@solana/web3.js';
  import bs58 from 'bs58';

  export const useTokenLauncher = () => {
    const { publicKey, signTransaction } = useWallet();
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);

    const launchToken = useCallback(async (tokenData) => {
      if (!publicKey || !signTransaction) {
        throw new Error('Wallet not connected');
      }

      setLoading(true);
      setError(null);

      try {
        // Create launch transaction
        const launchResponse = await fetch('https://api.zcombinator.io/launch', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            ...tokenData,
            payerPublicKey: publicKey.toString(),
            quoteToken: tokenData.quoteToken || "SOL" // Optional: "SOL" or "ZC"
          })
        });

        if (!launchResponse.ok) {
          const errorData = await launchResponse.json();
          throw new Error(errorData.error);
        }

        const launchResult = await launchResponse.json();

        // Sign transaction
        const transaction = Transaction.from(bs58.decode(launchResult.transaction));
        const signedTransaction = await signTransaction(transaction);

        // Confirm launch
        const confirmResponse = await fetch('https://api.zcombinator.io/confirm-launch', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            signedTransaction: bs58.encode(signedTransaction.serialize()),
            baseMint: launchResult.baseMint,
            metadataUrl: launchResult.metadataUrl,
            name: tokenData.name,
            symbol: tokenData.symbol,
            payerPublicKey: publicKey.toString()
          })
        });

        if (!confirmResponse.ok) {
          const errorData = await confirmResponse.json();
          throw new Error(errorData.error);
        }

        const confirmResult = await confirmResponse.json();
        return confirmResult;

      } catch (err) {
        setError(err.message);
        throw err;
      } finally {
        setLoading(false);
      }
    }, [publicKey, signTransaction]);

    return { launchToken, loading, error };
  };

  // Component usage
  function TokenLaunchForm() {
    const { launchToken, loading, error } = useTokenLauncher();
    const [formData, setFormData] = useState({
      name: '',
      symbol: '',
      description: ''
    });

    const handleSubmit = async (e) => {
      e.preventDefault();
      try {
        const result = await launchToken(formData);
        alert(`Token launched! Transaction: ${result.transactionSignature}`);
      } catch (error) {
        alert(`Launch failed: ${error.message}`);
      }
    };

    return (
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="Token Name"
          value={formData.name}
          onChange={(e) => setFormData({...formData, name: e.target.value})}
          required
        />
        <input
          type="text"
          placeholder="Symbol"
          value={formData.symbol}
          onChange={(e) => setFormData({...formData, symbol: e.target.value})}
          required
        />
        <textarea
          placeholder="Description"
          value={formData.description}
          onChange={(e) => setFormData({...formData, description: e.target.value})}
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Launching...' : 'Launch Token'}
        </button>
        {error && <div style={{color: 'red'}}>{error}</div>}
      </form>
    );
  }
  ```
</CodeGroup>

### Python (Backend)

Server-side integration for automated systems:

<CodeGroup>
  ```python complete-client theme={null}
  import requests
  import time
  import base58
  from solders.keypair import Keypair
  from solders.transaction import Transaction
  from typing import Dict, Any, Optional

  class TokenLaunchClient:
      def __init__(self, wallet_keypair: Keypair):
          self.base_url = 'https://api.zcombinator.io'
          self.wallet_keypair = wallet_keypair
          self.session = requests.Session()
          self.request_count = 0
          self.window_start = time.time()

      def _make_request(self, endpoint: str, method: str = 'GET', data: Optional[Dict] = None) -> Dict[str, Any]:
          """Make API request with rate limiting"""
          # Simple rate limiting
          now = time.time()
          if now - self.window_start >= 120:  # 2 minutes
              self.request_count = 0
              self.window_start = now

          if self.request_count >= 4:
              wait_time = 120 - (now - self.window_start)
              raise Exception(f"Rate limited. Wait {wait_time:.0f} seconds.")

          url = f"{self.base_url}{endpoint}"

          try:
              if method == 'POST':
                  response = self.session.post(url, json=data, timeout=30)
              else:
                  response = self.session.get(url, timeout=30)

              self.request_count += 1

              if response.status_code == 429:
                  raise Exception("Rate limited by server. Please wait 2 minutes.")

              response.raise_for_status()
              return response.json()

          except requests.RequestException as e:
              raise Exception(f"API request failed: {str(e)}")

      def launch_token(self, token_data: Dict[str, str]) -> Dict[str, Any]:
          """Launch a new token"""
          print("Creating launch transaction...")

          # Step 1: Create unsigned transaction
          launch_result = self._make_request('/launch', 'POST', {
              **token_data,
              'payerPublicKey': str(self.wallet_keypair.pubkey()),
              'quoteToken': token_data.get('quoteToken', 'SOL')  # Optional: 'SOL' or 'ZC'
          })

          # Step 2: Sign transaction
          print("Signing transaction...")
          transaction_bytes = base58.b58decode(launch_result['transaction'])
          transaction = Transaction.from_bytes(transaction_bytes)
          transaction.sign([self.wallet_keypair])

          # Step 3: Confirm launch
          print("Confirming launch...")
          confirm_result = self._make_request('/confirm-launch', 'POST', {
              'signedTransaction': base58.b58encode(bytes(transaction)).decode(),
              'baseMint': launch_result['baseMint'],
              'metadataUrl': launch_result['metadataUrl'],
              'name': token_data['name'],
              'symbol': token_data['symbol'],
              'payerPublicKey': str(self.wallet_keypair.pubkey())
          })

          print(f"Token launched successfully! Transaction: {confirm_result['transactionSignature']}")
          return confirm_result

      def check_claim_eligibility(self, token_address: str, wallet_address: str) -> Dict[str, Any]:
          """Check claim eligibility for a wallet"""
          return self._make_request(f'/claims/{token_address}?wallet={wallet_address}')

      def claim_tokens(self, token_address: str, amount: str) -> Dict[str, Any]:
          """Claim available tokens"""
          wallet_address = str(self.wallet_keypair.pubkey())

          # Step 1: Check eligibility
          eligibility = self.check_claim_eligibility(token_address, wallet_address)

          if not eligibility['canClaimNow']:
              raise Exception(f"Cannot claim now. Next claim: {eligibility['nextInflationTime']}")

          if int(amount) > int(eligibility['availableToClaim']):
              raise Exception(f"Amount {amount} exceeds available {eligibility['availableToClaim']}")

          # Step 2: Create claim transaction
          print("Creating claim transaction...")
          mint_result = self._make_request('/claims/mint', 'POST', {
              'tokenAddress': token_address,
              'userWallet': wallet_address,
              'claimAmount': amount
          })

          # Step 3: Sign transaction
          print("Signing claim transaction...")
          transaction_bytes = base58.b58decode(mint_result['transaction'])
          transaction = Transaction.from_bytes(transaction_bytes)
          transaction.sign([self.wallet_keypair])

          # Step 4: Confirm claim
          print("Confirming claim...")
          confirm_result = self._make_request('/claims/confirm', 'POST', {
              'signedTransaction': base58.b58encode(bytes(transaction)).decode(),
              'transactionKey': mint_result['transactionKey']
          })

          print(f"Tokens claimed successfully! Transaction: {confirm_result['transactionSignature']}")
          return confirm_result

      def verify_token(self, address: str) -> Dict[str, Any]:
          """Verify if a token exists"""
          return self._make_request(f'/verify-token/{address}')

      def get_health(self) -> Dict[str, Any]:
          """Check API health"""
          return self._make_request('/health')

  # Usage example
  def main():
      # Load your wallet keypair
      # keypair = Keypair.from_bytes(your_private_key_bytes)
      keypair = Keypair()  # Generate new keypair for demo

      client = TokenLaunchClient(keypair)

      try:
          # Check API health
          health = client.get_health()
          print("API Health:", health)

          # Launch a token
          token_data = {
              'name': 'My Python Token',
              'symbol': 'PYT',
              'description': 'A token launched from Python',
              'caEnding': 'PYT',
              'quoteToken': 'SOL'  # Optional: 'SOL' or 'ZC'
          }

          launch_result = client.launch_token(token_data)
          token_address = launch_result['baseMint']

          # Verify token was created
          verification = client.verify_token(token_address)
          print(f"Token exists: {verification['exists']}")

          # Check claim eligibility
          eligibility = client.check_claim_eligibility(
              token_address,
              str(keypair.pubkey())
          )
          print(f"Can claim: {eligibility['canClaimNow']}")
          print(f"Available to claim: {eligibility['availableToClaim']}")

          # Claim tokens if eligible
          if eligibility['canClaimNow'] and int(eligibility['availableToClaim']) > 0:
              claim_result = client.claim_tokens(
                  token_address,
                  eligibility['availableToClaim']
              )
              print(f"Claimed tokens: {claim_result['transactionSignature']}")

      except Exception as e:
          print(f"Error: {e}")

  if __name__ == "__main__":
      main()
  ```

  ```python flask-wrapper theme={null}
  from flask import Flask, request, jsonify, g
  from functools import wraps
  import time

  app = Flask(__name__)

  # Rate limiting decorator
  def rate_limit(max_requests=4, window=120):
      def decorator(f):
          @wraps(f)
          def decorated_function(*args, **kwargs):
              if not hasattr(g, 'rate_limit_data'):
                  g.rate_limit_data = {'count': 0, 'window_start': time.time()}

              now = time.time()
              if now - g.rate_limit_data['window_start'] >= window:
                  g.rate_limit_data['count'] = 0
                  g.rate_limit_data['window_start'] = now

              if g.rate_limit_data['count'] >= max_requests:
                  return jsonify({
                      'error': 'Rate limited. Please wait before making more requests.'
                  }), 429

              g.rate_limit_data['count'] += 1
              return f(*args, **kwargs)
          return decorated_function
      return decorator

  @app.route('/api/launch', methods=['POST'])
  @rate_limit()
  def launch_token():
      """Launch a token via API proxy"""
      try:
          data = request.get_json()

          # Validate input
          required_fields = ['name', 'symbol', 'payerPublicKey']
          for field in required_fields:
              if field not in data:
                  return jsonify({'error': f'Missing required field: {field}'}), 400

          # Create client with server wallet
          keypair = load_server_wallet()  # Your wallet loading logic
          client = TokenLaunchClient(keypair)

          # Override payer with client's request
          token_data = {k: v for k, v in data.items() if k != 'payerPublicKey'}

          result = client.launch_token(token_data)
          return jsonify(result)

      except Exception as e:
          return jsonify({'error': str(e)}), 500

  @app.route('/api/claims/<token_address>', methods=['GET'])
  @rate_limit()
  def get_claim_eligibility(token_address):
      """Get claim eligibility"""
      try:
          wallet = request.args.get('wallet')
          if not wallet:
              return jsonify({'error': 'wallet parameter required'}), 400

          client = TokenLaunchClient(load_server_wallet())
          result = client.check_claim_eligibility(token_address, wallet)
          return jsonify(result)

      except Exception as e:
          return jsonify({'error': str(e)}), 500

  @app.route('/api/health', methods=['GET'])
  def health_check():
      """Proxy health check"""
      try:
          client = TokenLaunchClient(load_server_wallet())
          result = client.get_health()
          return jsonify(result)
      except Exception as e:
          return jsonify({'error': str(e)}), 500

  def load_server_wallet():
      """Load server wallet keypair"""
      # Implement your wallet loading logic here
      # This is a placeholder
      return Keypair()

  if __name__ == '__main__':
      app.run(debug=True)
  ```
</CodeGroup>

### Go (Backend)

High-performance server integration:

<CodeGroup>
  ```go client theme={null}
  package main

  import (
      "bytes"
      "encoding/json"
      "fmt"
      "io"
      "net/http"
      "time"
  )

  type TokenLaunchClient struct {
      BaseURL     string
      HTTPClient  *http.Client
      RequestCount int
      WindowStart  time.Time
  }

  type TokenData struct {
      Name        string `json:"name"`
      Symbol      string `json:"symbol"`
      Description string `json:"description,omitempty"`
      Image       string `json:"image,omitempty"`
      Website     string `json:"website,omitempty"`
      Twitter     string `json:"twitter,omitempty"`
      CAEnding    string `json:"caEnding,omitempty"`
      PayerPubkey string `json:"payerPublicKey"`
      QuoteToken  string `json:"quoteToken,omitempty"`
  }

  type LaunchResult struct {
      Success         bool   `json:"success"`
      Transaction     string `json:"transaction"`
      BaseMint        string `json:"baseMint"`
      MetadataURL     string `json:"metadataUrl"`
      Message         string `json:"message"`
  }

  type ClaimEligibility struct {
      WalletAddress      string    `json:"walletAddress"`
      TokenAddress       string    `json:"tokenAddress"`
      TotalClaimed       string    `json:"totalClaimed"`
      AvailableToClaim   string    `json:"availableToClaim"`
      MaxClaimableNow    string    `json:"maxClaimableNow"`
      TokensPerPeriod    string    `json:"tokensPerPeriod"`
      InflationPeriods   int       `json:"inflationPeriods"`
      TokenLaunchTime    time.Time `json:"tokenLaunchTime"`
      NextInflationTime  time.Time `json:"nextInflationTime"`
      CanClaimNow        bool      `json:"canClaimNow"`
      TimeUntilNextClaim int64     `json:"timeUntilNextClaim"`
  }

  func NewTokenLaunchClient() *TokenLaunchClient {
      return &TokenLaunchClient{
          BaseURL: "https://api.zcombinator.io",
          HTTPClient: &http.Client{
              Timeout: 30 * time.Second,
          },
          WindowStart: time.Now(),
      }
  }

  func (c *TokenLaunchClient) makeRequest(method, endpoint string, body interface{}) ([]byte, error) {
      // Rate limiting
      now := time.Now()
      if now.Sub(c.WindowStart) >= 2*time.Minute {
          c.RequestCount = 0
          c.WindowStart = now
      }

      if c.RequestCount >= 4 {
          waitTime := 2*time.Minute - now.Sub(c.WindowStart)
          return nil, fmt.Errorf("rate limited. wait %v", waitTime)
      }

      var reqBody io.Reader
      if body != nil {
          jsonData, err := json.Marshal(body)
          if err != nil {
              return nil, err
          }
          reqBody = bytes.NewBuffer(jsonData)
      }

      req, err := http.NewRequest(method, c.BaseURL+endpoint, reqBody)
      if err != nil {
          return nil, err
      }

      if body != nil {
          req.Header.Set("Content-Type", "application/json")
      }

      resp, err := c.HTTPClient.Do(req)
      if err != nil {
          return nil, err
      }
      defer resp.Body.Close()

      c.RequestCount++

      respBody, err := io.ReadAll(resp.Body)
      if err != nil {
          return nil, err
      }

      if resp.StatusCode == 429 {
          return nil, fmt.Errorf("rate limited by server")
      }

      if resp.StatusCode >= 400 {
          var errorResp map[string]interface{}
          json.Unmarshal(respBody, &errorResp)
          if msg, ok := errorResp["error"].(string); ok {
              return nil, fmt.Errorf("API error: %s", msg)
          }
          return nil, fmt.Errorf("API error: status %d", resp.StatusCode)
      }

      return respBody, nil
  }

  func (c *TokenLaunchClient) CreateLaunchTransaction(tokenData TokenData) (*LaunchResult, error) {
      respBody, err := c.makeRequest("POST", "/launch", tokenData)
      if err != nil {
          return nil, err
      }

      var result LaunchResult
      err = json.Unmarshal(respBody, &result)
      if err != nil {
          return nil, err
      }

      return &result, nil
  }

  func (c *TokenLaunchClient) GetClaimEligibility(tokenAddress, walletAddress string) (*ClaimEligibility, error) {
      endpoint := fmt.Sprintf("/claims/%s?wallet=%s", tokenAddress, walletAddress)
      respBody, err := c.makeRequest("GET", endpoint, nil)
      if err != nil {
          return nil, err
      }

      var result ClaimEligibility
      err = json.Unmarshal(respBody, &result)
      if err != nil {
          return nil, err
      }

      return &result, nil
  }

  func (c *TokenLaunchClient) VerifyToken(address string) (map[string]interface{}, error) {
      endpoint := fmt.Sprintf("/verify-token/%s", address)
      respBody, err := c.makeRequest("GET", endpoint, nil)
      if err != nil {
          return nil, err
      }

      var result map[string]interface{}
      err = json.Unmarshal(respBody, &result)
      if err != nil {
          return nil, err
      }

      return result, nil
  }

  func (c *TokenLaunchClient) GetHealth() (map[string]interface{}, error) {
      respBody, err := c.makeRequest("GET", "/health", nil)
      if err != nil {
          return nil, err
      }

      var result map[string]interface{}
      err = json.Unmarshal(respBody, &result)
      if err != nil {
          return nil, err
      }

      return result, nil
  }

  func main() {
      client := NewTokenLaunchClient()

      // Check API health
      health, err := client.GetHealth()
      if err != nil {
          fmt.Printf("Health check failed: %v\n", err)
          return
      }
      fmt.Printf("API Health: %+v\n", health)

      // Create launch transaction
      tokenData := TokenData{
          Name:        "Go Token",
          Symbol:      "GOTKN",
          Description: "A token launched from Go",
          CAEnding:    "GO",
          PayerPubkey: "YourWalletPublicKeyHere",
          QuoteToken:  "SOL", // Optional: "SOL" or "ZC"
      }

      result, err := client.CreateLaunchTransaction(tokenData)
      if err != nil {
          fmt.Printf("Launch failed: %v\n", err)
          return
      }

      fmt.Printf("Launch transaction created: %s\n", result.BaseMint)
      fmt.Printf("Transaction to sign: %s\n", result.Transaction)

      // Note: In a real implementation, you would:
      // 1. Deserialize the transaction
      // 2. Sign it with your wallet
      // 3. Call /confirm-launch with the signed transaction
  }
  ```
</CodeGroup>

## Testing and Development

### Local Testing Setup

<CodeGroup>
  ```javascript test-setup theme={null}
  // test-client.js
  const { TokenLaunchClient } = require('./token-launch-client');

  class TestClient extends TokenLaunchClient {
    constructor() {
      super(null); // No wallet for testing
      this.baseURL = 'https://api.zcombinator.io'; // Use real API for integration tests
    }

    async testHealthEndpoint() {
      try {
        const health = await this.getHealth();
        console.log('✅ Health endpoint working:', health.status);
        return true;
      } catch (error) {
        console.error('❌ Health endpoint failed:', error.message);
        return false;
      }
    }

    async testTokenVerification() {
      try {
        // Test with known token (USDC)
        const result = await this.verifyToken('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
        console.log('✅ Token verification working:', result.exists);
        return true;
      } catch (error) {
        console.error('❌ Token verification failed:', error.message);
        return false;
      }
    }

    async testRateLimiting() {
      console.log('Testing rate limiting...');
      let successCount = 0;
      let rateLimited = false;

      for (let i = 0; i < 6; i++) {
        try {
          await this.getHealth();
          successCount++;
          console.log(`Request ${i + 1}: Success`);
        } catch (error) {
          if (error.message.includes('rate limit')) {
            rateLimited = true;
            console.log(`Request ${i + 1}: Rate limited (expected)`);
            break;
          } else {
            console.error(`Request ${i + 1}: Unexpected error:`, error.message);
          }
        }

        // Small delay between requests
        await new Promise(resolve => setTimeout(resolve, 100));
      }

      if (rateLimited && successCount >= 4) {
        console.log('✅ Rate limiting working correctly');
        return true;
      } else {
        console.log('❌ Rate limiting not working as expected');
        return false;
      }
    }

    async runAllTests() {
      console.log('Running API integration tests...\n');

      const tests = [
        { name: 'Health Endpoint', fn: () => this.testHealthEndpoint() },
        { name: 'Token Verification', fn: () => this.testTokenVerification() },
        { name: 'Rate Limiting', fn: () => this.testRateLimiting() }
      ];

      let passed = 0;
      let total = tests.length;

      for (const test of tests) {
        console.log(`Running: ${test.name}`);
        const result = await test.fn();
        if (result) passed++;
        console.log('');
      }

      console.log(`\nTest Results: ${passed}/${total} passed`);

      if (passed === total) {
        console.log('🎉 All tests passed!');
      } else {
        console.log('❌ Some tests failed. Check your API configuration.');
      }
    }
  }

  // Run tests
  if (require.main === module) {
    const testClient = new TestClient();
    testClient.runAllTests().catch(console.error);
  }

  module.exports = { TestClient };
  ```

  ```python test-suite theme={null}
  # test_client.py
  import asyncio
  import aiohttp
  import time
  from typing import Dict, Any

  class TestClient:
      def __init__(self):
          self.base_url = 'https://api.zcombinator.io'
          self.session = None

      async def __aenter__(self):
          self.session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=30))
          return self

      async def __aexit__(self, exc_type, exc_val, exc_tb):
          if self.session:
              await self.session.close()

      async def make_request(self, endpoint: str, method: str = 'GET', data: Dict = None) -> Dict[str, Any]:
          """Make API request"""
          url = f"{self.base_url}{endpoint}"

          async with self.session.request(method, url, json=data) as response:
              result = await response.json()

              if response.status >= 400:
                  raise Exception(f"API error ({response.status}): {result.get('error', 'Unknown error')}")

              return result

      async def test_health_endpoint(self) -> bool:
          """Test health endpoint"""
          try:
              result = await self.make_request('/health')
              print(f"✅ Health endpoint working: {result['status']}")
              return True
          except Exception as e:
              print(f"❌ Health endpoint failed: {e}")
              return False

      async def test_token_verification(self) -> bool:
          """Test token verification"""
          try:
              # Test with known token (USDC)
              result = await self.make_request('/verify-token/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
              print(f"✅ Token verification working: {result['exists']}")
              return True
          except Exception as e:
              print(f"❌ Token verification failed: {e}")
              return False

      async def test_rate_limiting(self) -> bool:
          """Test rate limiting"""
          print("Testing rate limiting...")
          success_count = 0
          rate_limited = False

          for i in range(6):
              try:
                  await self.make_request('/health')
                  success_count += 1
                  print(f"Request {i + 1}: Success")
              except Exception as e:
                  if 'rate limit' in str(e).lower() or '429' in str(e):
                      rate_limited = True
                      print(f"Request {i + 1}: Rate limited (expected)")
                      break
                  else:
                      print(f"Request {i + 1}: Unexpected error: {e}")

              # Small delay between requests
              await asyncio.sleep(0.1)

          if rate_limited and success_count >= 4:
              print("✅ Rate limiting working correctly")
              return True
          else:
              print("❌ Rate limiting not working as expected")
              return False

      async def run_all_tests(self):
          """Run all integration tests"""
          print("Running API integration tests...\n")

          tests = [
              ("Health Endpoint", self.test_health_endpoint),
              ("Token Verification", self.test_token_verification),
              ("Rate Limiting", self.test_rate_limiting)
          ]

          passed = 0
          total = len(tests)

          for name, test_fn in tests:
              print(f"Running: {name}")
              result = await test_fn()
              if result:
                  passed += 1
              print()

          print(f"\nTest Results: {passed}/{total} passed")

          if passed == total:
              print("🎉 All tests passed!")
          else:
              print("❌ Some tests failed. Check your API configuration.")

  async def main():
      async with TestClient() as client:
          await client.run_all_tests()

  if __name__ == "__main__":
      asyncio.run(main())
  ```
</CodeGroup>

### Error Handling Examples

<CodeGroup>
  ```javascript error-handling theme={null}
  class RobustTokenClient {
    constructor(wallet) {
      this.wallet = wallet;
      this.baseURL = 'https://api.zcombinator.io';
      this.maxRetries = 3;
    }

    async makeRequestWithRetry(endpoint, options, retryCount = 0) {
      try {
        const response = await fetch(`${this.baseURL}${endpoint}`, options);

        if (response.status === 429) {
          // Rate limited - wait and retry
          if (retryCount < this.maxRetries) {
            const delay = Math.min(1000 * (2 ** retryCount), 30000);
            console.log(`Rate limited. Waiting ${delay}ms before retry...`);
            await new Promise(resolve => setTimeout(resolve, delay));
            return this.makeRequestWithRetry(endpoint, options, retryCount + 1);
          }
          throw new Error('Rate limit exceeded. Please try again later.');
        }

        if (response.status >= 500) {
          // Server error - retry with exponential backoff
          if (retryCount < this.maxRetries) {
            const delay = 1000 * (2 ** retryCount);
            console.log(`Server error. Retrying in ${delay}ms...`);
            await new Promise(resolve => setTimeout(resolve, delay));
            return this.makeRequestWithRetry(endpoint, options, retryCount + 1);
          }
        }

        const data = await response.json();

        if (!response.ok) {
          throw new Error(data.error || `HTTP ${response.status}`);
        }

        return data;

      } catch (error) {
        if (error.name === 'TypeError' && error.message.includes('fetch')) {
          // Network error
          if (retryCount < this.maxRetries) {
            const delay = 1000 * (2 ** retryCount);
            console.log(`Network error. Retrying in ${delay}ms...`);
            await new Promise(resolve => setTimeout(resolve, delay));
            return this.makeRequestWithRetry(endpoint, options, retryCount + 1);
          }
          throw new Error('Network connection failed. Please check your internet connection.');
        }
        throw error;
      }
    }

    async launchTokenSafely(tokenData) {
      try {
        // Validate inputs first
        this.validateTokenData(tokenData);

        // Check wallet connection
        if (!this.wallet.publicKey) {
          throw new Error('Please connect your wallet first.');
        }

        // Check API health
        try {
          await this.makeRequestWithRetry('/health', { method: 'GET' });
        } catch (error) {
          throw new Error('API is currently unavailable. Please try again later.');
        }

        // Proceed with launch...
        const launchResult = await this.makeRequestWithRetry('/launch', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            ...tokenData,
            payerPublicKey: this.wallet.publicKey.toString(),
            quoteToken: tokenData.quoteToken || "SOL" // Optional: "SOL" or "ZC"
          })
        });

        return launchResult;

      } catch (error) {
        // Categorize and handle different types of errors
        if (error.message.includes('Missing required fields')) {
          throw new Error('Please fill in all required fields (name, symbol).');
        } else if (error.message.includes('CA ending')) {
          throw new Error('Custom address ending must be 3 characters or less with valid characters.');
        } else if (error.message.includes('rate limit')) {
          throw new Error('Too many requests. Please wait a moment before trying again.');
        } else if (error.message.includes('Network')) {
          throw new Error('Connection failed. Please check your internet and try again.');
        } else {
          // Log unexpected errors for debugging
          console.error('Unexpected error:', error);
          throw new Error('An unexpected error occurred. Please try again or contact support.');
        }
      }
    }

    validateTokenData(data) {
      const errors = [];

      if (!data.name?.trim()) errors.push('Token name is required');
      if (!data.symbol?.trim()) errors.push('Token symbol is required');

      if (data.symbol && data.symbol.length > 10) {
        errors.push('Token symbol must be 10 characters or less');
      }

      if (data.caEnding && data.caEnding.length > 3) {
        errors.push('CA ending must be 3 characters or less');
      }

      if (data.caEnding && /[0OIl]/.test(data.caEnding)) {
        errors.push('CA ending contains invalid characters (0, O, I, l not allowed)');
      }

      if (data.website && !this.isValidURL(data.website)) {
        errors.push('Please enter a valid website URL');
      }

      if (errors.length > 0) {
        throw new Error(errors.join('. '));
      }
    }

    isValidURL(string) {
      try {
        new URL(string);
        return true;
      } catch {
        return false;
      }
    }
  }
  ```
</CodeGroup>

These examples provide complete, production-ready code that you can adapt for your specific use case. Each example includes proper error handling, rate limiting, validation, and follows best practices for API integration.
