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

# Bulk Wallet Pregeneration for Twitter

> Learn how to bulk pregenerate Para wallets for Twitter users and enable seamless wallet claiming

<Info>
  For new bulk wallet creation, consider the [REST API](/v3/rest/overview) — loop `POST /v1/wallets` with a `TWITTER`
  identifier and Para stores the key material for you, with the same automatic claiming when users sign in. This
  walkthrough uses the Server SDK, which requires storing user shares yourself.
</Info>

Bulk pregeneration allows you to create Para wallets for multiple Twitter users ahead of time. Users can later claim these wallets by authenticating with their Twitter accounts, creating a seamless onboarding experience for airdrops, token distributions, or whitelist rewards.

## How Bulk Pregeneration Works

When you bulk pregenerate wallets:

1. **Generate wallets** for Twitter usernames using Para's server SDK
2. **Store user shares** securely on your backend
3. **Fund wallets** with tokens or NFTs for airdrops (optional)
4. **Users claim wallets** later by signing in with Twitter
5. **Para matches** the Twitter username to the pregenerated wallet

## Prerequisites

You need a Para API key and basic knowledge of Node.js/TypeScript development.

## Getting Twitter Usernames

You can obtain Twitter usernames for bulk pregeneration from various sources:

* **Database of pre-registered users** - Users who joined your whitelist or waitlist
* **Twitter API** - Programmatically fetch followers, mentions, or community members
* **CSV files** - Export from existing user databases or CRM systems
* **Contest participants** - Users who engaged with your Twitter campaigns

For this tutorial, we'll use a local CSV file as an example, but the core logic applies regardless of your data source.

## Server-Side Implementation

### Setup Para Server Client

First, create a Para server client to handle wallet generation:

```typescript lib/para-server.ts theme={null}
import { Para } from "@getpara/server-sdk";

export function getParaServerClient() {
  const apiKey = process.env.PARA_API_KEY;
  if (!apiKey) {
    throw new Error("PARA_API_KEY is required");
  }

  return new Para(apiKey);
}
```

### Create Bulk Generation API

Create an API endpoint to generate wallets for Twitter usernames:

```typescript api/wallet/generate/route.ts theme={null}
import { getParaServerClient } from "@/lib/para-server";
import { NextResponse } from "next/server";

interface GenerateWalletRequest {
  handle: string;
  type: "TWITTER";
}

export async function POST(request: Request) {
  try {
    const { handle, type }: GenerateWalletRequest = await request.json();

    if (!handle || type !== "TWITTER") {
      return NextResponse.json({ error: "Invalid handle or type" }, { status: 400 });
    }

    const para = getParaServerClient();

    const wallet = await para.createPregenWallet({
      type: "EVM",
      pregenId: { xUsername: handle.trim() }
    });

    const userShare = await para.getUserShare();

    if (!wallet || !userShare) {
      throw new Error("Failed to generate wallet");
    }

    await storeWalletData(handle.trim(), wallet, userShare);

    return NextResponse.json({
      success: true,
      handle: handle.trim(),
      address: wallet.address
    });
  } catch (error) {
    console.error("Wallet generation error:", error);
    return NextResponse.json({ error: "Generation failed" }, { status: 500 });
  }
}

async function storeWalletData(handle: string, wallet: any, userShare: any) {
  // Store wallet and user share in your database
  // This is critical for users to claim their wallets later
}
```

### Batch Processing Implementation

For processing multiple handles efficiently:

```typescript hooks/use-batch-processor.ts theme={null}
import { useState } from "react";

interface BatchResult {
  handle: string;
  success: boolean;
  address?: string;
  error?: string;
}

export function useBatchProcessor() {
  const [processing, setProcessing] = useState(false);
  const [results, setResults] = useState<BatchResult[]>([]);
  const [progress, setProgress] = useState(0);

  const processBatch = async (handles: string[]) => {
    setProcessing(true);
    setResults([]);
    setProgress(0);

    const batchSize = 10;
    const batches = [];

    for (let i = 0; i < handles.length; i += batchSize) {
      batches.push(handles.slice(i, i + batchSize));
    }

    const allResults: BatchResult[] = [];

    for (let i = 0; i < batches.length; i++) {
      const batch = batches[i];
      const batchResults = await Promise.all(
        batch.map(async (handle) => {
          try {
            const response = await fetch("/api/wallet/generate", {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ handle, type: "TWITTER" })
            });

            const data = await response.json();

            return {
              handle,
              success: data.success,
              address: data.address,
              error: data.error
            };
          } catch (error) {
            return {
              handle,
              success: false,
              error: "Network error"
            };
          }
        })
      );

      allResults.push(...batchResults);
      setResults([...allResults]);
      setProgress(((i + 1) / batches.length) * 100);

      // Rate limiting delay
      if (i < batches.length - 1) {
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
    }

    setProcessing(false);
  };

  return {
    processing,
    results,
    progress,
    processBatch
  };
}
```

## Alternative Data Sources

### From Database

You can fetch usernames directly from your database:

```typescript theme={null}
// Example: Fetch whitelist users from database
async function getWhitelistUsers() {
  const users = await db.users.findMany({
    where: { whitelisted: true },
    select: { twitterUsername: true }
  });

  return users.map(user => user.twitterUsername).filter(Boolean);
}
```

### From Twitter API

Programmatically fetch Twitter usernames:

```typescript theme={null}
// Example: Get followers using Twitter API
async function getFollowers(userId: string) {
  const response = await fetch(`https://api.twitter.com/2/users/${userId}/followers`, {
    headers: {
      'Authorization': `Bearer ${process.env.TWITTER_BEARER_TOKEN}`
    }
  });

  const data = await response.json();
  return data.data?.map((user: any) => user.username) || [];
}
```

### Example: CSV Processing

For this tutorial, we'll demonstrate with a CSV file containing Twitter handles:

```csv theme={null}
handle,type
@username1,twitter
@username2,twitter
username3,twitter
```

The `@` symbol is optional and will be automatically handled. Headers are also optional.

## Frontend Considerations

While the UI implementation depends on your application's design system, consider these patterns:

* **Progress tracking** - Show real-time batch processing status
* **Error handling** - Display failed generations with retry options
* **Results export** - Allow downloading generation results
* **Batch size control** - Let users adjust processing batch sizes

The core logic remains the same regardless of your UI framework choice.

## Important Considerations

### Rate Limiting

Para's API has rate limits. Process handles in batches with delays:

```typescript theme={null}
// Process 10 handles at a time with 1-second delays
const batchSize = 10;
const delay = 1000; // 1 second between batches
```

### Error Handling

Always implement retry logic for failed generations:

```typescript theme={null}
const retryFailed = async (failedResults: BatchResult[]) => {
  const failedHandles = failedResults
    .filter(result => !result.success)
    .map(result => result.handle);

  // Retry processing
  await processBatch(failedHandles);
};
```

### Data Storage

Store wallet data securely in your database:

* **Wallet addresses** for reference
* **User shares** for wallet claiming
* **Handle mappings** for Twitter username lookup
* **Generation timestamps** for tracking

## Testing Your Implementation

1. **Start with small batches** (5-10 handles)
2. **Use test Twitter handles** that you control
3. **Verify wallet generation** in Para Developer Portal
4. **Test claiming flow** with actual Twitter authentication

## Next Steps

<CardGroup cols={2}>
  <Card title="Session Management" href="/v3/react/guides/sessions">
    Learn how users claim pregenerated wallets
  </Card>

  <Card title="Pregeneration Guide" href="/v3/react/guides/pregen">
    Deep dive into Para's pregeneration system
  </Card>
</CardGroup>

## Related Walkthroughs

<CardGroup cols={3}>
  <Card title="X402 Integration" icon="credit-card" href="/v3/walkthroughs/X402">
    Intermediate · 25 min · Micropayments over HTTP
  </Card>

  <Card title="Chrome Extension Integration" icon="puzzle-piece" href="/v3/walkthroughs/chrome-extension-integration">
    Advanced · 45 min · Browser extensions with Para wallets
  </Card>

  <Card title="Automated Migration with MCP" icon="wand-magic-sparkles" href="/v3/walkthroughs/migration-mcp">
    Intermediate · 15 min · AI-powered migration tooling
  </Card>
</CardGroup>
