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

# NodeJS (server-auth) legacy reference

> Compiled legacy documentation for @privy-io/server-auth. For new integrations, use @privy-io/node.

<Warning>
  The `@privy-io/server-auth` library is deprecated. This page compiles legacy documentation for
  existing customers who have not yet migrated. For new integrations, refer to the
  [`@privy-io/node`](/basics/nodeJS/installation) guide. For migration instructions, see the
  [migration guide](/basics/nodeJS/advanced/migrating-from-server-auth).
</Warning>

***

## Installation

<Info>Originally documented at [Installation](/basics/nodeJS-server-auth/installation).</Info>

In a backend JS environment, the `@privy-io/server-auth` library authorizes requests and manages your application from your server.

Install the library using your package manager of choice:

<CodeGroup>
  ```bash npm theme={"system"}
  npm install @privy-io/server-auth@latest
  ```

  ```bash pnpm theme={"system"}
  pnpm install @privy-io/server-auth@latest
  ```

  ```bash yarn theme={"system"}
  yarn add @privy-io/server-auth@latest
  ```
</CodeGroup>

***

## Setup

<Info>Originally documented at [Setup](/basics/nodeJS-server-auth/setup).</Info>

### Prerequisites

Before you begin:

* Get your [Privy app ID and app secret](/basics/get-started/dashboard/create-new-app) from the Privy Dashboard
* Have a minimum Node version of 18

### Instantiating the `PrivyClient`

Import the `PrivyClient` class and create an instance by passing the Privy app ID and app secret as parameters.

```tsx theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

const privy = new PrivyClient('insert-your-app-id', 'insert-your-app-secret');
```

***

## Quickstart

<Info>Originally documented at [Quickstart](/basics/nodeJS-server-auth/quickstart).</Info>

### 1. Creating a wallet

Create a wallet and save its `id` for future calls.

<Tabs>
  <Tab title="Ethereum">
    ```tsx theme={"system"}
    const {id, address, chainType} = await privy.walletApi.createWallet({chainType: 'ethereum'});
    ```
  </Tab>

  <Tab title="Solana">
    ```tsx theme={"system"}
    const {id, address, chainType} = await privy.walletApi.createWallet({chainType: 'solana'});
    ```
  </Tab>
</Tabs>

### 2. Signing a message

Sign a plaintext message with the wallet using the `signMessage` method.

<Tabs>
  <Tab title="Ethereum">
    ```tsx theme={"system"}
    const {signature, encoding} = await privy.walletApi.ethereum.signMessage({
      walletId: id,
      message: 'Hello Privy!'
    });
    ```
  </Tab>

  <Tab title="Solana">
    ```tsx theme={"system"}
    const {signature, encoding} = await privy.walletApi.solana.signMessage({
      walletId: 'insert-wallet-id',
      message: 'Hello world'
    });
    ```
  </Tab>
</Tabs>

### 3. Sending transactions

