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

# Legacy Wallet Create API

This guide shows how to create Swig wallets programmatically using the Developer Portal API. This approach is ideal for applications that need to create wallets on behalf of users with predefined policies.

<Note>
  This page covers the direct developer-portal API clients
  <code>@swig-wallet/api</code> and <code>@swig-wallet/developer</code>. If you
  want the newer prepare-first SDK in
  <code>swig-ts/packages/developer-sdk</code>, start with
  [What the Developer SDK Does](/developer-sdk).
  Treat <code>@swig-wallet/developer</code> as the legacy developer SDK for
  existing integrations.
</Note>

## When to Use the API

**Use the Portal API when:**

* Creating wallets from a backend service
* Using predefined policies from the Developer Portal
* Leveraging the paymaster for sponsored wallet creation (optional)
* You want to build the transaction server-side but sign and send it client-side
* Managing wallets at scale

**Use the direct protocol SDKs when:**

* Building client-side applications
* Users control their own keypairs
* You need full control over wallet configuration
* Not using the Developer Portal policies

<Tip>
  For direct SDK wallet creation (without the Portal API), see the [Creating a Swig tutorial](/tutorials/typescript/create).
</Tip>

## Prerequisites

Before creating wallets via the API, ensure you have:

* An [API key](./create-api-key) created in the Developer Portal
* A [policy](./create-policy) configured (with or without a signer)
* (Optional) A paymaster public key — see [Creating a Paymaster](./create-paymaster)

<Info>
  A paymaster is **optional**. When you omit `paymasterPubkey`, the API returns an unsigned transaction instead of submitting it on-chain. You can then sign and send the transaction yourself. See [Creating Without a Paymaster](#creating-without-a-paymaster) below.
</Info>

## Installing a Portal Client

<Tabs>
  <Tab title="API SDK">
    ```bash theme={null}
    npm install @swig-wallet/api
    # or
    bun add @swig-wallet/api
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```bash theme={null}
    npm install @swig-wallet/developer
    # or
    bun add @swig-wallet/developer
    ```
  </Tab>
</Tabs>

## Current Swig Developer SDK

If you are starting a new server-assisted integration, prefer
<code>@swig-wallet/developer-sdk</code> over
<code>@swig-wallet/developer</code>.

The current package is prepare-first:

1. your server uses an API key
2. the server prepares wallet transactions
3. the client signs only the required transactions
4. your app submits them directly or through a sponsor flow

Minimal server-side example:

```typescript theme={null}
import { SwigClient } from '@swig-wallet/developer-sdk/server/typescript';

const swig = new SwigClient({
  apiKey: process.env.SWIG_API_KEY!,
  network: 'devnet',
});

const created = await swig.wallets.create({
  feePayer,
  initialUser: {
    ed25519: {
      publicKey: userPublicKey,
    },
  },
});

return {
  wallet: created.wallet,
  transactions: created.transactions,
  clientAuthorityTransactions: created.clientAuthorityTransactions,
};
```

Use this page when you specifically want the developer-portal create-wallet
endpoint or its older portal clients. Use [What the Developer SDK Does](/developer-sdk)
for the current product surface.

For the current hosted operation flows after wallet creation, see
[Transfers and Swaps](/developer-sdk/transfers-swaps-and-signing) and
[Recovery](/developer-sdk/recovery-flows).

## Specifying the Wallet Authority

When creating a Swig wallet, you need to define the authority (signer) that will control it. There are two ways to do this:

**Option 1: Using a Signer ID from the Dashboard**

If you've already created a signer in the Developer Portal dashboard (or your policy has one attached), you can reference it by its `signerId`. This is the original approach and is useful when you manage signers centrally through the portal.

**Option 2: Providing a Wallet Address and Type Directly**

You can supply a `walletAddress` (the public key) and `walletType` (the authority type) at creation time instead of using a signer ID. This lets you skip creating a signer in the dashboard entirely -- useful when your application already knows the user's public key and authority type.

<Info>
  Provide either `signerId` **or** the `walletAddress` + `walletType` pair. When
  your policy already has a signer attached and both inputs are omitted, the
  policy's signer is used by default.
</Info>

### Supported Wallet Types

When using the `walletAddress` + `walletType` approach, the following types are supported:

| Type                | Description                    |
| ------------------- | ------------------------------ |
| `ED25519`           | Standard Solana keypair        |
| `ED25519_SESSION`   | Time-limited Ed25519 session   |
| `SECP256K1`         | Ethereum-compatible keys       |
| `SECP256K1_SESSION` | Time-limited Secp256k1 session |
| `SECP256R1`         | WebAuthn/Passkey compatible    |
| `SECP256R1_SESSION` | Time-limited Secp256r1 session |

<Tip>
  For session types (`ED25519_SESSION`, `SECP256K1_SESSION`, `SECP256R1_SESSION`), you must also provide the `maxDurationSlots` parameter to specify how long the session authority remains valid.
</Tip>

## Creating a Swig Wallet

### Using the REST API

Make a POST request to the wallet creation endpoint:

```bash theme={null}
curl -X POST "https://dashboard.onswig.com/api/v1/wallet/create" \
  -H "Authorization: Bearer sk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "policyId": "clx1234567890abcdef",
    "network": "devnet",
    "paymasterPubkey": "PaymasterPublicKeyHere..."
  }'
