rise-webhook-validator
TypeScript icon, indicating that this package has built-in type declarations

1.0.10 • Public • Published

Rise SDK

Official TypeScript/JavaScript SDK for Rise's payment and webhook systems, providing both webhook validation and API client functionality.

Features

  • 📝 Comprehensive TypeScript Types - Full type definitions for all Rise webhook events and API endpoints
  • Webhook Validation - Validate webhook payloads against Zod schemas with signature verification
  • 🚀 API Client - Type-safe HTTP client for all Rise API endpoints
  • 🎯 Type Safety - Full type support for all Rise webhook events and API requests/responses with autocomplete
  • 🔒 Security First - Built-in signature verification to ensure webhooks come from Rise
  • Optimized Builds - Lightweight and fast library

Installation

npm install @riseworks/sdk
# or
yarn add @riseworks/sdk
# or
pnpm add @riseworks/sdk

Quick Start

Basic Webhook Validation

import { WebhookValidator, type RiseWebhookEvent } from '@riseworks/sdk';

const riseValidator = new WebhookValidator({
  secret: process.env.RISE_WEBHOOK_SECRET!,
  tolerance: 720 // 12 minutes tolerance
});

// Validate webhook signature and payload
const event = riseValidator.validateEvent(req.body, req.headers['x-rise-signature']);
console.log(`Event type: ${event.event_type}`);
console.log(`Event ID: ${event.id}`);

Webhook Signature Verification

For production use, verify that webhook requests actually come from Rise using the WebhookValidator class:

import express from 'express';
import { WebhookValidator, type RiseWebhookEvent } from '@riseworks/sdk';

const app = express();

// Use raw body for signature verification
app.use('/rise-webhooks', express.raw({ type: 'application/json' }));

app.post('/rise-webhooks', (req, res) => {
  const signature = req.headers['x-rise-signature'] as string;
  const secret = process.env.RISE_WEBHOOK_SECRET!;

  try {
    // Validate webhook using Rise SDK WebhookValidator with full type safety
    const riseValidator = new WebhookValidator({
      secret: secret,
      tolerance: 720 // 12 minutes tolerance
    });
    
    // Option 1: validateEvent (throws on failure)
    let event = riseValidator.validateEvent(req.body, signature);
    
    // Option 2: validateEventSafe (returns result object)
    const result = riseValidator.validateEventSafe(req.body, signature);
    if (!result.isValid) {
      console.error('Validation failed:', result.error);
      return res.status(400).json({ error: result.error });
    }
    event = result.event;

    // Signature is valid, process the event with full TypeScript support
    handleEvent(event);

    res.status(200).json({ 
      received: true,
      timestamp: new Date().toISOString(),
      event_type: event.event_type,
      event_version: event.event_version,
      idempotency_key: event.idempotency_key
    });
  } catch (error) {
    console.error('Webhook verification failed:', error instanceof Error ? error.message : String(error));
    res.status(400).json({ 
      error: 'Webhook processing failed',
      message: error instanceof Error ? error.message : String(error),
      timestamp: new Date().toISOString()
    });
  }
});

Handling Different Event Types

import type { 
  RiseWebhookEvent, 
  PaymentSentV1, 
  PaymentGroupCreatedV1, 
  DepositReceivedV1 
} from '@riseworks/sdk';

function handleEvent(event: RiseWebhookEvent) {
  switch (event.event_type) {
    case 'payment.sent':
      // Send confirmation email with full type safety
      sendPaymentConfirmation(event as PaymentSentV1);
      break;

    case 'payment.group.created':
      // Update order status with full type safety
      updateOrderStatus(event as PaymentGroupCreatedV1);
      break;

    case 'deposit.received':
      // Trigger fulfillment with full type safety
      triggerFulfillment(event as DepositReceivedV1);
      break;

    default:
      console.log('Unhandled event type:', event.event_type);
  }
}

async function sendPaymentConfirmation(event: PaymentSentV1) {
  // Your email logic here with full type safety
  console.log(`Sending confirmation for payment ${event.payment.nanoid}`);
  console.log(`Amount: ${event.payment.amount_cents} cents`);
  console.log(`Recipients: ${event.payment.recipients.length}`);
}

API Client

The Rise API Client provides type-safe methods to interact with all Rise API endpoints.

Basic API Client Usage

import { RiseApiClient } from '@riseworks/sdk';

// Initialize the API client
const riseClient = new RiseApiClient({
  jwtToken: process.env.RISE_JWT_TOKEN!,
  timeout: 30000, // Optional, defaults to 30 seconds
});

// Get current user information
const userResponse = await riseClient.me.get();
console.log('Current user:', userResponse.data.user);
console.log('Company:', userResponse.data.company);

