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

# Payment Integration Guide

> Complete guide to integrating payments with Rise B2B API using the SDK

Rise provides a comprehensive payment system that enables batch payments with blockchain security. This guide covers the complete payment flow using the Rise SDK for seamless integration.

## Payment Flow Overview

<Steps>
  <Step title="Initialize SDK">
    Set up the Rise SDK with authentication
  </Step>

  <Step title="Create Payment">
    Use SDK to create payment drafts with typed data
  </Step>

  <Step title="Execute Payment">
    SDK automatically handles signing and execution
  </Step>

  <Step title="Monitor Status">
    Track payment status and confirmations
  </Step>
</Steps>

## Payment Types

### Batch Payments

Process multiple payments in a single transaction for efficiency and cost savings.

### Individual Payments

Process single payments with immediate execution.

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

## Creating Payments

### Step 1: Initialize the SDK

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

// Initialize SDK with private key for automatic signing
const client = new RiseApiClient({
  environment: 'prod',
  riseIdAuth: {
    riseId: process.env.RISE_ID,
    privateKey: process.env.PRIVATE_KEY  // Required for automatic signing
  }
});

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

### Step 2: Create and Execute Payment

The SDK provides two methods for creating payments:

#### Method 1: Automatic Payment (Recommended)

The SDK must be initialized with a private key for automatic signing:

```javascript theme={null}
// Initialize SDK with private key for automatic signing
const client = new RiseApiClient({
  environment: 'prod',
  riseIdAuth: {
    riseId: process.env.RISE_ID,
    privateKey: process.env.PRIVATE_KEY  // Required for automatic signing
  }
});

// SDK handles everything automatically
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'
    },
    {
      to: 'us-def456ghi789',
      amount_cents: 15000,
      currency_symbol: 'USD',
      invoice_description: 'Bonus payment'
    }
  ],
  pay_now: true,
  network: 'arbitrum'
});

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

#### Method 2: Manual Flow (Advanced)

For manual control over the signing process:

```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'
});

// 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);
```

## Complete Payment Integration Example

Here's a complete example using the Rise SDK:

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

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

  async createBatchPayment(teamNanoid, recipients, payNow = true) {
    try {
      console.log('Creating batch payment...');
      
      const payment = await this.client.payments.sendPayment({
        from: teamNanoid,
        to: recipients,
        pay_now: payNow,
        network: 'arbitrum'
      });

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

  async queryPayments(teamNanoid, options = {}) {
    try {
      const params = {
        team_nanoid: teamNanoid,
        state: options.state || 'all',
        query_type: options.queryType || 'payable',
        ...(options.startDate && { start_date: options.startDate }),
        ...(options.endDate && { end_date: options.endDate }),
        ...(options.recipient && { recipient: options.recipient })
      };

      const payments = await this.client.payments.get(params);
      return payments.data;
    } catch (error) {
      console.error('Failed to query payments:', error.message);
      throw error;
    }
  }

  async getPaymentHistory(teamNanoid, startDate, endDate) {
    return this.queryPayments(teamNanoid, {
      startDate,
      endDate,
      state: 'all'
    });
  }
}

// Usage example
const paymentSystem = new RisePaymentSystem();

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'
  }
];

// Create immediate payment
const payment = await paymentSystem.createBatchPayment(
  'te-bXy7gjb_Iga-',
  recipients,
  true // pay immediately
);

// Query payment history
const history = await paymentSystem.getPaymentHistory(
  'te-bXy7gjb_Iga-',
  '2024-01-01',
  '2024-01-31'
);
```

## Payment Status Tracking

