> ## 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.

# Overview

> Understanding the API architecture and integration patterns

## API Architecture

The Token Launch API uses a **partial transaction signing model** that provides security while maintaining user control:

<AccordionGroup>
  <Accordion title="Two-Phase Process" icon="arrow-right">
    **Phase 1: Prepare**

    * API creates unsigned transaction
    * User receives transaction for signing
    * No sensitive data exposed

    **Phase 2: Complete**

    * User signs transaction with their wallet
    * API adds protocol signature
    * Transaction submitted to blockchain
  </Accordion>

  <Accordion title="Security Benefits" icon="shield-check">
    * **User Control**: Users sign all transactions
    * **Key Isolation**: API never sees user private keys
    * **Transparency**: All operations visible on-chain
    * **Verification**: Users can inspect transactions before signing
  </Accordion>

  <Accordion title="Technical Design" icon="gear">
    * **Stateless**: No session management required
    * **RESTful**: Standard HTTP methods and status codes
    * **JSON**: All data exchange in JSON format
    * **Rate Limited**: IP-based throttling for fair usage
  </Accordion>
</AccordionGroup>

## Integration Patterns

### Web Application Integration

Perfect for dApps and web interfaces:

<CodeGroup>
  ```javascript react-example theme={null}
  import { useWallet } from '@solana/wallet-adapter-react';
  import { Transaction } from '@solana/web3.js';
  import bs58 from 'bs58';

  function TokenLauncher() {
    const { publicKey, signTransaction } = useWallet();
    const [launching, setLaunching] = useState(false);

    const launchToken = async (tokenData) => {
      if (!publicKey || !signTransaction) return;

      setLaunching(true);
      try {
        // Step 1: Create unsigned 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: "SOL" // Optional: "SOL" or "ZC"
          })
        });

        const launchResult = await launchResponse.json();

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

        // Step 3: 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()
          })
        });

        const confirmResult = await confirmResponse.json();

        if (confirmResult.success) {
          console.log('Token launched!', confirmResult.transactionSignature);
          return confirmResult;
        }
      } catch (error) {
        console.error('Launch failed:', error);
        throw error;
      } finally {
        setLaunching(false);
      }
    };

    return (
      <div>
        {/* Your UI components */}
        <button onClick={() => launchToken(formData)} disabled={launching}>
          {launching ? 'Launching...' : 'Launch Token'}
        </button>
      </div>
    );
  }
  ```

  ```typescript nextjs-example theme={null}
  // app/api/launch/route.ts
  import { NextRequest, NextResponse } from 'next/server';

  export async function POST(request: NextRequest) {
    try {
      const body = await request.json();

      // Validate input
      if (!body.name || !body.symbol || !body.payerPublicKey) {
        return NextResponse.json(
          { error: 'Missing required fields' },
          { status: 400 }
        );
      }

      // Proxy to API (with rate limiting)
      const response = await fetch('https://api.zcombinator.io/launch', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(body)
      });

      const result = await response.json();

      if (!response.ok) {
        return NextResponse.json(result, { status: response.status });
      }

      return NextResponse.json(result);
    } catch (error) {
      return NextResponse.json(
        { error: 'Internal server error' },
        { status: 500 }
      );
    }
  }
  ```
</CodeGroup>

### Backend Service Integration

For automated systems and batch operations:

<CodeGroup>
  ```python flask-backend theme={null}
  from flask import Flask, request, jsonify
  import requests
  from solders.pubkey import Pubkey
  from solders.transaction import Transaction
  import base58

  app = Flask(__name__)

  class TokenLaunchService:
      def __init__(self):
          self.api_base = 'https://api.zcombinator.io'
          self.session = requests.Session()

      def launch_token(self, token_data, wallet_keypair):
          """Launch a token programmatically"""

          # Step 1: Create launch transaction
          launch_response = self.session.post(
              f'{self.api_base}/launch',
              json={
                  **token_data,
                  'payerPublicKey': str(wallet_keypair.pubkey()),
                  'quoteToken': 'SOL'  # Optional: 'SOL' or 'ZC'
              }
          )
          launch_response.raise_for_status()
          launch_result = launch_response.json()

          # Step 2: Sign transaction
          transaction_bytes = base58.b58decode(launch_result['transaction'])
          transaction = Transaction.from_bytes(transaction_bytes)

          # Sign with your keypair
          transaction.sign([wallet_keypair])

          # Step 3: Confirm launch
          confirm_response = self.session.post(
              f'{self.api_base}/confirm-launch',
              json={
                  'signedTransaction': base58.b58encode(bytes(transaction)).decode(),
                  'baseMint': launch_result['baseMint'],
                  'metadataUrl': launch_result['metadataUrl'],
                  'name': token_data['name'],
                  'symbol': token_data['symbol'],
                  'payerPublicKey': str(wallet_keypair.pubkey())
              }
          )
          confirm_response.raise_for_status()

          return confirm_response.json()

  @app.route('/internal/launch-token', methods=['POST'])
  def internal_launch():
      """Internal endpoint for launching tokens"""
      data = request.get_json()

      # Your wallet management logic here
      wallet_keypair = load_wallet_keypair(data['wallet_id'])

      service = TokenLaunchService()
      result = service.launch_token(data['token_data'], wallet_keypair)

      return jsonify(result)
  ```

  ```javascript node-backend theme={null}
  // server.js
  const express = require('express');
  const { Keypair, Transaction } = require('@solana/web3.js');
  const bs58 = require('bs58');
  const fetch = require('node-fetch');

  const app = express();
  app.use(express.json());

  class TokenLaunchAPI {
    constructor() {
      this.baseURL = 'https://api.zcombinator.io';
    }

    async launchToken(tokenData, walletKeypair) {
      try {
        // Step 1: Create unsigned transaction
        const launchResponse = await fetch(`${this.baseURL}/launch`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            ...tokenData,
            payerPublicKey: walletKeypair.publicKey.toString(),
            quoteToken: "SOL" // Optional: "SOL" or "ZC"
          })
        });

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

        // Step 2: Sign transaction
        const transaction = Transaction.from(bs58.decode(launchResult.transaction));
        transaction.sign(walletKeypair);

        // Step 3: Confirm launch
        const confirmResponse = await fetch(`${this.baseURL}/confirm-launch`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            signedTransaction: bs58.encode(transaction.serialize()),
            baseMint: launchResult.baseMint,
            metadataUrl: launchResult.metadataUrl,
            name: tokenData.name,
            symbol: tokenData.symbol,
            payerPublicKey: walletKeypair.publicKey.toString()
          })
        });

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

        return confirmResult;
      } catch (error) {
        console.error('Token launch failed:', error);
        throw error;
      }
    }
  }

  // Usage endpoint
  app.post('/launch-token', async (req, res) => {
    try {
      const api = new TokenLaunchAPI();
      const walletKeypair = Keypair.fromSecretKey(
        bs58.decode(process.env.WALLET_PRIVATE_KEY)
      );

      const result = await api.launchToken(req.body, walletKeypair);
      res.json(result);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  });

  app.listen(3000, () => {
    console.log('Server running on port 3000');
  });
  ```
</CodeGroup>

### Mobile App Integration

For React Native and mobile applications:

<CodeGroup>
  ```javascript react-native theme={null}
  import { useConnection, useWallet } from '@solana/wallet-adapter-react';
  import { Transaction } from '@solana/web3.js';
  import bs58 from 'bs58';

  export const useTokenLauncher = () => {
    const { connection } = useConnection();
    const { publicKey, signTransaction } = useWallet();

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

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

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

        const result = await response.json();

        // Sign transaction
        const transaction = Transaction.from(bs58.decode(result.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: result.baseMint,
            metadataUrl: result.metadataUrl,
            name: tokenData.name,
            symbol: tokenData.symbol,
            payerPublicKey: publicKey.toString(),
          }),
        });

        const confirmResult = await confirmResponse.json();

        if (!confirmResponse.ok) {
          throw new Error(confirmResult.error);
        }

        return confirmResult;
      } catch (error) {
        console.error('Token launch error:', error);
        throw error;
      }
    };

    return { launchToken };
  };
  ```
</CodeGroup>

## Common Integration Patterns

### Error Handling