<Info>
  In order to send a transaction, your wallet must have some funds to pay for gas. Use a testnet
  [faucet](https://console.optimism.io/faucet) to test on a testnet like Base Sepolia.
</Info>

Use the `sendTransaction` method to populate missing network-related values, sign, broadcast, and return the transaction hash.

<Tabs>
  <Tab title="Ethereum">
    ```tsx theme={"system"}
    const data = await privy.walletApi.ethereum.sendTransaction({
      walletId: id,
      caip2: 'eip155:84532',
      transaction: {
        to: '0xyourRecipientAddress',
        value: '0x2386F26FC10000',
        chainId: 84532
      }
    });

    const {hash} = data;
    ```
  </Tab>

  <Tab title="Solana">
    ```tsx theme={"system"}
    const {hash} = await privy.walletApi.solana.signAndSendTransaction({
      walletId: wallet.id,
      caip2: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
      transaction: yourSolanaTransaction
    });
    ```
  </Tab>
</Tabs>

***

## Verify access tokens

<Info>
  Originally documented at [Access tokens](/authentication/user-authentication/access-tokens).
</Info>

Pass the user's access token as a `string` to the `PrivyClient`'s `verifyAuthToken` method:

```ts {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;
declare const authToken: string;

// `privy` refers to an instance of the `PrivyClient`
try {
  const verifiedClaims = await privy.verifyAuthToken(authToken);
} catch (error) {
  console.log(`Token verification failed with error ${error}.`);
}
```

To avoid a network request on each verification, pass the verification key directly:

```ts {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;
declare const authToken: string;

const verifiedClaims = await privy.verifyAuthToken(
  authToken,
  // Pass the verification key copied from the Dashboard as the second parameter
  'paste-your-verification-key-from-the-dashboard'
);
```

***

## Create or import a user

<Info>
  Originally documented at [Create or import a
  user](/user-management/migrating-users-to-privy/create-or-import-a-user).
</Info>

Use the `PrivyClient`'s `importUser` method to create or import a single user.

```tsx theme={"system"}
const user = await privy.importUser({
  linkedAccounts: [
    {
      type: 'email',
      address: 'batman@privy.io'
    }
  ],
  wallets: [{chainType: 'ethereum'}],
  customMetadata: {
    key: 'value'
  }
});
```

### Parameters

<ParamField body="linkedAccounts" type="LinkedAccount[]" required>
  An array of the user's linked accounts.
</ParamField>

<ParamField body="customMetadata" type="object">
  Custom metadata to associate with the user.
</ParamField>

<ParamField path="wallets" type="WalletCreateRequestType[]">
  An array of wallets to create for the user.

  <Expandable defaultOpen="true">
    <ParamField path="chainType" type="'ethereum' | 'solana' | 'stellar' | 'cosmos' | 'sui' | 'tron' | 'bitcoin-segwit' | 'near' | 'ton' | 'starknet' | 'aptos'" required>
      The chain type of the wallet to create.
    </ParamField>

    <ParamField path="additionalSigners" type="object[]">
      <Expandable defaultOpen="true">
        <ParamField path="signerId" type="string">
          The ID of the signer.
        </ParamField>

        <ParamField path="policyIds" type="string[]">
          List of policy IDs for the wallet.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField path="createSmartWallet" type="boolean">
      Set to `true` to create a smart wallet with the user's wallet as the signer. Ethereum only.
    </ParamField>
  </Expandable>
</ParamField>

***

## Query users

<Info>
  Originally documented at [Querying users](/user-management/users/managing-users/querying-users).
</Info>

### Query by identity token (recommended)

```typescript {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;

const user = await privy.getUser({idToken: 'your-idToken'});
```

### Query by Privy DID

```typescript {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;

const user = await privy.getUserById('did:privy:XXXXXX');
```

### Get all users

```typescript {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;

const users = await privy.getUsers();
```

### Query by account data

<AccordionGroup>
  <Accordion title="By email address">
    ```typescript theme={"system"}
    const user = await privy.getUserByEmail('user@gmail.com');
    ```
  </Accordion>

  <Accordion title="By phone number">
    ```typescript theme={"system"}
    const user = await privy.getUserByPhoneNumber('+1 555 555 5555');
    ```
  </Accordion>

  <Accordion title="By wallet address">
    ```typescript theme={"system"}
    const user = await privy.getUserByWalletAddress('0xABCDEFGHIJKL01234567895C5cAe8B9472c14328');
    ```
  </Accordion>

  <Accordion title="By custom auth ID">
    ```typescript theme={"system"}
    const user = await privy.getUserByCustomAuthId('123');
    ```
  </Accordion>

  <Accordion title="By Farcaster fid">
    ```typescript theme={"system"}
    const user = await privy.getUserByFarcasterId(1402);
    ```
  </Accordion>

  <Accordion title="By Twitter subject">
    ```typescript theme={"system"}
    const user = await privy.getUserByTwitterSubject('456');
    ```
  </Accordion>

  <Accordion title="By Twitter username">
    ```typescript theme={"system"}
    const user = await privy.getUserByTwitterUsername('batman');
    ```
  </Accordion>

  <Accordion title="By Discord username">
    ```typescript theme={"system"}
    const user = await privy.getUserByDiscordUsername('batman');
    ```
  </Accordion>

  <Accordion title="By Telegram user ID">
    ```typescript theme={"system"}
    const user = await privy.getUserByTelegramUserId('456');
    ```
  </Accordion>

  <Accordion title="By Telegram username">
    ```typescript theme={"system"}
    const user = await privy.getUserByTelegramUsername('batman');
    ```
  </Accordion>
</AccordionGroup>

***

## Delete a user

<Info>
  Originally documented at [Deleting users](/user-management/users/managing-users/deleting-users).
</Info>

Use the `PrivyClient`'s `deleteUser` method to delete a user. Pass the user's Privy DID as a `string`:

```ts {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;

await privy.deleteUser('did:privy:XXXXXX');
```

This method throws an error if the deletion fails (e.g. due to an invalid Privy DID).

***

## Custom metadata

<Info>Originally documented at [Custom metadata](/user-management/users/custom-metadata).</Info>

Use the `PrivyClient`'s `setCustomMetadata` method to set custom metadata for a user by their DID.

```typescript theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

const privy = new PrivyClient(process.env.PRIVY_APP_ID!, process.env.PRIVY_APP_SECRET!);

const user = await privy.setCustomMetadata('did:privy:XXXXXX', {username: 'name'});
```

<Tip>
  When using TypeScript, specify a type generic to enable type inference:

  ```tsx theme={"system"}
  const user = await privy.setCustomMetadata<{key1: string}>('did:privy:XXXXXX', customMetadata);
  ```
</Tip>

***

## Allowlist

<Info>Originally documented at [Allowlist](/user-management/users/managing-users/allowlist).</Info>

### Add to allowlist

Use the `inviteToAllowlist` method to add a user to your allowlist.

```tsx theme={"system"}
const allowlistEntry = await privy.inviteToAllowlist({
  type: 'email',
  value: 'batman@privy.io'
});
```

<ParamField path="type" type="'email' | 'phone' | 'wallet'" required>
  The type of account to add to the allowlist.
</ParamField>

<ParamField path="value" type="string" required>
  The identifier of the account to add to the allowlist.
</ParamField>

### Remove from allowlist

Use the `removeFromAllowlist` method to remove a user from your allowlist.

```tsx theme={"system"}
const removedAllowlistEntry = await privy.removeFromAllowlist({
  type: 'email',
  value: 'batman@privy.io'
});
```

### Get allowlist

Use the `getAllowlist` method to get your app's current allowlist.

```tsx theme={"system"}
const allowlist = await privy.getAllowlist();
```

***

## Test accounts

<Info>Originally documented at [Using test accounts](/recipes/using-test-accounts).</Info>

Enabling a test account registers a set of test credentials (a hardcoded email or phone number and OTP code); it does not create a Privy user record. The user record is created on the first successful login.

Use the `getTestAccessToken` method to get an access token for a test account.

```ts theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

const privy = new PrivyClient('insert-your-app-id', 'insert-your-app-secret');

// Uses the first test account by default
const {accessToken} = await privy.getTestAccessToken();

// Or, select a test account by email
const {accessToken: tokenByEmail} = await privy.getTestAccessToken({
  email: 'test-XXXX@privy.io'
});

// Or, select a test account by phone number
const {accessToken: tokenByPhone} = await privy.getTestAccessToken({
  phoneNumber: '+1 555 555 XXXX'
});
```

***

## Create a wallet

<Info>Originally documented at [Create a wallet](/wallets/wallets/create/create-a-wallet).</Info>

Use the `createWallet` method from the Privy client's `walletApi` class:

```ts {skip-check} theme={"system"}
export {};
type WalletApiCreateRequestType = import('@privy-io/server-auth').WalletApiCreateRequestType;
type WalletApiCreateResponseType = import('@privy-io/server-auth').WalletApiWalletResponseType;

createWallet: (input: WalletApiCreateRequestType) => Promise<WalletApiCreateResponseType>;
```

### Usage

```ts {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;

const {id, address, chainType} = await privy.walletApi.createWallet({
  chainType: 'ethereum',
  owner: {userId: 'privy:did:xxxxx'}
});
```

### Parameters

<ParamField type="'ethereum' | 'solana' | 'stellar' | 'cosmos' | 'sui' | 'tron' | 'bitcoin-segwit' | 'near' | 'ton' | 'starknet' | 'aptos'" path="chainType" required>
  Chain type of the wallet to create.
</ParamField>

<ParamField type="{'userId': string} | {'publicKey': string}" path="owner">
  The user ID or P-256 public key to set as the owner. Do not specify `ownerId` if providing this.
</ParamField>

<ParamField type="string" path="ownerId">
  The key quorum ID of the owner. Do not specify `owner` if providing this.
</ParamField>

<ParamField type="string[]" path="policyIds">
  List of policy IDs to enforce on the wallet.
</ParamField>

<ParamField type="string" path="idempotencyKey">
  [Idempotency key](/api-reference/idempotency-keys) to identify a unique request.
</ParamField>

<ParamField type="{'signerId': string}[]" path="additionalSigners">
  List of key quorum IDs allowed to approve transactions for the wallet.
</ParamField>

### Returns

<ResponseField type="string" name="id">
  Unique ID of the created wallet.
</ResponseField>

<ResponseField type="string" name="address">
  Address of the created wallet.
</ResponseField>

<ResponseField type="string" name="chainType">
  Chain type of the created wallet.
</ResponseField>

***

## Get wallet by ID

<Info>
  Originally documented at [Get wallet by ID](/wallets/wallets/get-a-wallet/get-wallet-by-id).
</Info>

```tsx theme={"system"}
getWallet: ({id}: {id: string}) => Promise<WalletApiWalletResponseType>;
```

### Usage

```tsx theme={"system"}
const wallet = await client.walletApi.getWallet({id: walletId});
```

### Parameters

<ParamField path="id" type="string">
  The ID of the wallet to get.
</ParamField>

### Returns

<ResponseField name="wallet" type="WalletApiWalletResponseType">
  <Expandable defaultOpen="true">
    <ResponseField name="id" type="string">
      Unique ID of the wallet.
    </ResponseField>

    <ResponseField name="address" type="string">
      Address of the wallet.
    </ResponseField>

    <ResponseField name="chainType" type="'ethereum' | 'solana'">
      Chain type of the wallet.
    </ResponseField>

    <ResponseField name="policyIds" type="string[]">
      List of policy IDs associated with the wallet.
    </ResponseField>

    <ResponseField type="string | null" name="ownerId">
      The key quorum ID of the owner.
    </ResponseField>

    <ResponseField type="{signerId: string}[]" name="additionalSigners">
      The key quorum IDs of additional signers.
    </ResponseField>

    <ResponseField name="createdAt" type="Date">
      The creation date of the wallet.
    </ResponseField>
  </Expandable>
</ResponseField>

***

## Get all wallets

<Info>
  Originally documented at [Get all wallets](/wallets/wallets/get-a-wallet/get-all-wallets).
</Info>

Use the Privy client's `walletApi.getWallets` method. This is a paginated query.

```tsx theme={"system"}
getWallets: ({cursor?: string, limit?: number, chainType?: 'ethereum' | 'solana'}) => Promise<{data: WalletApiWalletResponseType[], nextCursor?: string}>
```

### Usage

```tsx theme={"system"}
const wallets = [];
let nextCursor;

do {
  const result = await privy.walletApi.getWallets({chainType: 'ethereum', cursor: nextCursor});
  wallets.push(...result.data);
  nextCursor = result.nextCursor;
} while (nextCursor);
```

***

## Import a wallet (private key)

<Info>
  Originally documented at [Import a wallet (private
  key)](/wallets/wallets/import-a-wallet/private-key).
</Info>

Use the `importWallet` method from the Privy client's `walletApi` class.

<Tabs>
  <Tab title="EVM">
    The Privy client accepts a hex-encoded private key, with or without a `0x` prefix.

    ```ts theme={"system"}
    import {PrivyClient, WalletApiWalletResponseType} from '@privy-io/server-auth';

    const privy = new PrivyClient('your-app-id', 'your-app-secret');

    const wallet: WalletApiWalletResponseType = await privy.walletApi.importWallet({
      address: '<your-wallet-address>',
      chainType: 'ethereum',
      entropy: '<your-hex-encoded-wallet-private-key>',
      entropyType: 'private-key'
    });
    ```
  </Tab>

  <Tab title="Solana">
    The Privy client accepts a base58-encoded private key.

    ```ts theme={"system"}
    import {PrivyClient, WalletApiWalletResponseType} from '@privy-io/server-auth';

    const privy = new PrivyClient('your-app-id', 'your-app-secret');

    const wallet: WalletApiWalletResponseType = await privy.walletApi.importWallet({
      address: '<your-wallet-address>',
      chainType: 'solana',
      entropy: '<your-base58-encoded-wallet-private-key>',
      entropyType: 'private-key'
    });
    ```
  </Tab>
</Tabs>

***

## Import an HD wallet

<Info>Originally documented at [HD wallets](/wallets/wallets/import-a-wallet/hd-wallets).</Info>

Use the `importWallet` method from the Privy client's `walletApi` class.

<Tabs>
  <Tab title="Ethereum">
    ```ts theme={"system"}
    import {PrivyClient, WalletApiWalletResponseType} from '@privy-io/server-auth';

    const privy = new PrivyClient('your-app-id', 'your-app-secret');

    const wallet: WalletApiWalletResponseType = await privy.walletApi.importWallet({
      address: '<your-wallet-address>',
      chainType: 'ethereum',
      entropy: '<your-bip39-mnemonic>',
      entropyType: 'hd',
      index: 0
    });
    ```
  </Tab>

  <Tab title="Solana">
    ```ts theme={"system"}
    import {PrivyClient, WalletApiWalletResponseType} from '@privy-io/server-auth';

    const privy = new PrivyClient('your-app-id', 'your-app-secret');

    const wallet: WalletApiWalletResponseType = await privy.walletApi.importWallet({
      address: '<your-wallet-address>',
      chainType: 'solana',
      entropy: '<your-bip39-mnemonic>',
      entropyType: 'hd',
      index: 0
    });
    ```
  </Tab>
</Tabs>

***

## Sign a message (Ethereum)

<Info>
  Originally documented at [Sign a message](/wallets/using-wallets/ethereum/sign-a-message).
</Info>

Use the `signMessage` method on the Ethereum client.

```javascript theme={"system"}
signMessage: async ({walletId: string, message: string, idempotencyKey?: string}) => Promise<{signature: string, encoding: 'hex'}>
```

### Usage

```tsx theme={"system"}
const {signature, encoding} = await privy.walletApi.ethereum.signMessage({
  walletId: 'insert-wallet-id',
  message: 'Hello world'
});
```

### Parameters

<ParamField path="walletId" type="string" required>
  Unique ID of the wallet.
</ParamField>

<ParamField path="message" type="string | Uint8Array" required>
  The string or bytes to sign.
</ParamField>

<ParamField path="idempotencyKey" type="string">
  [Idempotency key](/api-reference/idempotency-keys).
</ParamField>

### Returns

<ResponseField name="signature" type="string">
  The signature produced by the wallet.
</ResponseField>

<ResponseField name="encoding" type="'hex'">
  The encoding format for the signature.
</ResponseField>

***

## Sign typed data (EIP-712)

<Info>
  Originally documented at [Sign typed data](/wallets/using-wallets/ethereum/sign-typed-data).
</Info>

Use the `signTypedData` method on the Ethereum client.

```javascript theme={"system"}
signTypedData: (input: {walletId: string, typedData: TypedData}) => Promise<{signature: string, encoding: 'hex'}>
```

### Usage

```tsx theme={"system"}
const {signature, encoding} = await privy.walletApi.ethereum.signTypedData({
  walletId: 'insert-wallet-id',
  typedData: {
    domain: {
      name: 'Ether Mail',
      version: '1',
      chainId: 1,
      verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
    },
    types: {
      EIP712Domain: [
        {name: 'name', type: 'string'},
        {name: 'version', type: 'string'},
        {name: 'chainId', type: 'uint256'},
        {name: 'verifyingContract', type: 'address'}
      ],
      Person: [
        {name: 'name', type: 'string'},
        {name: 'wallet', type: 'address'}
      ],
      Mail: [
        {name: 'from', type: 'Person'},
        {name: 'to', type: 'Person'},
        {name: 'contents', type: 'string'}
      ]
    },
    primaryType: 'Mail',
    message: {
      from: {name: 'Cow', wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826'},
      to: {name: 'Bob', wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB'},
      contents: 'Hello, Bob!'
    }
  }
});
```

***

## Sign a transaction (Ethereum)

<Info>
  Originally documented at [Sign a transaction](/wallets/using-wallets/ethereum/sign-a-transaction).
</Info>

Use the `signTransaction` method on the Ethereum client.

```js theme={"system"}
signTransaction: (input: EthereumSignTransactionInputType) => Promise<EthereumSignTransactionResponseType>
```

### Usage

```js theme={"system"}
const {signedTransaction, encoding} = await privy.walletApi.ethereum.signTransaction({
  walletId: 'insert-wallet-id',
  transaction: {
    to: '0xE3070d3e4309afA3bC9a6b057685743CF42da77C',
    value: '0x2386F26FC10000',
    chainId: 8453
  }
});
```

### Parameters

<ParamField path="walletId" type="string" required>
  The ID of the wallet.
</ParamField>

<ParamField path="transaction" type="EthereumTransactionType" required>
  The transaction to sign.
</ParamField>

### Returns

<ResponseField name="signedTransaction" type="string">
  The signed transaction.
</ResponseField>

<ResponseField name="encoding" type="'rlp'">
  The encoding format. Only `'rlp'` is supported.
</ResponseField>

***

## Sign a raw hash

<Info>
  Originally documented at [Sign a raw hash](/wallets/using-wallets/ethereum/sign-a-raw-hash).
</Info>

Use the `secp256k1Sign` method on the Ethereum client.

```javascript theme={"system"}
secp256k1Sign: async ({walletId: string, hash: string}) => Promise<{signature: string, encoding: 'hex'}>
```

### Usage

```tsx theme={"system"}
const {signature, encoding} = await privy.walletApi.ethereum.secp256k1Sign({
  walletId: 'insert-wallet-id',
  hash: '0x6503b027a625549f7be691646404f275f149d17a119a6804b855bac3030037aa'
});
```

### Parameters

<ParamField path="walletId" type="string" required>
  Unique ID of the wallet.
</ParamField>

<ParamField path="hash" type="hash" required>
  The hash to sign. Must start with `0x`.
</ParamField>

***

## Sign EIP-7702 authorization

<Info>
  Originally documented at [Sign EIP-7702
  authorization](/wallets/using-wallets/ethereum/sign-7702-authorization).
</Info>

Use the `sign7702Authorization` method on the Ethereum client.

```javascript theme={"system"}
sign7702Authorization: async ({walletId: string, contract: string, chainId: number, nonce?: number, idempotencyKey?: string}) => Promise<{chainId, contract, nonce, yParity, r, s}>
```

### Usage

```tsx theme={"system"}
const authorization = await privy.walletApi.ethereum.sign7702Authorization({
  walletId: 'insert-wallet-id',
  contract: '0x1234567890abcdef1234567890abcdef12345678',
  chainId: 1,
  nonce: 0
});
```

### Parameters

<ParamField path="walletId" type="string" required>
  Unique ID of the wallet.
</ParamField>

<ParamField path="contract" type="Hex" required>
  The smart contract address to delegate to.
</ParamField>

<ParamField path="chainId" type="number" required>
  The chain ID for the authorization.
</ParamField>

<ParamField path="nonce" type="number">
  The nonce for the authorization. Defaults to the current transaction count.
</ParamField>

<ParamField path="idempotencyKey" type="string">
  [Idempotency key](/api-reference/idempotency-keys).
</ParamField>

***

## Send a transaction (Ethereum)

<Info>
  Originally documented at [Send a transaction](/wallets/using-wallets/ethereum/send-a-transaction).
</Info>

Use the `sendTransaction` method on the Ethereum client.

```js theme={"system"}
sendTransaction: (input: EthereumSendTransactionInputType) => Promise<EthereumSendTransactionResponseType>
```

### Usage

```js theme={"system"}
const {hash, caip2} = await privy.walletApi.ethereum.sendTransaction({
  walletId: 'insert-wallet-id',
  caip2: 'eip155:8453',
  transaction: {
    to: '0xE3070d3e4309afA3bC9a6b057685743CF42da77C',
    value: '0x2386F26FC10000',
    chainId: 8453
  },
  sponsor: true
});
```

### Parameters

<ParamField path="walletId" type="string" required>
  The ID of the wallet.
</ParamField>

<ParamField path="caip2" type="`eip155:${number}`" required>
  The CAIP2 chain ID.
</ParamField>

<ParamField path="transaction" type="EthereumTransactionType" required>
  The transaction to send.
</ParamField>

<ParamField path="sponsor" type="boolean">
  Enable gas sponsorship. [Learn more.](/wallets/gas-and-asset-management/gas/overview)
</ParamField>

### Returns

<ResponseField name="hash" type="string">
  The transaction hash.
</ResponseField>

<ResponseField name="caip2" type="`eip155:${number}`">
  The CAIP2 chain ID.
</ResponseField>

***

## Web3 integrations (Ethereum)

<Info>
  Originally documented at [Interfacing with common
  libraries](/wallets/using-wallets/ethereum/web3-integrations).
</Info>

### viem

Use Privy's `createViemAccount` method to initialize a viem `Account` for an EVM wallet.

```tsx theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';
import {createViemAccount} from '@privy-io/server-auth/viem';

const privy = new PrivyClient(...);
const account = await createViemAccount({
  walletId: 'insert-wallet-id',
  address: 'insert-address',
  privy
});
```

From the returned `Account`, initialize a viem `WalletClient`:

```tsx theme={"system"}
import {createWalletClient, http, parseEther} from 'viem';
import {base} from 'viem/chains';

const client = createWalletClient({
  account,
  chain: base,
  transport: http()
});

const hash = await client.sendTransaction({
  to: '0x59D3eB21Dd06A211C89d1caBE252676e2F3F2218',
  value: parseEther('0.001')
});
```

### ethers

Use Privy's `createEthersSigner` method to initialize an ethers signer.

```typescript {skip-check} theme={"system"}
import {ethers, TransactionRequest} from 'ethers';
import {PrivyClient} from '@privy-io/server-auth';
import {createEthersSigner} from '@privy-io/server-auth/ethers';

const privyClient = new PrivyClient('insert-your-app-id', 'insert-your-app-secret');
const provider = new ethers.JsonRpcProvider('https://base.llamarpc.com');
const walletId = 'insert-wallet-id';
const wallet = await privyClient.walletApi.getWallet({id: walletId});

const signer = createEthersSigner({
  walletId,
  address: wallet.address,
  provider,
  privyClient: privyClient as any
});

const TO_ADDRESS = '0xE3070d3e4309afA3bC9a6b057685743CF42da77C';
const hash = await signer.sendTransaction({to: TO_ADDRESS, value: 100, chainId: 8453});
```

***

## Sign a message (Solana)

<Info>
  Originally documented at [Sign a message (Solana)](/wallets/using-wallets/solana/sign-a-message).
</Info>

Use the `signMessage` method on the Solana client.

### Usage

```tsx theme={"system"}
const {signature, encoding} = await privy.walletApi.solana.signMessage({
  walletId: 'insert-wallet-id',
  message: 'Hello world'
});
```

### Parameters

<ParamField path="walletId" type="string" required>
  Unique ID of the wallet.
</ParamField>

<ParamField path="message" type="string | Uint8Array" required>
  The string or bytes to sign.
</ParamField>

<ParamField path="idempotencyKey" type="string">
  [Idempotency key](/api-reference/idempotency-keys).
</ParamField>

***

## Sign a transaction (Solana)

<Info>
  Originally documented at [Sign a transaction
  (Solana)](/wallets/using-wallets/solana/sign-a-transaction).
</Info>

Use the `signTransaction` method on the Solana client.

```js theme={"system"}
signTransaction: (input: SolanaSignTransactionInputType) => Promise<SolanaSignTransactionResponseType>
```

### Usage

```js theme={"system"}
import {
  clusterApiUrl,
  Connection,
  LAMPORTS_PER_SOL,
  PublicKey,
  SystemProgram,
  Transaction,
  VersionedTransaction,
  TransactionMessage
} from '@solana/web3.js';

const walletPublicKey = new PublicKey(wallet.address);
const connection = new Connection(clusterApiUrl('devnet'));
const instruction = SystemProgram.transfer({
  fromPubkey: walletPublicKey,
  toPubkey: new PublicKey(address),
  lamports: value * LAMPORTS_PER_SOL
});

const {blockhash: recentBlockhash} = await connection.getLatestBlockhash();

const message = new TransactionMessage({
  payerKey: walletPublicKey,
  instructions: [instruction],
  recentBlockhash
});

const yourSolanaTransaction = new VersionedTransaction(message.compileToV0Message());

const {signedTransaction} = await privy.walletApi.solana.signTransaction({
  walletId: wallet.id,
  transaction: yourSolanaTransaction
});
```

### Parameters

<ParamField path="walletId" type="string" required>
  The ID of the wallet.
</ParamField>

<ParamField path="transaction" type="Transaction | VersionedTransaction" required>
  The transaction to sign.
</ParamField>

### Returns

<ResponseField name="signedTransaction" type="string">
  The signed transaction.
</ResponseField>

<ResponseField name="encoding" type="'base64'">
  The encoding format. Only `'base64'` is supported.
</ResponseField>

***

## Send a transaction (Solana)

<Info>
  Originally documented at [Send a transaction
  (Solana)](/wallets/using-wallets/solana/send-a-transaction).
</Info>

Use the `signAndSendTransaction` method on the Solana client.

```js theme={"system"}
signAndSendTransaction: (input: SolanaSignAndSendTransactionInputType) => Promise<SolanaSignAndSendTransactionResponseType>
```

### Usage

```js theme={"system"}
import {PublicKey, SystemProgram, VersionedTransaction, TransactionMessage} from '@solana/web3.js';

const walletPublicKey = new PublicKey(wallet.address);
const instruction = SystemProgram.transfer({
  fromPubkey: walletPublicKey,
  toPubkey: new PublicKey(recipientAddress),
  lamports: amount
});

const message = new TransactionMessage({
  payerKey: walletPublicKey,
  instructions: [instruction],
  recentBlockhash
});

const transaction = new VersionedTransaction(message.compileToV0Message());

const {hash} = await privy.walletApi.solana.signAndSendTransaction({
  walletId: 'insert-wallet-id',
  caip2: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
  transaction: transaction,
  sponsor: true
});
```

### Parameters

<ParamField path="walletId" type="string" required>
  The ID of the wallet.
</ParamField>

<ParamField path="caip2" type="string" required>
  The CAIP2 chain ID.
</ParamField>

<ParamField path="transaction" type="Transaction | VersionedTransaction" required>
  The transaction to sign and send.
</ParamField>

<ParamField path="sponsor" type="boolean">
  Enable gas sponsorship.
</ParamField>

### Returns

<ResponseField name="hash" type="string">
  The transaction hash.
</ResponseField>

<ResponseField name="caip2" type="string">
  The CAIP2 chain ID.
</ResponseField>

***

## Send SOL

<Info>Originally documented at [Sending a SOL transaction](/recipes/solana/send-sol).</Info>

```typescript {skip-check} theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

declare function createSOLTransferTransaction(...args: any[]): Promise<{transaction: any}>;

const privy = new PrivyClient(process.env.PRIVY_APP_ID!, process.env.PRIVY_APP_SECRET!);

const {transaction} = await createSOLTransferTransaction(
  'insert-wallet-address',
  'recipient-wallet-address',
  0.01 // amount in SOL
);

const response = await privy.walletApi.solana.signAndSendTransaction({
  walletId: 'insert-wallet-id',
  address: 'insert-wallet-address',
  caip2: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
  transaction: transaction
});
```

***

## Send SPL tokens

<Info>Originally documented at [Sending SPL tokens](/recipes/solana/send-spl-tokens).</Info>

```typescript {skip-check} theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

declare function createSPLTransferTransaction(...args: any[]): Promise<{transaction: any}>;

const privy = new PrivyClient(process.env.PRIVY_APP_ID!, process.env.PRIVY_APP_SECRET!);

const {transaction} = await createSPLTransferTransaction(
  'insert-wallet-address',
  'recipient-wallet-address',
  'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC mint address
  10 // Amount to send
);

const response = await privy.walletApi.solana.signAndSendTransaction({
  walletId: 'insert-wallet-id',
  address: 'insert-wallet-address',
  caip2: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
  transaction: transaction
});
```

***

## Send USDC (ERC-20)

<Info>Originally documented at [Sending USDC](/recipes/send-usdc).</Info>

```typescript theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

const privy = new PrivyClient(process.env.PRIVY_APP_ID!, process.env.PRIVY_APP_SECRET!);

const usdcContractAddress = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'; // on Base

const {hash} = await privy.walletApi.ethereum.sendTransaction({
  walletId: 'insert-wallet-id',
  caip2: 'eip155:8453',
  transaction: {
    to: usdcContractAddress,
    data: '0x...', // encoded transfer call
    chainId: 8453
  }
});
```

***

## Create a policy

<Info>Originally documented at [Create a policy](/controls/policies/create-a-policy).</Info>

Use the `PrivyClient`'s `createPolicy` method.

```tsx theme={"system"}
const policy = await privy.walletApi.createPolicy({
  name: 'Allowlist certain smart contracts',
  version: '1.0',
  chainType: 'ethereum',
  rules: [
    {
      name: 'Allowlist OUSD',
      method: 'eth_sendTransaction',
      action: 'ALLOW',
      conditions: [
        {
          fieldSource: 'ethereum_transaction',
          field: 'to',
          operator: 'eq',
          value: '0x20c0000000000000000000006a37da5c996874be'
        }
      ]
    }
  ],
  ownerId: 'fmfdj6yqly31huorjqzq38zc'
});
```

***

## Get a policy

<Info>Originally documented at [Get a policy](/controls/policies/get-a-policy).</Info>

Use the `PrivyClient`'s `getPolicy` method.

```tsx theme={"system"}
const policy = await privy.getPolicy({
  id: 'fmfdj6yqly31huorjqzq38zc'
});
```

***

## Update a policy

<Info>Originally documented at [Update a policy](/controls/policies/update-a-policy).</Info>

### Add a rule to a policy

```tsx theme={"system"}
const rule = await client.walletApi.addRuleToPolicy({
  policyId: 'fmfdj6yqly31huorjqzq38zc',
  name: 'Allowlist USDT',
  method: 'eth_sendTransaction',
  conditions: [
    {
      fieldSource: 'ethereum_transaction',
      field: 'to',
      operator: 'eq',
      value: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
    }
  ],
  action: 'ALLOW'
});
```

### Edit a rule in a policy

```tsx theme={"system"}
const rule = await client.walletApi.updateRuleInPolicy({
  policyId: 'fmfdj6yqly31huorjqzq38zc',
  ruleId: 'allow-list-usdt-18381838',
  name: 'Allowlist USDT',
  method: 'eth_sendTransaction',
  conditions: [
    {
      fieldSource: 'ethereum_transaction',
      field: 'to',
      operator: 'eq',
      value: '0xdAC17F958D2ee523a2206206994597C13D831ec7'
    }
  ],
  action: 'ALLOW'
});
```

### Delete a rule from a policy

```ts theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

const client = new PrivyClient('insert-app-id', 'insert-app-secret');

const rule = await client.walletApi.deleteRuleFromPolicy({
  policyId: 'fmfdj6yqly31huorjqzq38zc',
  ruleId: 'allow-list-usdt-18381838'
});
```

### Update a whole policy

```tsx theme={"system"}
const policy = await client.walletApi.updatePolicy({
  id: 'fmfdj6yqly31huorjqzq38zc',
  name: 'Transactions must be <= 5ETH',
  rules: [
    {
      name: 'Transactions must be <= 5ETH',
      method: 'eth_sendTransaction',
      action: 'ALLOW',
      conditions: [
        {
          fieldSource: 'ethereum_transaction',
          field: 'value',
          operator: 'lte',
          value: '0x2386F26FC10000'
        }
      ]
    }
  ]
});
```

***

## Request a user authorization key

<Info>
  Originally documented at [Using user owners &
  signers](/controls/authorization-keys/keys/create/user/request).
</Info>

### 1. Request a user key

Use the `generateUserSigner` method of the Privy client.

```ts theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

const privy = new PrivyClient('insert-your-app-id', 'insert-your-app-secret');

const {authorizationKey} = await privy.walletApi.generateUserSigner({
  userJwt: 'insert-user-jwt'
});
```

<ParamField path="userJwt" type="string" required>
  The user's JWT to authenticate the user.
</ParamField>

### 2. Update the Privy client to use the user's keypair

```ts {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;

privy.walletApi.updateAuthorizationKey('insert-user-authorization-key');
```

### 3. Execute requests with the user's authorization key

Once updated, the Privy client automatically signs requests made via `privy.walletApi.ethereum.*` and `privy.walletApi.solana.*` methods.

***

## Use signers

<Info>Originally documented at [Use signers](/wallets/using-wallets/signers/use-signers).</Info>

Use the Privy client's `getUser` method to get a user object. Pass the user's identity token:

```tsx theme={"system"}
const user = await client.getUser({identityToken});
```

Filter for wallets with signers:

```tsx theme={"system"}
const walletsWithSessionSigners = user.linkedAccounts.filter(
  (account): account is WalletWithMetadata =>
    account.type === 'wallet' && account.delegated === true
);
```

***

## Using user signers

<Info>
  Originally documented at [Using user signers](/wallets/using-wallets/user-signers/usage).
</Info>

Once you have created a wallet with a user signer, your application will:

1. Generate a SPKI-formatted ECDH P-256 keypair.
2. Request a time-bound session key from [`/v1/wallets/authenticate`](/api-reference/wallets/authenticate) using the user's JWT and the public key.
3. Send a transaction to the Wallet API, signed with the session key.

### Generate an ECDH P-256 keypair

```typescript theme={"system"}
import * as crypto from 'crypto';

async function generateEcdhP256KeyPair(): Promise<{
  privateKey: crypto.webcrypto.CryptoKey;
  recipientPublicKey: string;
}> {
  const keyPair = await crypto.subtle.generateKey({name: 'ECDH', namedCurve: 'P-256'}, true, [
    'deriveBits'
  ]);

  const privateKey = keyPair.privateKey;
  const publicKeyInSpkiFormat = await crypto.subtle.exportKey('spki', keyPair.publicKey);
  const recipientPublicKey = Buffer.from(publicKeyInSpkiFormat).toString('base64');

  return {privateKey, recipientPublicKey};
}
```

### POST /v1/wallets/authenticate

```ts {skip-check} theme={"system"}
export {};
declare function generateEcdhP256KeyPair(): Promise<{
  privateKey: CryptoKey;
  recipientPublicKey: string;
}>;

async function authenticateUserWallet() {
  const jwt = 'your-user-jwt';
  const appId = 'your-app-id';
  const appSecret = 'your-app-secret';

  const {recipientPublicKey} = await generateEcdhP256KeyPair();

  const basicAuth = Buffer.from(`${appId}:${appSecret}`).toString('base64');
  const response = await fetch(`https://api.privy.io/v1/wallets/authenticate`, {
    method: 'POST',
    headers: {
      Authorization: `Basic ${basicAuth}`,
      'Content-Type': 'application/json',
      'privy-app-id': appId
    },
    body: JSON.stringify({
      user_jwt: jwt,
      encryption_type: 'HPKE',
      recipient_public_key: recipientPublicKey
    })
  });

  return await response.json();
}
```

### Decrypt the response

```ts {skip-check} theme={"system"}
import {CipherSuite, DhkemP256HkdfSha256, HkdfSha256} from '@hpke/core';
import {Chacha20Poly1305} from '@hpke/chacha20poly1305';