Monitor payment status using the SDK:

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

  async queryPayments(teamNanoid, options = {}) {
    const params = {
      team_nanoid: teamNanoid,
      state: options.state || 'all',
      query_type: options.queryType || 'payable',
      ...(options.startDate && { start_date: options.startDate }),
      ...(options.endDate && { end_date: options.endDate }),
      ...(options.recipient && { recipient: options.recipient })
    };
    
    return await this.client.payments.get(params);
  }

  async waitForConfirmation(transactionHash, maxAttempts = 30) {
    const { ethers } = require('ethers');
    const provider = new ethers.JsonRpcProvider('https://arb1.arbitrum.io/rpc');
    
    for (let i = 0; i < maxAttempts; i++) {
      const receipt = await provider.getTransactionReceipt(transactionHash);
      
      if (receipt && receipt.confirmations > 0) {
        return {
          confirmed: true,
          blockNumber: receipt.blockNumber,
          gasUsed: receipt.gasUsed.toString(),
          status: receipt.status === 1 ? 'success' : 'failed'
        };
      }
      
      // Wait 10 seconds before next check
      await new Promise(resolve => setTimeout(resolve, 10000));
    }
    
    throw new Error('Transaction confirmation timeout');
  }
}
```

## Payment Timing Options

Rise supports two payment timing options:

| Option           | Description                  | Use Case                           |
| ---------------- | ---------------------------- | ---------------------------------- |
| `pay_now: true`  | Payment executes immediately | Instant payroll, urgent payments   |
| `pay_now: false` | Payment intent (scheduled)   | Future payroll, scheduled payments |

## Error Handling

The SDK provides comprehensive error handling:

```javascript theme={null}
try {
  const payment = await client.payments.sendPayment({
    from: 'te-abc123def456',
    to: recipients,
    pay_now: true,
    network: 'arbitrum'
  });
  
  console.log('Payment successful:', payment.data);
} catch (error) {
  console.error('Payment error:', error.message);
  
  // Handle specific error types based on message content
  if (error.message.includes('insufficient balance')) {
    console.error('Insufficient balance in the source account');
  } else if (error.message.includes('invalid signature')) {
    console.error('Signature verification failed');
  } else if (error.message.includes('expired')) {
    console.error('Payment deadline has expired');
  } else if (error.message.includes('401')) {
    console.error('Authentication failed');
  } else if (error.message.includes('403')) {
    console.error('Insufficient permissions');
  } else {
    console.error('Payment failed:', error.message);
  }
}
```

Common payment errors:

| Error Message            | Description                             | Solution                                      |
| ------------------------ | --------------------------------------- | --------------------------------------------- |
| `insufficient balance`   | Not enough funds in source account      | Check entity balance before creating payments |
| `invalid signature`      | TypedData signature verification failed | SDK handles signing automatically             |
| `expired deadline`       | Payment deadline has passed             | Create a new payment with updated deadline    |
| `invalid recipient`      | Recipient address is not valid          | Verify recipient addresses and permissions    |
| `payment limit exceeded` | Payment amount exceeds limits           | Check payment limits for the entity           |

## Security Best Practices

<Warning>
  **Always verify payment details** before execution. Double-check amounts, recipients, and payment descriptions.
</Warning>

* **SDK Authentication**: Use the SDK's built-in authentication and signing
* **Environment Variables**: Store sensitive credentials securely
* **Secondary Wallets**: Use dedicated wallets for API operations
* **Amount Validation**: Validate payment amounts before submission
* **Recipient Verification**: Ensure recipients have valid Rise accounts
* **Error Handling**: Implement proper error handling for payment failures

## Testing Payments

For testing, use the staging environment:

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

// Test payment with small amounts
const testRecipients = [
  {
    to: 'us-test-user-nanoid',
    amount_cents: 100,
    currency_symbol: 'USD',
    invoice_description: 'Test payment'
  }
];

const testPayment = await stagingClient.payments.sendPayment({
  from: 'te-test-team-nanoid',
  to: testRecipients,
  pay_now: true,
  network: 'arbitrum'
});
```

## Real-World Integration Example

### Payroll System Integration

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

  async processPayrollRun(payrollRun) {
    const recipients = payrollRun.employees.map(emp => ({
      to: emp.user_nanoid,
      amount_cents: emp.amount_cents,
      currency_symbol: 'USD',
      invoice_description: `${emp.description} - ${payrollRun.pay_date}`
    }));

    try {
      const result = await this.client.payments.sendPayment({
        from: payrollRun.team_nanoid,
        to: recipients,
        pay_now: true,
        network: 'arbitrum'
      });

      // Store payroll run result
      await this.storePayrollResult(payrollRun.id, result);

      return result;
    } catch (error) {
      console.error(`Payroll run ${payrollRun.id} failed:`, error.message);
      throw error;
    }
  }

  async storePayrollResult(payrollId, result) {
    // Store in your database
    console.log(`Payroll ${payrollId} processed:`, result.data);
  }
}

// Usage
const payrollSystem = new PayrollSystem();

const payrollRun = {
  id: 'payroll-2024-01',
  employees: [
    {
      user_nanoid: 'us-emp1',
      amount_cents: 50000,
      description: 'January Salary'
    },
    {
      user_nanoid: 'us-emp2',
      amount_cents: 45000,
      description: 'January Salary'
    }
  ],
  team_nanoid: 'te-company-team',
  pay_date: '2024-01-31'
};

const result = await payrollSystem.processPayrollRun(payrollRun);
```

## 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="Team Management" icon="users" href="/guides/team-management">
    Manage teams and permissions for payment operations
  </Card>

  <Card title="Webhooks" icon="webhook" href="/webhooks/getting-started/overview">
    Set up real-time payment notifications
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/guides/error-handling">
    Comprehensive error handling and troubleshooting
  </Card>
</CardGroup>

<Note>
  **Need help?** See the [Payments](/concepts/payments) page for detailed payment concepts or contact support at [Hello@Riseworks.io](mailto:Hello@Riseworks.io)
</Note>