<AccordionGroup>
  <Accordion title="Retry Logic" icon="arrow-rotate-right">
    ```javascript theme={null}
    async function apiCallWithRetry(url, options, maxRetries = 3) {
      for (let attempt = 0; attempt < maxRetries; attempt++) {
        try {
          const response = await fetch(url, options);

          if (response.status === 429) {
            // Rate limited - wait before retry
            const delay = Math.min(1000 * (2 ** attempt), 30000);
            await new Promise(resolve => setTimeout(resolve, delay));
            continue;
          }

          if (response.status >= 500) {
            // Server error - retry with backoff
            if (attempt < maxRetries - 1) {
              const delay = 1000 * (2 ** attempt);
              await new Promise(resolve => setTimeout(resolve, delay));
              continue;
            }
          }

          return response;
        } catch (error) {
          if (attempt === maxRetries - 1) throw error;
          await new Promise(resolve => setTimeout(resolve, 1000 * (2 ** attempt)));
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="User Feedback" icon="comment">
    ```javascript theme={null}
    const handleLaunch = async (tokenData) => {
      setStatus('Creating transaction...');

      try {
        const launchResult = await createLaunchTransaction(tokenData);
        setStatus('Please sign the transaction in your wallet...');

        const signedTransaction = await signTransaction(launchResult.transaction);
        setStatus('Submitting to blockchain...');

        const confirmResult = await confirmLaunch(signedTransaction);
        setStatus('Token launched successfully!');

        return confirmResult;
      } catch (error) {
        if (error.message.includes('rate limit')) {
          setStatus('Rate limited. Please wait before trying again.');
        } else if (error.message.includes('User rejected')) {
          setStatus('Transaction cancelled by user.');
        } else {
          setStatus('Launch failed. Please try again.');
        }
        throw error;
      }
    };
    ```
  </Accordion>

  <Accordion title="Validation" icon="shield-check">
    ```javascript theme={null}
    const 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.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');
      }

      try {
        new PublicKey(data.payerPublicKey);
      } catch {
        errors.push('Invalid payer public key');
      }

      return errors;
    };

    const launchToken = async (tokenData) => {
      const validationErrors = validateTokenData(tokenData);
      if (validationErrors.length > 0) {
        throw new Error(`Validation failed: ${validationErrors.join(', ')}`);
      }

      // Proceed with launch...
    };
    ```
  </Accordion>
</AccordionGroup>

### Performance Optimization

<AccordionGroup>
  <Accordion title="Request Batching" icon="bars">
    ```javascript theme={null}
    class BatchAPIClient {
      constructor() {
        this.requestQueue = [];
        this.processing = false;
      }

      async queueRequest(endpoint, options) {
        return new Promise((resolve, reject) => {
          this.requestQueue.push({ endpoint, options, resolve, reject });
          this.processQueue();
        });
      }

      async processQueue() {
        if (this.processing || this.requestQueue.length === 0) return;

        this.processing = true;

        while (this.requestQueue.length > 0) {
          const batch = this.requestQueue.splice(0, 4); // Respect rate limit

          const promises = batch.map(async ({ endpoint, options, resolve, reject }) => {
            try {
              const response = await fetch(endpoint, options);
              const result = await response.json();
              resolve(result);
            } catch (error) {
              reject(error);
            }
          });

          await Promise.all(promises);

          // Wait for rate limit window if needed
          if (this.requestQueue.length > 0) {
            await new Promise(resolve => setTimeout(resolve, 2 * 60 * 1000));
          }
        }

        this.processing = false;
      }
    }
    ```
  </Accordion>

  <Accordion title="Response Caching" icon="database">
    ```javascript theme={null}
    class CachedAPIClient {
      constructor() {
        this.cache = new Map();
        this.cacheTimeout = 60000; // 1 minute
      }

      async get(url, cacheable = false) {
        const cacheKey = url;

        if (cacheable && this.cache.has(cacheKey)) {
          const { data, timestamp } = this.cache.get(cacheKey);
          if (Date.now() - timestamp < this.cacheTimeout) {
            return data;
          }
        }

        const response = await fetch(url);
        const data = await response.json();

        if (cacheable) {
          this.cache.set(cacheKey, {
            data,
            timestamp: Date.now()
          });
        }

        return data;
      }

      // Cache token verification permanently
      async verifyToken(address) {
        return this.get(
          `https://api.zcombinator.io/verify-token/${address}`,
          true // Cache token verification
        );
      }

      // Don't cache claim eligibility (changes over time)
      async getClaimEligibility(tokenAddress, wallet) {
        return this.get(
          `https://api.zcombinator.io/claims/${tokenAddress}?wallet=${wallet}`,
          false // Don't cache eligibility
        );
      }
    }
    ```
  </Accordion>
</AccordionGroup>

## Best Practices

<AccordionGroup>
  <Accordion title="Security" icon="shield-check">
    * **Never store private keys** in client-side applications
    * **Validate all inputs** before sending to API
    * **Use HTTPS** for all API communications
    * **Implement proper error handling** to avoid exposing sensitive information
    * **Verify transaction contents** before signing
  </Accordion>

  <Accordion title="User Experience" icon="heart">
    * **Show loading states** during API calls
    * **Provide clear error messages** with actionable guidance
    * **Implement proper retry logic** for transient failures
    * **Cache appropriate responses** to reduce API calls
    * **Respect rate limits** to maintain service availability
  </Accordion>

  <Accordion title="Monitoring" icon="gauge">
    * **Track API response times** and error rates
    * **Monitor rate limit usage** to avoid 429 errors
    * **Log transaction signatures** for debugging
    * **Implement health checks** using `/health` endpoint
    * **Set up alerts** for persistent API failures
  </Accordion>
</AccordionGroup>