```

You can also supply the wallet authority directly instead of relying on a signer from the dashboard:

```bash theme={null}
curl -X POST "https://dashboard.onswig.com/api/v1/wallet/create" \
  -H "Authorization: Bearer sk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "policyId": "clx1234567890abcdef",
    "network": "devnet",
    "paymasterPubkey": "PaymasterPublicKeyHere...",
    "walletAddress": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
    "walletType": "ED25519"
  }'
```

**Example Response:**

```json theme={null}
{
  "swigId": "a1b2c3d4e5f67890",
  "swigAddress": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
  "signature": "5wHu1qwD7g4p3zWxF..."
}
```

### Using a Portal Client

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    import { SwigApiClient } from '@swig-wallet/api';

    // Initialize the client
    const client = new SwigApiClient({
      apiKey: 'sk_your_api_key',
      portalUrl: 'https://dashboard.onswig.com',
    });

    // Create a wallet
    async function createWallet() {
      const { data: wallet, error } = await client.wallet.create({
        policyId: 'clx1234567890abcdef',
        network: 'devnet',
        paymasterPubkey: 'PaymasterPublicKeyHere...',
      });

      if (error) {
        console.error(`Error creating wallet: ${error.message}`);
        return null;
      }

      console.log('Swig ID:', wallet.swigId);
      console.log('Wallet Address:', wallet.swigAddress);
      console.log('Transaction Signature:', wallet.signature);

      return wallet;
    }

    const wallet = await createWallet();
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    import { SwigClient, SwigError } from '@swig-wallet/developer';

    // Initialize the client
    const client = new SwigClient({
      apiKey: 'sk_your_api_key',
      baseUrl: 'https://dashboard.onswig.com',
    });

    // Create a wallet
    async function createWallet() {
      try {
        const wallet = await client.createWallet({
          policyId: 'clx1234567890abcdef',
          network: 'devnet',
          paymasterPubkey: 'PaymasterPublicKeyHere...',
        });

        console.log('Swig ID:', wallet.swigId);
        console.log('Wallet Address:', wallet.swigAddress);
        console.log('Transaction Signature:', wallet.signature);

        return wallet;
      } catch (error) {
        if (error instanceof SwigError) {
          console.error(`Error: ${error.code} - ${error.message}`);
        }
        return null;
      }
    }

    const wallet = await createWallet();
    ```
  </Tab>
</Tabs>

#### With Wallet Address and Type