async function decryptEncapsulatedKey(
  encrypted_authorization_key: any,
  privateKey: CryptoKey
): Promise<string> {
  const {encapsulated_key: encapsulatedKey, ciphertext} = encrypted_authorization_key;

  const suite = new CipherSuite({
    kem: new DhkemP256HkdfSha256(),
    kdf: new HkdfSha256(),
    aead: new Chacha20Poly1305()
  });

  const context = await suite.createRecipientContext({
    recipientKey: privateKey,
    enc: Buffer.from(encapsulatedKey, 'base64')
  });

  const decrypted = await context.open(Buffer.from(ciphertext, 'base64'));
  return Buffer.from(decrypted).toString('utf8');
}
```

### Send a transaction using the decrypted key

```ts {skip-check} theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

declare function authenticateUserWallet(): Promise<any>;
declare function decryptEncapsulatedKey(key: any, privateKey: CryptoKey): Promise<string>;
declare const privateKey: CryptoKey;

const resp = await authenticateUserWallet();
const {encrypted_authorization_key, wallets} = resp;
const decryptedKey = await decryptEncapsulatedKey(encrypted_authorization_key, privateKey);
const walletId = wallets[0].id;

const client = new PrivyClient('insert-your-app-id', 'insert-your-app-secret', {
  walletApi: {
    authorizationPrivateKey: decryptedKey
  }
});

