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

# Payy network integration

> Use Privy embedded wallets to authenticate users, sign messages, and send PUSD on Payy Network

[Payy Network](https://payy.network) is an EVM-compatible network with a native stablecoin (`PUSD`). Because it's EVM-compatible, you can use Privy's React SDK to authenticate users, create embedded wallets, and sign or send transactions on Payy with minimal configuration.

This recipe shows how to:

* Configure Privy for the Payy Network testnet
* Create an embedded wallet on Payy
* Sign messages, typed data, and transactions
* Send native PUSD transfers

## Prerequisites

* A Privy app configured in the [Privy Dashboard](https://dashboard.privy.io)
* A React app using `@privy-io/react-auth`
* Familiarity with [configuring EVM networks](/basics/react/advanced/configuring-evm-networks)

## Install dependencies

```bash theme={"system"}
npm install @privy-io/react-auth @privy-io/chains viem
```

## Step 1: Define the Payy chain

Use viem's `defineChain` to create a custom chain definition for Payy Network, then pass it to `addRpcUrlOverrideToChain` from `@privy-io/chains` so Privy routes requests through the Payy RPC endpoint.

```tsx theme={"system"}
import {defineChain} from 'viem';
import {addRpcUrlOverrideToChain} from '@privy-io/chains';

const payyTestnet = addRpcUrlOverrideToChain(
  defineChain({
    id: 7298,
    name: 'Payy Network Testnet',
    network: 'payy-testnet',
    nativeCurrency: {
      decimals: 18,
      name: 'Payy USD',
      symbol: 'PUSD'
    },
    rpcUrls: {
      default: {
        http: ['https://rpc.testnet.payy.network']
      }
    },
    blockExplorers: {
      default: {
        name: 'Payy Blockscout',
        url: 'https://blockscout.testnet.payy.network'
      }
    },
    testnet: true
  }),
  'https://rpc.testnet.payy.network'
);
```

## Step 2: Configure `PrivyProvider`

Set Payy as the default and only supported chain in your `PrivyProvider`. This constrains embedded wallets to operate exclusively on Payy Network.

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

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <PrivyProvider
      appId={import.meta.env.VITE_PRIVY_APP_ID!}
      config={{
        defaultChain: payyTestnet,
        supportedChains: [payyTestnet]
      }}
    >
      <App />
    </PrivyProvider>
  </StrictMode>
);
```

<Info>
  Setting `supportedChains` to only `[payyTestnet]` ensures Privy creates wallets targeting Payy by
  default. If your app supports multiple chains, add them to `supportedChains` alongside Payy.
</Info>

## Step 3: Authenticate users

Use [`usePrivy`](/basics/react/setup) to handle authentication. Users must be authenticated before creating or using a Payy wallet.

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

function Landing() {
  const {ready, authenticated, login, logout} = usePrivy();

  if (!ready) return <div>Loading...</div>;

  if (!authenticated) {
    return <button onClick={login}>Get started</button>;
  }

  return <button onClick={logout}>Logout</button>;
}
```

## Step 4: Create a Payy wallet

Because Payy is EVM-compatible, use Privy's standard [`useCreateWallet`](/wallets/wallets/create/create-a-wallet) hook. The wallet will target Payy Network based on your `PrivyProvider` configuration.

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

function CreatePayyWallet() {
  const {createWallet} = useCreateWallet({
    onSuccess: ({wallet}) => {
      console.log('Created Payy wallet', wallet.address);
    },
    onError: (error) => {
      console.error('Payy wallet creation failed', error);
    }
  });

  return <button onClick={() => createWallet({createAdditional: true})}>Create Payy wallet</button>;
}
```

## Step 5: Sign messages and transactions

All standard Privy signing hooks work on Payy. Pass the embedded wallet's `address` to target it for signing.

### Sign a message

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

const {signMessage} = useSignMessage();

const {signature} = await signMessage({message: 'Hello from Payy'}, {address: walletAddress});
```

### Sign typed data

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

const {signTypedData} = useSignTypedData();

const {signature} = await signTypedData(
  {
    domain: {
      name: 'My App',
      version: '1',
      chainId: 7298,
      verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
    },
    types: {
      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: 'Alice', wallet: walletAddress},
      to: {name: 'Bob', wallet: '0x0000000000000000000000000000000000000001'},
      contents: 'Hello from Payy!'
    }
  },
  {address: walletAddress}
);
```

### Send a transaction

Use [`useSendTransaction`](/wallets/using-wallets/ethereum/send-a-transaction) for standard EVM sends on Payy:

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

const {sendTransaction} = useSendTransaction();

const tx = await sendTransaction({to: recipientAddress, value: 0}, {address: walletAddress});
```