You can also provide a `walletAddress` and `walletType` directly instead of relying on a signer configured in the dashboard:

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    import { SwigApiClient } from '@swig-wallet/api';

    const client = new SwigApiClient({
      apiKey: 'sk_your_api_key',
      portalUrl: 'https://dashboard.onswig.com',
    });

    async function createWallet() {
      const { data: wallet, error } = await client.wallet.create({
        policyId: 'clx1234567890abcdef',
        network: 'devnet',
        paymasterPubkey: 'PaymasterPublicKeyHere...',
        walletAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',
        walletType: 'ED25519',
      });

      if (error) {
        console.error(`Error creating wallet: ${error.message}`);
        return null;
      }

      console.log('Swig ID:', wallet.swigId);
      console.log('Wallet Address:', wallet.swigAddress);
      console.log('Transaction Signature:', wallet.signature);

      return wallet;
    }

    const wallet = await createWallet();
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    import { SwigClient, SwigError } from '@swig-wallet/developer';

    const client = new SwigClient({
      apiKey: 'sk_your_api_key',
      baseUrl: 'https://dashboard.onswig.com',
    });

    async function createWallet() {
      try {
        const wallet = await client.createWallet({
          policyId: 'clx1234567890abcdef',
          network: 'devnet',
          paymasterPubkey: 'PaymasterPublicKeyHere...',
          walletAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',
          walletType: 'ED25519',
        });

        console.log('Swig ID:', wallet.swigId);
        console.log('Wallet Address:', wallet.swigAddress);
        console.log('Transaction Signature:', wallet.signature);

        return wallet;
      } catch (error) {
        if (error instanceof SwigError) {
          console.error(`Error: ${error.code} - ${error.message}`);
        }
        return null;
      }
    }

    const wallet = await createWallet();
    ```
  </Tab>
</Tabs>

## Portal Client Comparison

| Feature               | `@swig-wallet/api`                 | `@swig-wallet/developer` (legacy)           |
| --------------------- | ---------------------------------- | ------------------------------------------- |
| Error handling        | Returns `{ data, error }`          | Throws `SwigError`                          |
| Method name           | `client.wallet.create()`           | `client.createWallet()`                     |
| No-paymaster response | Raw base58 string in `transaction` | Reconstructed `VersionedTransaction` object |
| Best for              | Low-level control                  | Existing legacy portal integrations         |

## Request Parameters

### Required Parameters

| Parameter  | Type                      | Description                             |
| ---------- | ------------------------- | --------------------------------------- |
| `policyId` | string                    | The policy ID from the Developer Portal |
| `network`  | `'mainnet'` \| `'devnet'` | Target Solana network                   |

### Optional Parameters

| Parameter          | Type         | Description                                                                                                                                                                                                          |
| ------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `paymasterPubkey`  | string       | Public key of the paymaster covering fees. When provided, the paymaster signs and sends the transaction. When omitted, the API returns an unsigned transaction for you to sign and send.                             |
| `swigId`           | string       | Custom Swig ID (auto-generated if not provided)                                                                                                                                                                      |
| `signerId`         | string       | Signer ID from the dashboard (alternative to `walletAddress` + `walletType`)                                                                                                                                         |
| `walletAddress`    | string       | Wallet public key to use as the authority (alternative to `signerId`). Must be provided together with `walletType`.                                                                                                  |
| `walletType`       | `WalletType` | Authority type for the wallet (alternative to `signerId`). Must be provided together with `walletAddress`. One of: `ED25519`, `ED25519_SESSION`, `SECP256K1`, `SECP256K1_SESSION`, `SECP256R1`, `SECP256R1_SESSION`. |
| `maxDurationSlots` | string       | Maximum session duration in slots. Only valid for session authority types (`ED25519_SESSION`, `SECP256K1_SESSION`, `SECP256R1_SESSION`).                                                                             |

## Response Fields

The response shape depends on whether a paymaster was provided.

### With Paymaster

| Field         | Type   | Description                                      |
| ------------- | ------ | ------------------------------------------------ |
| `swigId`      | string | The unique identifier for this Swig wallet       |
| `swigAddress` | string | The on-chain PDA address of the wallet           |
| `signature`   | string | The transaction signature (viewable on explorer) |

### Without Paymaster

| Field         | Type   | Description                                                 |
| ------------- | ------ | ----------------------------------------------------------- |
| `swigId`      | string | The unique identifier for this Swig wallet                  |
| `swigAddress` | string | The on-chain PDA address of the wallet                      |
| `transaction` | string | Base58-encoded serialized `VersionedTransaction` (unsigned) |

<Note>
  When no paymaster is used, the expected swig address is still recorded in the Developer Portal database so you can track and manage it through the dashboard.
</Note>

## Creating Without a Paymaster

When you omit `paymasterPubkey`, the API builds the create-swig transaction but does **not** send it. Instead, it returns a base58-encoded serialized `VersionedTransaction` that you can deserialize, sign, and send yourself.

This is useful when:

* Your users pay their own transaction fees
* You want to collect multiple signatures before sending
* You prefer to manage fee payment directly

### Using the REST API (No Paymaster)

```bash theme={null}
curl -X POST "https://dashboard.onswig.com/api/v1/wallet/create" \
  -H "Authorization: Bearer sk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "policyId": "clx1234567890abcdef",
    "network": "devnet"
  }'