const res = await client.walletApi.ethereum.signMessage({
  walletId: walletId,
  message: 'Hello world'
});
```

***

## Sponsor gas on Ethereum

<Info>
  Originally documented at [Sponsoring transactions on
  Ethereum](/wallets/gas-and-asset-management/gas/ethereum).
</Info>

### 0. Install dependencies

```sh theme={"system"}
npm i @privy-io/server-auth permissionless viem
```

### 1. Create a wallet

```ts theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

const privy = new PrivyClient('your privy app id', 'your privy app secret');

const {
  id: walletId,
  address,
  chainType
} = await privy.walletApi.createWallet({chainType: 'ethereum'});
```

### 2. Get a viem `LocalAccount`

```tsx theme={"system"}
import {createViemAccount} from '@privy-io/server-auth/viem';

const serverWalletAccount = await createViemAccount({walletId, address, privy});
```

### 3. Create a smart wallet

```tsx theme={"system"}
import {toKernelSmartAccount} from 'permissionless/accounts';
import {entryPoint07Address} from 'viem/account-abstraction';

const kernelSmartAccount = await toKernelSmartAccount({
  client: publicClient,
  entryPoint: {address: entryPoint07Address, version: '0.7'},
  owner: serverWalletAccount
});
```

### 4. Create a smart account client

```tsx theme={"system"}
import {createSmartAccountClient} from 'permissionless';
import {createPublicClient, http} from 'viem';

