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

# Web3 Integration

> Integrate wallets and typed data signing with Rise B2B API using the SDK

Rise B2B API is designed for seamless integration with Web3 wallets and smart contract standards. This guide covers wallet integration and EIP-712 typed data signing for secure blockchain operations using the official Rise SDK.

<CardGroup cols={2}>
  <Card title="Secure" icon="shield">
    EIP-712 typed data signing for enhanced security
  </Card>

  <Card title="Efficient" icon="bolt">
    Gas-optimized transactions with structured data
  </Card>

  <Card title="Compatible" icon="globe">
    Works with MetaMask, WalletConnect, and other wallets
  </Card>

  <Card title="User-Friendly" icon="mobile-notch">
    Human-readable messages in wallet interfaces
  </Card>
</CardGroup>

## SDK Installation

First, install the Rise SDK:

```bash theme={null}
npm install @riseworks/riseworks-sdk
# Or: yarn add @riseworks/riseworks-sdk
# Or: pnpm add @riseworks/riseworks-sdk
```

## Supported Wallets

Rise B2B API supports all major Web3 wallets:

<CardGroup cols={3}>
  <Card title="MetaMask" icon="wallet">
    Most popular Ethereum wallet
  </Card>

  <Card title="WalletConnect" icon="link">
    Multi-wallet connection protocol
  </Card>

  <Card title="Coinbase Wallet" icon="credit-card">
    Coinbase's Web3 wallet
  </Card>

  <Card title="Rainbow" icon="droplet">
    Beautiful mobile wallet
  </Card>

  <Card title="Trust Wallet" icon="shield">
    Binance's mobile wallet
  </Card>

  <Card title="Any EIP-1193" icon="circle-check">
    Compatible with any EIP-1193 wallet
  </Card>
</CardGroup>

## Getting Started

### Initialize the SDK

```javascript theme={null}
const { RiseApiClient } = require('@riseworks/riseworks-sdk');
require('dotenv').config();

// Initialize with Rise ID and private key (recommended for Web3 operations)
const client = new RiseApiClient({
  environment: 'prod',
  riseIdAuth: {
    riseId: process.env.RISE_ID,
    privateKey: process.env.PRIVATE_KEY
  }
});

// Alternative: Initialize with JWT token
const jwtClient = new RiseApiClient({
  environment: 'prod',
  jwtToken: process.env.JWT_TOKEN
});
```

## EIP-712 Typed Data Signing

Many Rise operations (payments, team management, invites) require **EIP-712 typed data signing** for enhanced security and gas efficiency. The SDK handles this automatically for most operations.

### What is EIP-712 Typed Data?

EIP-712 is a standard for typed data signing that provides:

* **Human-readable messages** in wallet interfaces
* **Type safety** to prevent signature replay attacks
* **Gas efficiency** compared to raw message signing
* **Better security** through structured data validation

### Automatic Typed Data Signing

The SDK automatically handles typed data signing for most operations:

```javascript theme={null}
// Automatic payment with signing
const payment = await client.payments.sendPayment({
  from: 'te-abc123def456',
  to: [
    {
      to: 'us-xyz789abc123',
      amount_cents: 10000,
      currency_symbol: 'USD',
      invoice_description: 'Salary payment for January 2024'
    }
  ],
  pay_now: true,
  network: 'arbitrum'
});

console.log('Payment executed:', payment.data);
```

**What the SDK does automatically:**

1. **Generates typed data** for EIP-712 signing
2. **Signs the typed data** using your private key
3. **Submits the signed transaction** to the Rise API
4. **Handles authentication** and JWT token management
5. **Provides error handling** and retry logic

### Manual Typed Data Signing

For more control over the signing process, you can handle the signing manually:

```javascript theme={null}
// Initialize SDK (private key not required for manual flow)
const client = new RiseApiClient({
  environment: 'prod',
  jwtToken: process.env.JWT_TOKEN  // JWT token is sufficient for manual flow
});

// Step 1: Get typed data for signing
const typedDataResponse = await client.payments.getPaymentTypedData({
  from: 'te-abc123def456',
  to: [
    {
      to: 'us-xyz789abc123',
      amount_cents: 10000,
      currency_symbol: 'USD',
      invoice_description: 'Salary payment for January 2024'
    }
  ],
  pay_now: true,
  network: 'arbitrum'
});

console.log('Typed data received:', typedDataResponse.data);

// Step 2: Sign the typed data (if you want custom signing logic)
const { ethers } = require('ethers');
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY);
const signature = await wallet.signTypedData(
  typedDataResponse.data.domain,
  typedDataResponse.data.types,
  typedDataResponse.data.typed_data
);

// Step 3: Execute with signature
const executeResponse = await client.payments.executePaymentWithSignedData({
  from: 'te-abc123def456',
  to: [
    {
      to: 'us-xyz789abc123',
      amount_cents: 10000,
      currency_symbol: 'USD',
      invoice_description: 'Salary payment for January 2024'
    }
  ],
  pay_now: true,
  network: 'arbitrum',
  signer: wallet.address,
  typed_data: typedDataResponse.data.typed_data,
  signature: signature
});

console.log('Payment executed:', executeResponse.data);
```

**What the manual flow provides:**

1. **Custom signing logic** - You control when and how to sign
2. **Typed data inspection** - You can examine the data before signing
3. **Signature verification** - You can verify the signature before submission
4. **Error handling control** - Custom error handling for each step
5. **Integration flexibility** - Easier integration with existing signing workflows

## When to Use Typed Data Signing

Typed data signing is required for the following Rise operations:

<CardGroup cols={2}>
  <Card title="Payments" icon="credit-card">
    Creating and executing payments
  </Card>

  <Card title="Team Management" icon="users">
    Adding/removing team members
  </Card>

  <Card title="Invites" icon="envelope">
    Sending team invitations
  </Card>

  <Card title="Settings" icon="bars">
    Updating team settings
  </Card>

  <Card title="Permissions" icon="lock">
    Managing role permissions
  </Card>

  <Card title="Withdrawals" icon="arrow-up">
    Processing withdrawals
  </Card>
</CardGroup>

## Complete Integration Example

Here's a complete example showing how to integrate Web3 operations with Rise API using the SDK:

```javascript theme={null}
const { RiseApiClient } = require('@riseworks/riseworks-sdk');
require('dotenv').config();

class RiseWeb3Integration {
  constructor() {
    this.client = new RiseApiClient({
      environment: 'prod',
      riseIdAuth: {
        riseId: process.env.RISE_ID,
        privateKey: process.env.PRIVATE_KEY
      }
    });
  }

  // Automatic payment with signing
  async createPayment(teamNanoid, recipients, payNow = true) {
    try {
      const payment = await this.client.payments.sendPayment({
        from: teamNanoid,
        to: recipients,
        pay_now: payNow,
        network: 'arbitrum'
      });

      console.log('Payment executed:', payment.data);
      return payment.data;
    } catch (error) {
      console.error('Payment failed:', error.message);
      throw error;
    }
  }

  // Automatic manager invite with signing
  async createManagerInvite(teamNanoid, emails, role) {
    try {
      const managerInvite = await this.client.invites.sendManagerInvite({
        emails: emails,
        role: role,
        nanoid: teamNanoid
      });

      console.log('Manager invite sent:', managerInvite.data);
      return managerInvite.data;
    } catch (error) {
      console.error('Manager invite failed:', error.message);
      throw error;
    }
  }

  // Automatic withdrawal with signing
  async processWithdrawal(accountNanoid, amount, currency) {
    try {
      const withdrawal = await this.client.withdraw.sendWithdraw(
        { account_nanoid: accountNanoid },
        {
          amount_cents: amount,
          currency_symbol: currency
        }
      );

      console.log('Withdrawal processed:', withdrawal.data);
      return withdrawal.data;
    } catch (error) {
      console.error('Withdrawal failed:', error.message);
      throw error;
    }
  }

  // Manual payment with custom signing
  async createManualPayment(teamNanoid, recipients, payNow = true) {
    try {
      // Step 1: Get typed data
      const typedDataResponse = await this.client.payments.getPaymentTypedData({
        from: teamNanoid,
        to: recipients,
        pay_now: payNow,
        network: 'arbitrum'
      });

      console.log('Typed data received:', typedDataResponse.data);

      // Step 2: Sign the typed data
      const { ethers } = require('ethers');
      const wallet = new ethers.Wallet(process.env.PRIVATE_KEY);
      const signature = await wallet.signTypedData(
        typedDataResponse.data.domain,
        typedDataResponse.data.types,
        typedDataResponse.data.typed_data
      );

      // Step 3: Execute with signature
      const executeResponse = await this.client.payments.executePaymentWithSignedData({
        from: teamNanoid,
        to: recipients,
        pay_now: payNow,
        network: 'arbitrum',
        signer: wallet.address,
        typed_data: typedDataResponse.data.typed_data,
        signature: signature
      });

      console.log('Manual payment executed:', executeResponse.data);
      return executeResponse.data;
    } catch (error) {
      console.error('Manual payment failed:', error.message);
      throw error;
    }
  }

  // Generic typed data signing utility
  async signTypedData(typedData, privateKey) {
    const { ethers } = require('ethers');
    const wallet = new ethers.Wallet(privateKey);

    const signature = await wallet.signTypedData(
      typedData.domain,
      typedData.types,
      typedData.typed_data
    );

    return signature;
  }
}

// Usage example
const web3Integration = new RiseWeb3Integration();

async function main() {
  try {
    // Example: Create automatic payment
    const recipients = [
      {
        to: 'us-jRxg2LRL54DJ',
        amount_cents: 300,
        currency_symbol: 'USD',
        invoice_description: 'Salary payment'
      },
      {
        to: 'us-d6JHBF2kuZjE',
        amount_cents: 700,
        currency_symbol: 'USD',
        invoice_description: 'Bonus payment'
      }
    ];

    const payment = await web3Integration.createPayment(
      'te-abc123def456',
      recipients,
      true // pay immediately
    );

    // Example: Create manager invite
    const managerInvite = await web3Integration.createManagerInvite(
      'te-abc123def456',
      ['admin@company.com'],
      'team_admin'
    );

    // Example: Process withdrawal
    const withdrawal = await web3Integration.processWithdrawal(
      'ac-xyz789abc123',
      5000, // $50.00
      'USD'
    );

    // Example: Manual payment with custom signing
    const manualPayment = await web3Integration.createManualPayment(
      'te-abc123def456',
      recipients,
      true
    );

  } catch (error) {
    console.error('Web3 integration error:', error.message);
  }
}

// Run the example
if (require.main === module) {
  main();
}
```

## Security Best Practices

<CardGroup cols={2}>
  <Card title="Private Keys" icon="shield">
    * Never store private keys in client-side code
    * Use environment variables for server-side operations
    * Consider hardware wallets for high-value transactions
  </Card>

  <Card title="Verification" icon="circle-check">
    * Always verify signatures before submitting
    * Check contract addresses and chain IDs
    * Validate typed data structure
  </Card>

  <Card title="Environment" icon="lock">
    * Use HTTPS for all API communications
    * Implement proper error handling
    * Log security events for auditing
  </Card>

  <Card title="Timing" icon="clock">
    * Respect expiration times in typed data
    * Implement retry logic for failed transactions
    * Monitor transaction status
  </Card>
</CardGroup>

## Error Handling

The SDK provides comprehensive error handling:

```javascript theme={null}
try {
  const payment = await client.payments.sendPayment({
    from: 'te-abc123def456',
    to: [
      {
        to: 'us-xyz789abc123',
        amount_cents: 10000,
        currency_symbol: 'USD',
        invoice_description: 'Payment'
      }
    ],
    pay_now: true,
    network: 'arbitrum'
  });
  
  console.log('Payment successful:', payment.data);
} catch (error) {
  console.error('Web3 operation error:', error.message);
  
  // Handle specific error types based on message content
  if (error.message.includes('insufficient balance')) {
    console.error('Insufficient funds for payment');
  } else if (error.message.includes('invalid signature')) {
    console.error('Signature verification failed');
  } else if (error.message.includes('expired')) {
    console.error('Typed data has expired');
  } else if (error.message.includes('wrong network')) {
    console.error('Incorrect network connected');
  } else {
    console.error('Web3 operation failed:', error.message);
  }
}
```

Common Web3 errors:

| Error Message          | Description                      | Solution                             |
| ---------------------- | -------------------------------- | ------------------------------------ |
| `insufficient balance` | Not enough funds for transaction | Ensure wallet has sufficient balance |
| `invalid signature`    | Signature verification failed    | Ensure the correct wallet is signing |
| `expired`              | Typed data has expired           | Request fresh typed data from API    |
| `wrong network`        | Incorrect network connected      | Switch to the correct network        |
| `invalid typed data`   | Invalid typed data structure     | Check typed data format              |

## Testing Web3 Integration

For testing, use the staging environment:

```javascript theme={null}
// Staging configuration for testing
const stagingClient = new RiseApiClient({
  environment: 'stg',
  riseIdAuth: {
    riseId: process.env.RISE_ID,
    privateKey: process.env.PRIVATE_KEY
  }
});

// Test Web3 operations
const testPayment = await stagingClient.payments.sendPayment({
  from: 'te-test123',
  to: [
    {
      to: 'us-test456',
      amount_cents: 100,
      currency_symbol: 'USD',
      invoice_description: 'Test payment'
    }
  ],
  pay_now: true,
  network: 'arbitrum'
});

console.log('Test payment executed:', testPayment.data);
```

## Environment Configuration

For the complete list of API URLs for each environment, see our [Environments](/concepts/environments) page.

<CodeGroup>
  ```javascript theme={null}
  // Staging (Arbitrum Sepolia)
  const STAGING_CONFIG = {
    environment: 'stg',
    chainId: 421614,
    verifyingContract: '0x...' // Sepolia contract address
  };

  // Production (Arbitrum mainnet)
  const PROD_CONFIG = {
    environment: 'prod',
    chainId: 42161,
    verifyingContract: '0x...' // Mainnet contract address
  };
  ```

  ```typescript theme={null}
  interface Web3Config {
    environment: 'stg' | 'prod';
    chainId: number;
    verifyingContract: string;
  }

  const STAGING_CONFIG: Web3Config = {
    environment: 'stg',
    chainId: 421614,
    verifyingContract: '0x...'
  };

  const PROD_CONFIG: Web3Config = {
    environment: 'prod',
    chainId: 42161,
    verifyingContract: '0x...'
  };
  ```
</CodeGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Authentication Guide" icon="key" href="/guides/auth-integration">
    Learn how to authenticate with Rise using the SDK
  </Card>

  <Card title="Payment Integration" icon="credit-card" href="/guides/payment-integration">
    Complete payment flow with typed data
  </Card>

  <Card title="Team Management" icon="users" href="/guides/team-management">
    Managing teams with Web3
  </Card>

  <Card title="Invites Integration" icon="envelope" href="/guides/invites-integration">
    User onboarding flow
  </Card>
</CardGroup>

<Note>
  **Need help?** Check out our [Payment Integration Guide](/guides/payment-integration) for a complete example of typed data signing in action.
</Note>