```

**Example Response:**

```json theme={null}
{
  "data": {
    "swigId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "swigAddress": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
    "transaction": "BASE58_ENCODED_VERSIONED_TRANSACTION..."
  },
  "error": null
}
```

### Using the SDK (No Paymaster)

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    import { SwigApiClient } from '@swig-wallet/api';

    const client = new SwigApiClient({
      apiKey: 'sk_your_api_key',
      portalUrl: 'https://dashboard.onswig.com',
    });

    // Create without paymaster — returns the raw transaction data
    const { data, error } = await client.wallet.create({
      policyId: 'clx1234567890abcdef',
      network: 'devnet',
      // No paymasterPubkey
    });

    if (error) {
      console.error(`Error: ${error.message}`);
    } else if (data && 'transaction' in data) {
      console.log('Swig ID:', data.swigId);
      console.log('Swig Address:', data.swigAddress);
      console.log('Transaction (base58):', data.transaction);

      // Reconstruct, sign, and send the transaction yourself:
      // const txBytes = bs58.decode(data.transaction);
      // const tx = VersionedTransaction.deserialize(txBytes);
      // tx.sign([yourKeypair]);
      // const sig = await connection.sendTransaction(tx);
    }
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    import { Connection } from '@solana/web3.js';
    import { SwigClient, SwigError } from '@swig-wallet/developer';

    const client = new SwigClient({
      apiKey: 'sk_your_api_key',
      baseUrl: 'https://dashboard.onswig.com',
    });

    try {
      // Create without paymaster — returns a VersionedTransaction object
      const result = await client.createWallet({
        policyId: 'clx1234567890abcdef',
        network: 'devnet',
        // No paymasterPubkey
      });

      if ('transaction' in result) {
        console.log('Swig ID:', result.swigId);
        console.log('Swig Address:', result.swigAddress);

        // The SDK automatically reconstructs the VersionedTransaction
        const tx = result.transaction; // VersionedTransaction object

        // Sign with your keypair and send
        tx.sign([yourKeypair]);
        const connection = new Connection('https://api.devnet.solana.com');
        const signature = await connection.sendTransaction(tx);
        console.log('Transaction sent:', signature);
      }
    } catch (error) {
      if (error instanceof SwigError) {
        console.error(`Error: ${error.code} - ${error.message}`);
      }
    }
    ```
  </Tab>
</Tabs>

<Warning>
  When using the no-paymaster flow, the returned transaction includes a recent blockhash. Blockhashes expire after approximately 60-90 seconds. You must sign and send the transaction promptly.
</Warning>

## Examples