Sending Team Invites

// Send invites to team members with full type safety
const inviteResponse = await riseClient.invites.send({
  nanoid: 'team_1234567890',
  invites: [
    {
      email: 'john@example.com',
      prefill: {
        first_name: 'John',
        last_name: 'Doe',
        phone: '+1234567890',
        company_name: 'Example Corp',
        job_title: 'Developer',
        company_size: '10-50',
        company_website: 'https://example.com',
        company_industry: 'Technology',
        company_address: '123 Main St',
        company_city: 'San Francisco',
        company_state: 'CA',
        company_zip: '94105',
        company_country: 'US',
      },
    },
  ],
  role: 'team_employee',
});

console.log('Invites sent:', inviteResponse.data.nanoids);

Creating and Executing Payments

// Step 1: Create payments (get typed data for blockchain)
const createResponse = await riseClient.payments.create({
  from: 'team_1234567890',
  to: [
    {
      to: 'user_1234567890',
      amount_cents: 100000, // $1000.00
      currency_symbol: 'USD',
      invoice_description: 'Payment for services',
    },
  ],
  pay_now: true,
  network: 'arbitrum',
});

console.log('Typed data for blockchain:', createResponse.data);

// Step 2: Execute payments (after signing the typed data)
const executeResponse = await riseClient.payments.execute({
  from: 'team_1234567890',
  to: [
    {
      to: 'user_1234567890',
      amount_cents: 100000,
      currency_symbol: 'USD',
      invoice_description: 'Payment for services',
    },
  ],
  pay_now: true,
  network: 'arbitrum',
  signer: '0x1234567890123456789012345678901234567890',
  typed_data: createResponse.data, // The typed data from step 1
  signature: '0x...', // The signature from the wallet
});

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

Getting Team Payments

// Get payments for a team with full type safety
const paymentsResponse = await riseClient.payments.get({
  team_nanoid: 'team_1234567890',
  state: 'all',
  start_date: '2024-01-01',
  end_date: '2024-12-31',
  query_type: 'payable',
});

console.log('Payments:', paymentsResponse.data.items);

B2B Webhook Events

// Send webhook events to Rise (B2B API)
const webhookResponse = await riseClient.webhooks.sendEvent({
  event_type: 'payment.sent',
  event_version: '1.0',
  id: 'evt_1234567890',
  timestamp: Math.floor(Date.now() / 1000),
  data: {
    payment: {
      nanoid: 'pay_1234567890',
      amount_cents: 100000,
      currency_symbol: 'USD',
      recipients: ['user_1234567890'],
    },
  },
});

console.log('Webhook event sent:', webhookResponse);

Authentication

The Rise API client uses JWT token authentication. You need to provide a JWT token when initializing the client.

JWT Token Authentication

import { RiseApiClient } from '@riseworks/sdk'

const client = new RiseApiClient({
  jwtToken: 'your-jwt-token-here',
  timeout: 30000, // Default: 30 seconds
})

API Reference

WebhookValidator

Class for validating webhook signatures and payloads.

Constructor

new WebhookValidator(options: {
  secret: string;
  tolerance?: number; // Default: 300 seconds (5 minutes)
})

Methods

validateEvent(payload, signature)

Validates a webhook event and returns the parsed event.

Parameters:

  • payload: Raw webhook payload (string, Buffer, or object)
  • signature: The x-rise-signature header value

Returns: The validated and typed webhook event

Throws: Error if validation fails

validateEventSafe(payload, signature)

Safely validates a webhook event and returns a result object.

Parameters:

  • payload: Raw webhook payload (string, Buffer, or object)
  • signature: The x-rise-signature header value

Returns: { isValid: boolean; event?: RiseWebhookEvent; error?: string }

RiseApiClient

Class for making type-safe API calls to Rise endpoints.

Constructor

new RiseApiClient(options: {
  // Authentication (choose one):
  jwtToken?: string;           // JWT token for authentication
  riseIdAuth?: {              // Rise ID authentication configuration
    riseId: string;           // Rise ID for automatic JWT generation
    privateKey: string;       // Private key for automatic JWT generation
  };
  
  // Configuration:
  environment?: 'dev' | 'stg' | 'prod'; // Default: 'prod'
  baseUrl?: string;           // Custom base URL (overrides environment)
  timeout?: number;           // Default: 30000ms
  headers?: Record<string, string>; // Custom headers
})

Authentication Methods

The Rise API client supports two authentication methods:

1. JWT Token (Traditional)

const client = new RiseApiClient({
  jwtToken: 'your-jwt-token-here',
  environment: 'prod'
})

2. Rise ID + Private Key (Automatic JWT Generation)