const smartAccountClient = createSmartAccountClient({
  account: kernelSmartAccount,
  chain: sepolia,
  paymaster: paymasterClient,
  bundlerTransport: http(bundlerUrl),
  userOperation: {
    estimateFeesPerGas: async () => (await paymasterClient.getUserOperationGasPrice()).fast
  }
});
```

***

## Fetch a transaction

<Info>
  Originally documented at [Fetch transaction via
  API](/wallets/gas-and-asset-management/assets/fetch-a-transaction).
</Info>

Use the `getTransaction` method from the Privy client.

```typescript theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

const privy = new PrivyClient('insert-your-app-id', 'insert-your-app-secret');

const transaction = await privy.walletApi.getTransaction({
  id: 'insert-transaction-id'
});
```

### Parameters

<ParamField path="id" type="string" required>
  ID of the transaction to fetch.
</ParamField>

***

## Pregenerate wallets

<Info>Originally documented at [Pregenerating wallets](/recipes/pregenerate-wallets).</Info>

To pregenerate wallets for a new user, use the `importUser` method.

```tsx theme={"system"}
const privy = new PrivyClient('your-app-id', 'your-app-secret');

const user = await privy.importUser({
  linkedAccounts: [
    {
      type: 'email',
      address: 'batman@privy.io'
    }
  ],
  wallets: [
    {
      chainType: 'ethereum',
      walletIndex: 0,
      additionalSigners: [
        {
          signerId: '<signer-id>',
          overridePolicyIds: ['<policy-id>']
        }
      ],
      policyIds: ['<policy-id>']
    },
    {
      chainType: 'solana',
      walletIndex: 0,
      additionalSigners: [
        {
          signerId: '<signer-id>',
          overridePolicyIds: ['<policy-id>']
        }
      ],
      policyIds: []
    }
  ],
  createDirectSigner: true
});
```

***

## Server-side user wallets

<Info>
  Originally documented at [Server-side user wallets](/recipes/wallets/server-side-user-wallets).
</Info>

Use the Privy client's `importUser` method to create a user.

```ts {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;

const user = await privy.importUser({
  linkedAccounts: [
    {
      type: 'custom_auth',
      customUserId: 'insert-user-id-from-authentication-provider'
    }
  ]
});

const id = user.id;
```

***

## Verify access token (optimizing)

<Info>Originally documented at [Optimize your setup](/recipes/dashboard/optimizing).</Info>

To avoid a network call when verifying access tokens, pass the verification key directly:

```ts theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';

const privy = new PrivyClient('your-privy-app-id', 'your-privy-app-secret');

const verifiedClaims = await privy.verifyAuthToken(
  '$AUTH_TOKEN',
  'paste-your-verification-key-from-the-dashboard'
);
```

***

## Idempotency keys

<Info>Originally documented at [Idempotency keys](/api-reference/idempotency-keys).</Info>

```ts theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';
import {v4 as uuidv4} from 'uuid';

const client = new PrivyClient('$PRIVY_APP_ID', '$PRIVY_APP_SECRET');

const idempotencyKey = uuidv4();

const res = await client.walletApi.ethereum.sendTransaction({
  walletId: '$WALLET_ID',
  idempotencyKey,
  caip2: 'eip155:8453',
  transaction: {
    to: '0xE3070d3e4309afA3bC9a6b057685743CF42da77C',
    value: '0x2386F26FC10000',
    chainId: 8453
  }
});
```

***

## tRPC integration

<Info>Originally documented at [Integrating with tRPC](/recipes/trpc).</Info>

```ts theme={"system"}
import * as trpc from '@trpc/server';
import {inferAsyncReturnType} from '@trpc/server';
import * as trpcNext from '@trpc/server/adapters/next';

import {PrivyClient, AuthTokenClaims} from '@privy-io/server-auth';

const privy = new PrivyClient(
  process.env.NEXT_PUBLIC_PRIVY_APP_ID || '',
  process.env.PRIVY_APP_SECRET || ''
);

export async function createContext({req, res}: trpcNext.CreateNextContextOptions) {
  const authToken = req.headers.authorization.replace('Bearer ', '');
  let userClaim: AuthTokenClaims | undefined = undefined;

  if (authToken) {
    try {
      userClaim = await privy.verifyAuthToken(authToken);
    } catch (_) {
      // Expected error for unauthenticated procedures
    }
  }
  return {userClaim};
}
export type Context = inferAsyncReturnType<typeof createContext>;
```

***

## Speeding up transactions

<Info>
  Originally documented at [Speeding up transactions on EVM
  chains](/recipes/speeding-up-transactions).
</Info>

Send a replacement transaction using the same nonce:

```ts {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;
declare const payload: any;

const {hash, caip2} = await privy.walletApi.ethereum.sendTransaction({
  walletId: payload.wallet_id,
  caip2: payload.caip2,
  transaction: {
    to: payload.transaction_request.to,
    value: payload.transaction_request.value,
    data: payload.transaction_request.data,
    nonce: payload.transaction_request.nonce
  }
});
```

***

## Telegram bot

<Info>Originally documented at [Building a Telegram trading bot](/recipes/telegram-bot).</Info>

### Initialize the client

```ts theme={"system"}
const TelegramBot = require('node-telegram-bot-api');
const {PrivyClient} = require('@privy-io/server-auth');

const token = 'YOUR_TELEGRAM_BOT_TOKEN';
const bot = new TelegramBot(token, {polling: true});
const privy = new PrivyClient('insert-app-id', 'insert-app-secret');
```

### Send a transaction on command

```ts {skip-check} theme={"system"}
import type {WalletWithMetadata} from '@privy-io/server-auth';

declare const bot: any;
declare const privy: import('@privy-io/server-auth').PrivyClient;
declare function getTransactionDetailsFromMsg(msg: any): any;

bot.onText(/\/transact/, async (msg: any) => {
  const transaction = getTransactionDetailsFromMsg(msg);
  const user = await privy.getUserByTelegramUserId(msg.from.id);

  const wallet = user?.linkedAccounts.find(
    (account): account is WalletWithMetadata =>
      account.type === 'wallet' && account.walletClientType === 'privy'
  );
  const walletId = wallet?.id;

  if (!walletId) throw new Error('Cannot determine wallet ID for user');

  await privy.walletApi.solana.signAndSendTransaction({walletId, ...transaction});
});
```

### Bot-first wallet creation

```ts {skip-check} theme={"system"}
export {};
declare const bot: any;
declare const privy: import('@privy-io/server-auth').PrivyClient;

bot.onText(/\/start/, async (msg: any) => {
  const telegramUserId = msg.from.id;
  const privyUser = await privy.importUser({
    linkedAccounts: [{type: 'telegram', telegramUserId}]
  });

  const wallet = await privy.walletApi.createWallet({
    chainType: 'solana',
    owner: {userId: privyUser.id},
    additionalSigners: [{signerId: 'id-of-authorization-key-from-dashboard'}]
  });
});
```

***

## Flashblocks

<Info>Originally documented at [Using Flashblocks with Privy](/recipes/evm/flashblocks).</Info>

Sign a transaction with the `@privy-io/server-auth` SDK and broadcast to your custom Flashblocks RPC URL:

```ts {skip-check} theme={"system"}
export {};
declare const privy: import('@privy-io/server-auth').PrivyClient;

const {signedTransaction} = await privy.walletApi.ethereum.signTransaction({
  walletId: 'insert-wallet-id',
  transaction: {
    to: '0xE3070d3e4309afA3bC9a6b057685743CF42da77C',
    value: '0x2386F26FC10000',
    chainId: 8453
  }
});
```

***

## Aave integration

<Info>Originally documented at [Integrating Aave with Privy](/recipes/yield/aave-guide).</Info>

### Installation

```bash theme={"system"}
npm install @aave/client@latest @privy-io/server-auth@latest
```

### Setup

```tsx theme={"system"}
import {PrivyClient} from '@privy-io/server-auth';
import {AaveClient} from '@aave/client';

const privyClient = new PrivyClient('insert-your-app-id', 'insert-your-app-secret');

const walletId = 'privy-wallet-id';
const walletAddress = 'privy-wallet-address';

const aaveClient = AaveClient.create();
```

***

## Signing utility functions

<Info>
  Originally documented at [Signing with utility
  functions](/controls/authorization-keys/using-owners/sign/utility-functions).
</Info>

### Format a request for an authorization signature

```ts theme={"system"}
import {formatRequestForAuthorizationSignature} from '@privy-io/server-auth/wallet-api';

const input = {
  version: 1,
  url: 'https://api.privy.io/v1/wallets/<insert-wallet-id>/rpc',
  method: 'POST',
  headers: {
    'privy-app-id': '<insert-app-id>'
  },
  body: {
    method: 'personal_sign',
    params: {
      message: 'Hello from Privy!',
      encoding: 'utf-8'
    }
  }
} as const;
const serializedPayload = formatRequestForAuthorizationSignature({input});
```