### Basic Wallet Creation

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    import { SwigApiClient } from '@swig-wallet/api';

    const client = new SwigApiClient({
      apiKey: process.env.SWIG_API_KEY!,
      portalUrl: 'https://dashboard.onswig.com',
    });

    const { data, error } = await client.wallet.create({
      policyId: 'your-policy-id',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
    });

    if (data) {
      console.log(`Wallet created: ${data.swigAddress}`);
      console.log(`View on explorer: https://explorer.solana.com/address/${data.swigAddress}?cluster=devnet`);
    }
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    import { SwigClient } from '@swig-wallet/developer';

    const client = new SwigClient({
      apiKey: process.env.SWIG_API_KEY!,
      baseUrl: 'https://dashboard.onswig.com',
    });

    const wallet = await client.createWallet({
      policyId: 'your-policy-id',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
    });

    console.log(`Wallet created: ${wallet.swigAddress}`);
    console.log(`View on explorer: https://explorer.solana.com/address/${wallet.swigAddress}?cluster=devnet`);
    ```
  </Tab>
</Tabs>

### With Custom Swig ID

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    // Generate a custom ID (must be unique)
    const customId = crypto.randomUUID().replace(/-/g, '').slice(0, 16);

    const { data, error } = await client.wallet.create({
      policyId: 'your-policy-id',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
      swigId: customId,
    });
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    // Generate a custom ID (must be unique)
    const customId = crypto.randomUUID().replace(/-/g, '').slice(0, 16);

    const wallet = await client.createWallet({
      policyId: 'your-policy-id',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
      swigId: customId,
    });
    ```
  </Tab>
</Tabs>

### With Signer Override

If your policy doesn't have a signer attached, or you want to use a different signer from the dashboard:

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    const { data, error } = await client.wallet.create({
      policyId: 'policy-without-signer',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
      signerId: 'specific-signer-id', // Signer ID from the portal
    });
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    const wallet = await client.createWallet({
      policyId: 'policy-without-signer',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
      signerId: 'specific-signer-id', // Signer ID from the portal
    });
    ```
  </Tab>
</Tabs>

### With Wallet Address and Type

Instead of creating a signer in the dashboard and referencing it by ID, you can supply the wallet's public key and authority type directly at creation time:

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    const { data, error } = await client.wallet.create({
      policyId: 'your-policy-id',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
      walletAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',
      walletType: 'ED25519',
    });
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    const wallet = await client.createWallet({
      policyId: 'your-policy-id',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
      walletAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',
      walletType: 'ED25519',
    });
    ```
  </Tab>
</Tabs>

### With Session Authority

For session-based authority types, include `maxDurationSlots` to set the session lifetime:

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    const { data, error } = await client.wallet.create({
      policyId: 'your-policy-id',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
      walletAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',
      walletType: 'ED25519_SESSION',
      maxDurationSlots: '1000000', // session duration in slots
    });
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    const wallet = await client.createWallet({
      policyId: 'your-policy-id',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
      walletAddress: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',
      walletType: 'ED25519_SESSION',
      maxDurationSlots: '1000000', // session duration in slots
    });
    ```
  </Tab>
</Tabs>

### Production Wallet

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    const { data, error } = await client.wallet.create({
      policyId: 'production-policy-id',
      network: 'mainnet', // Use mainnet for production
      paymasterPubkey: 'ProductionPaymasterKey',
    });

    if (data) {
      // Store the wallet info in your database
      await db.wallets.create({
        swigId: data.swigId,
        address: data.swigAddress,
        createdAt: new Date(),
      });
    }
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    const wallet = await client.createWallet({
      policyId: 'production-policy-id',
      network: 'mainnet', // Use mainnet for production
      paymasterPubkey: 'ProductionPaymasterKey',
    });

    // Store the wallet info in your database
    await db.wallets.create({
      swigId: wallet.swigId,
      address: wallet.swigAddress,
      createdAt: new Date(),
    });
    ```
  </Tab>
</Tabs>