const client = new RiseApiClient({
  riseIdAuth: {
    riseId: '0x2DF5A64B859B203752C30F941035e3cfE93Bb089',
    privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
  },
  environment: 'dev'
})

When using Rise ID and private key authentication, the client will:

  • Automatically generate a JWT token using SIWE (Sign-In with Ethereum) before making any requests
  • Check JWT validity before each request
  • Automatically refresh the JWT token if it expires or becomes invalid
  • Handle 401 errors by regenerating the JWT token and retrying the request

Available API Groups

The client is organized into logical groups for better discoverability and organization:

riseClient.webhooks - Webhook Operations:

  • sendEvent(data) - Send webhook events to Rise

riseClient.company - Company Management:

  • getUsers(params) - Get company users
  • updateAddress(params, data) - Update company address
  • getDetails(params) - Get organization details
  • updateDetails(params, data) - Update organization details
  • getSettings(params) - Get company settings
  • updateSettings(params, data) - Update company settings
  • getRoleSettings(params) - Get company role settings
  • updateRoleSettings(params, data) - Update company role settings
  • getContacts(params) - Get organization contacts
  • updateContacts(params, data) - Update organization contacts
  • getOwnership(params) - Get organization ownership
  • updateOwnership(params, data) - Update organization ownership

riseClient.entityBalance - Entity Balance:

  • get(params) - Get entity balance

riseClient.invites - Team Invitations:

  • send(data) - Send invites to team members
  • sendManager(data) - Send manager invites
  • executeManager(data) - Execute manager invites
  • get(params) - Get invites for a company or team

riseClient.me - Current User:

  • get() - Get current user information

riseClient.payments - Payment Operations:

  • get(params) - Get payments
  • create(data) - Create payments
  • execute(data) - Execute payments

riseClient.payroll - Payroll Management:

  • enable(data) - Enable payroll for a team
  • getTeamPayroll(params) - Get team payroll
  • getPayrollPeriod(params) - Get payroll period

riseClient.team - Team Management:

  • update(data) - Update team information

riseClient.user - User Management:

  • updateAddress(data) - Update user address
  • updateAvatar(data) - Update user avatar
  • getCompanies() - Get user companies
  • getTeams() - Get user teams

riseClient.withdraw - Withdraw Operations:

  • getSignData(params) - Get withdraw sign data
  • getFee(params) - Get withdraw fee
  • create(data) - Create withdraw request
  • execute(data) - Execute withdraw

All methods are fully typed with request and response types generated from the API schemas.

Utility Methods

// Check authentication method
client.isUsingJwtToken()     // Returns true if using JWT token
client.isUsingRiseIdAuth()   // Returns true if using Rise ID + private key

// Get current token/info
client.getToken()            // Get current JWT token
client.getRiseId()           // Get Rise ID (if provided)

// Update authentication
client.updateToken(newToken) // Update JWT token

// Manual JWT refresh (for Rise ID auth)
await client.refreshJwtToken() // Manually refresh JWT token
await client.generateJwtToken() // Generate new JWT token

// Environment management
client.getEnvironment()      // Get current environment
client.updateEnvironment(env) // Update environment

Common Event Types

The SDK supports all Rise webhook events with full type safety:

  • payment.sent - A payment has been successfully sent
  • payment.group.created - A new payment group has been created
  • deposit.received - A deposit has been received and confirmed
  • invite.accepted - A team member has accepted an invitation
  • And many more...

Automatic JWT Generation Process

When using Rise ID and private key authentication, the client follows this process:

  1. SIWE Message Request: Requests a SIWE (Sign-In with Ethereum) message from the Rise API
  2. Message Signing: Signs the message using the provided private key
  3. Nonce Extraction: Extracts the nonce from the SIWE message
  4. Signature Verification: Sends the signed message to the Rise API for verification
  5. JWT Generation: Receives a JWT token upon successful verification
  6. Automatic Refresh: Checks JWT validity before each request and refreshes when needed

The process is fully automatic and transparent to the user.

Security Best Practices

  1. Always verify signatures - Use WebhookValidator for production webhooks
  2. Use HTTPS - Always use HTTPS in production
  3. Set appropriate tolerance - Use 5-15 minutes tolerance for timestamp validation
  4. Handle errors gracefully - Log validation failures for debugging
  5. Use environment variables - Store webhook secrets securely
  6. Secure private keys - Never expose private keys in client-side code or logs
  7. Use environment-specific keys - Use different private keys for dev/staging/production

License

MIT - See LICENSE file for details

Package Sidebar

Install

npm i rise-webhook-validator

Weekly Downloads

14

Version

1.0.10

License

MIT

Unpacked Size

376 kB

Total Files

7

Last publish

Collaborators

  • pietro-bertarini-riseworks