
Security News
npm Adopts OIDC for Trusted Publishing in CI/CD Workflows
npm now supports Trusted Publishing with OIDC, enabling secure package publishing directly from CI/CD workflows without relying on long-lived tokens.
rise-webhook-validator
Advanced tools
Official TypeScript/JavaScript SDK for Rise's payment and webhook systems, providing both webhook validation and API client functionality.
npm install @riseworks/sdk
# or
yarn add @riseworks/sdk
# or
pnpm add @riseworks/sdk
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}`);
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()
});
}
});
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}`);
}
The Rise API Client provides type-safe methods to interact with all Rise API endpoints.
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);
// 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);
// 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);
// 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);
// 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);
The Rise API client uses JWT token authentication. You need to provide a JWT token when initializing the client.
import { RiseApiClient } from '@riseworks/sdk'
const client = new RiseApiClient({
jwtToken: 'your-jwt-token-here',
timeout: 30000, // Default: 30 seconds
})
WebhookValidator
Class for validating webhook signatures and payloads.
new WebhookValidator(options: {
secret: string;
tolerance?: number; // Default: 300 seconds (5 minutes)
})
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 valueReturns: 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 valueReturns: { isValid: boolean; event?: RiseWebhookEvent; error?: string }
RiseApiClient
Class for making type-safe API calls to Rise endpoints.
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
})
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:
The client is organized into logical groups for better discoverability and organization:
riseClient.webhooks
- Webhook Operations:
sendEvent(data)
- Send webhook events to RiseriseClient.company
- Company Management:
getUsers(params)
- Get company usersupdateAddress(params, data)
- Update company addressgetDetails(params)
- Get organization detailsupdateDetails(params, data)
- Update organization detailsgetSettings(params)
- Get company settingsupdateSettings(params, data)
- Update company settingsgetRoleSettings(params)
- Get company role settingsupdateRoleSettings(params, data)
- Update company role settingsgetContacts(params)
- Get organization contactsupdateContacts(params, data)
- Update organization contactsgetOwnership(params)
- Get organization ownershipupdateOwnership(params, data)
- Update organization ownershipriseClient.entityBalance
- Entity Balance:
get(params)
- Get entity balanceriseClient.invites
- Team Invitations:
send(data)
- Send invites to team memberssendManager(data)
- Send manager invitesexecuteManager(data)
- Execute manager invitesget(params)
- Get invites for a company or teamriseClient.me
- Current User:
get()
- Get current user informationriseClient.payments
- Payment Operations:
get(params)
- Get paymentscreate(data)
- Create paymentsexecute(data)
- Execute paymentsriseClient.payroll
- Payroll Management:
enable(data)
- Enable payroll for a teamgetTeamPayroll(params)
- Get team payrollgetPayrollPeriod(params)
- Get payroll periodriseClient.team
- Team Management:
update(data)
- Update team informationriseClient.user
- User Management:
updateAddress(data)
- Update user addressupdateAvatar(data)
- Update user avatargetCompanies()
- Get user companiesgetTeams()
- Get user teamsriseClient.withdraw
- Withdraw Operations:
getSignData(params)
- Get withdraw sign datagetFee(params)
- Get withdraw feecreate(data)
- Create withdraw requestexecute(data)
- Execute withdrawAll methods are fully typed with request and response types generated from the API schemas.
// 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
The SDK supports all Rise webhook events with full type safety:
payment.sent
- A payment has been successfully sentpayment.group.created
- A new payment group has been createddeposit.received
- A deposit has been received and confirmedinvite.accepted
- A team member has accepted an invitationWhen using Rise ID and private key authentication, the client follows this process:
The process is fully automatic and transparent to the user.
WebhookValidator
for production webhooksMIT - See LICENSE file for details
FAQs
Rise SDK for webhook validation and TypeScript types
The npm package rise-webhook-validator receives a total of 13 weekly downloads. As such, rise-webhook-validator popularity was classified as not popular.
We found that rise-webhook-validator demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
npm now supports Trusted Publishing with OIDC, enabling secure package publishing directly from CI/CD workflows without relying on long-lived tokens.
Research
/Security News
A RubyGems malware campaign used 60 malicious packages posing as automation tools to steal credentials from social media and marketing tool users.
Security News
The CNA Scorecard ranks CVE issuers by data completeness, revealing major gaps in patch info and software identifiers across thousands of vulnerabilities.