## Error Handling

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    const { data, error } = await client.wallet.create({
      policyId: 'your-policy-id',
      network: 'devnet',
      paymasterPubkey: 'YourPaymasterPublicKey',
    });

    if (error) {
      switch (error.code) {
        case 'NOT_FOUND':
          console.error('Policy not found. Check the policy ID.');
          break;
        case 'UNAUTHORIZED':
          console.error('Invalid API key.');
          break;
        case 'BAD_REQUEST':
          console.error('Invalid request:', error.details);
          break;
        case 'CONFLICT':
          console.error('Swig ID already exists. Try a different ID.');
          break;
        default:
          console.error(`Unexpected error: ${error.message}`);
      }
    }
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    try {
      const wallet = await client.createWallet({
        policyId: 'your-policy-id',
        network: 'devnet',
        paymasterPubkey: 'YourPaymasterPublicKey',
      });
    } catch (error) {
      if (error instanceof SwigError) {
        switch (error.code) {
          case 'POLICY_NOT_FOUND':
            console.error('Policy not found. Check the policy ID.');
            break;
          case 'UNAUTHORIZED':
            console.error('Invalid API key.');
            break;
          case 'BAD_REQUEST':
            console.error('Invalid request:', error.response);
            break;
          case 'SWIG_ID_EXISTS':
            console.error('Swig ID already exists. Try a different ID.');
            break;
          default:
            console.error(`Unexpected error: ${error.message}`);
        }
      }
    }
    ```
  </Tab>
</Tabs>

### Common Errors

| Status | Code                             | Meaning                    |
| ------ | -------------------------------- | -------------------------- |
| 400    | `BAD_REQUEST`                    | Invalid request parameters |
| 401    | `UNAUTHORIZED`                   | Invalid or missing API key |
| 404    | `NOT_FOUND` / `POLICY_NOT_FOUND` | Policy or signer not found |
| 409    | `CONFLICT` / `SWIG_ID_EXISTS`    | Swig ID already exists     |
| 500    | `INTERNAL_ERROR`                 | Server error, try again    |

## Complete Example

<Tabs>
  <Tab title="API SDK">
    ```typescript theme={null}
    import { SwigApiClient } from '@swig-wallet/api';

    async function main() {
      const client = new SwigApiClient({
        apiKey: process.env.SWIG_API_KEY!,
        portalUrl: 'https://dashboard.onswig.com',
        retry: { maxRetries: 3, retryDelay: 1000 },
      });

      const config = {
        policyId: process.env.SWIG_POLICY_ID!,
        network: (process.env.SWIG_NETWORK || 'devnet') as 'mainnet' | 'devnet',
        paymasterPubkey: process.env.SWIG_PAYMASTER_PUBKEY!,
      };

      console.log('Creating Swig wallet...');
      console.log(`Network: ${config.network}`);
      console.log(`Policy: ${config.policyId}`);

      const { data: wallet, error } = await client.wallet.create(config);

      if (error) {
        console.error('Failed to create wallet:', error.message);
        console.error('Error code:', error.code);
        process.exit(1);
      }

      console.log('\n=== Wallet Created ===');
      console.log(`Swig ID: ${wallet.swigId}`);
      console.log(`Address: ${wallet.swigAddress}`);
      console.log(`Transaction: ${wallet.signature}`);

      const cluster = config.network === 'mainnet' ? '' : '?cluster=devnet';
      console.log(`\nExplorer: https://explorer.solana.com/address/${wallet.swigAddress}${cluster}`);
    }

    main();
    ```
  </Tab>

  <Tab title="Legacy SDK">
    ```typescript theme={null}
    import { SwigClient, SwigError } from '@swig-wallet/developer';

    async function main() {
      const client = new SwigClient({
        apiKey: process.env.SWIG_API_KEY!,
        baseUrl: 'https://dashboard.onswig.com',
        retryOptions: { maxRetries: 3, retryDelay: 1000 },
      });

      const config = {
        policyId: process.env.SWIG_POLICY_ID!,
        network: (process.env.SWIG_NETWORK || 'devnet') as 'mainnet' | 'devnet',
        paymasterPubkey: process.env.SWIG_PAYMASTER_PUBKEY!,
      };

      console.log('Creating Swig wallet...');
      console.log(`Network: ${config.network}`);
      console.log(`Policy: ${config.policyId}`);

      try {
        const wallet = await client.createWallet(config);

        console.log('\n=== Wallet Created ===');
        console.log(`Swig ID: ${wallet.swigId}`);
        console.log(`Address: ${wallet.swigAddress}`);
        console.log(`Transaction: ${wallet.signature}`);

        const cluster = config.network === 'mainnet' ? '' : '?cluster=devnet';
        console.log(`\nExplorer: https://explorer.solana.com/address/${wallet.swigAddress}${cluster}`);
      } catch (error) {
        if (error instanceof SwigError) {
          console.error('Failed to create wallet:', error.message);
          console.error('Error code:', error.code);
          process.exit(1);
        }
        throw error;
      }
    }

    main();
    ```
  </Tab>
</Tabs>

## TypeScript Types

```typescript theme={null}
type WalletType =
  | 'ED25519'
  | 'ED25519_SESSION'
  | 'SECP256K1'
  | 'SECP256K1_SESSION'
  | 'SECP256R1'
  | 'SECP256R1_SESSION';