## Step 6: Send PUSD with manual transaction control

For tighter control over nonce, gas, and broadcasting, sign and broadcast transactions manually through the embedded wallet's Ethereum provider.

This approach is useful when you need custom fee handling, RPC routing through your own backend, or explicit nonce management for PUSD transfers.

```tsx theme={"system"}
import {useWallets} from '@privy-io/react-auth';
import {isAddress, parseUnits, toHex} from 'viem';

const PAYY_RPC_URL = 'https://rpc.testnet.payy.network';
const PUSD_DECIMALS = 18;

function SendPUSD() {
  const {wallets} = useWallets();

  const handleSend = async (to: string, amount: string) => {
    const wallet = wallets.find(
      (w) => w.walletClientType === 'privy' || w.walletClientType === 'privy_v2'
    );

    if (!wallet) throw new Error('No embedded wallet found');
    if (!isAddress(to)) throw new Error('Invalid address');

    const provider = await wallet.getEthereumProvider();
    const value = parseUnits(amount, PUSD_DECIMALS);
    const feePerGas = 1_000_000_000n;

    const nonceResponse = await fetch(PAYY_RPC_URL, {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({
        jsonrpc: '2.0',
        id: 1,
        method: 'eth_getTransactionCount',
        params: [wallet.address, 'pending']
      })
    });
    const {result: nonce} = await nonceResponse.json();

    const rawTx = await provider.request({
      method: 'eth_signTransaction',
      params: [
        {
          from: wallet.address,
          to,
          value: toHex(value),
          chainId: toHex(7298),
          gas: toHex(21000n),
          nonce: nonce || '0x0',
          type: toHex(2),
          maxFeePerGas: toHex(feePerGas),
          maxPriorityFeePerGas: toHex(feePerGas)
        }
      ]
    });

    const broadcastResponse = await fetch(PAYY_RPC_URL, {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({
        jsonrpc: '2.0',
        id: 1,
        method: 'eth_sendRawTransaction',
        params: [rawTx]
      })
    });
    const broadcastData = await broadcastResponse.json();

    if (broadcastData.error) {
      throw new Error(broadcastData.error.message || 'Broadcast failed');
    }

    return broadcastData.result;
  };

  return null;
}
```

<Warning>
  This example uses a fixed gas price of `1 gwei` for both `maxFeePerGas` and
  `maxPriorityFeePerGas`. In production, query the network for current gas prices or implement
  dynamic fee estimation.
</Warning>

## Step 7: Read PUSD balances

Query the Payy RPC endpoint directly for native PUSD balances:

```tsx theme={"system"}
const PAYY_RPC_URL = 'https://rpc.testnet.payy.network';

async function getBalance(address: string): Promise<bigint> {
  const response = await fetch(PAYY_RPC_URL, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
      jsonrpc: '2.0',
      id: 1,
      method: 'eth_getBalance',
      params: [address, 'latest']
    })
  });
  const {result} = await response.json();
  return BigInt(result);
}
```

## Choosing a transaction method

| Use case                     | Recommended approach                                                                                                                              |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Standard EVM sends           | [`useSendTransaction`](/wallets/using-wallets/ethereum/send-a-transaction) hook                                                                   |
| Custom nonce or fee handling | Manual `eth_signTransaction` + `eth_sendRawTransaction`                                                                                           |
| Backend-routed RPC           | Manual signing with your own RPC proxy                                                                                                            |
| Simple message/data signing  | [`useSignMessage`](/wallets/using-wallets/ethereum/sign-a-message) or [`useSignTypedData`](/wallets/using-wallets/ethereum/sign-typed-data) hooks |

## Payy Network reference

| Property        | Value                                     |
| --------------- | ----------------------------------------- |
| Chain name      | Payy Network Testnet                      |
| Chain ID        | `7298`                                    |
| RPC URL         | `https://rpc.testnet.payy.network`        |
| Block explorer  | `https://blockscout.testnet.payy.network` |
| Native currency | PUSD (18 decimals)                        |

## Related resources

<CardGroup cols={2}>
  <Card title="Configuring EVM networks" icon="link" href="/basics/react/advanced/configuring-evm-networks">
    Learn how to add custom chains to Privy
  </Card>

  <Card title="Reference implementation" icon="github" href="https://github.com/polybase/payy-network-privy-test">
    Full example repo for Payy + Privy integration
  </Card>
</CardGroup>