interface CreateWalletRequest {
  /** Policy ID to use for wallet creation */
  policyId: string;
  /** Optional signer ID to override or provide (alternative to walletAddress + walletType) */
  signerId?: string;
  /**
   * Wallet public key to use as the authority (alternative to signerId).
   * Must be provided together with walletType.
   */
  walletAddress?: string;
  /**
   * Authority type for the wallet (alternative to signerId).
   * Must be provided together with walletAddress.
   */
  walletType?: WalletType;
  /**
   * Maximum session duration in slots (only valid for session authority types).
   * String to safely handle bigint values.
   */
  maxDurationSlots?: string;
  /** Optional swig ID (generated if not provided) */
  swigId?: string;
  /** Network to use */
  network: 'mainnet' | 'devnet';
  /** Paymaster public key (optional — omit for self-send flow) */
  paymasterPubkey?: string;
}

/** Response when a paymaster is used */
interface CreateWalletPaymasterResponse {
  swigId: string;
  swigAddress: string;
  signature: string;
}

/** Response when no paymaster is provided */
interface CreateWalletTransactionResponse {
  swigId: string;
  swigAddress: string;
  /** Base58-encoded serialized VersionedTransaction (unsigned) */
  transaction: string;
}

type CreateWalletResponse =
  | CreateWalletPaymasterResponse
  | CreateWalletTransactionResponse;
```

### Legacy SDK Types

The legacy `@swig-wallet/developer` SDK provides higher-level types that automatically reconstruct the transaction:

```typescript theme={null}
import type { VersionedTransaction } from '@solana/web3.js';

/** Result when a paymaster was used */
interface WalletCreatePaymasterResult {
  swigId: string;
  swigAddress: string;
  signature: string;
}

/** Result when no paymaster was provided */
interface WalletCreateTransactionResult {
  swigId: string;
  swigAddress: string;
  /** Reconstructed VersionedTransaction ready for signing */
  transaction: VersionedTransaction;
}

type WalletCreateResult =
  | WalletCreatePaymasterResult
  | WalletCreateTransactionResult;
```

## Comparison: Portal API vs Direct SDK

| Feature                    | Portal API                | Direct SDK             |
| -------------------------- | ------------------------- | ---------------------- |
| Uses predefined policies   | Yes                       | No                     |
| Requires API key           | Yes                       | No                     |
| Paymaster sponsored        | Optional                  | Optional               |
| Self-send (no paymaster)   | Yes — returns unsigned tx | Yes — you build the tx |
| Full configuration control | Limited to policy         | Full                   |
| Best for                   | Backend services          | Client apps            |
| Keypair management         | Server-side               | Client-side            |

## Next Steps

After creating a wallet, you can:

* View the wallet on [Solana Explorer](https://explorer.solana.com)
* [Sign transactions](/tutorials/typescript/sign) using the wallet
* [Manage authorities](/tutorials/typescript/managing_authorities) to add more signers
