Welcome to the Rise B2B API! This guide will help you migrate from the V1 API to our new, more powerful B2B API. The B2B API introduces significant improvements in security, functionality, and developer experience.
SDK Recommended : For the best developer experience with the B2B API, install the Rise SDK: npm install @riseworks/sdk
Enhanced Security SIWE authentication replaces X-Auth-Token for better security
Better Performance Optimized endpoints with improved response times
Web3 Native Built for blockchain with EIP-712 typed data signing
Improved Data Enhanced response formats with better error handling
Key Changes Overview
Authentication Changes
V1 : Used SIWE authentication with /v1/api/siwe
endpoints
B2B : Uses Sign-In with Ethereum (SIWE) with /v2/auth/siwe
endpoints
JWT Tokens : Still used but obtained through updated SIWE flow
Endpoint Structure
V1 : Used /v1/
prefix with various endpoint patterns
B2B : Uses /v2/
prefix with consistent REST patterns
Base URL : Updated to use the new B2B API URLs - see Environments for API URLs
V1 : Mixed response formats and error structures
B2B : Consistent { success: boolean, data: any }
response format
Error Handling : Standardized HTTP status codes with detailed error messages
Endpoint Migration Table
Authentication Endpoints
V1 Endpoint B2B Endpoint GET /v1/api/siwe
GET /v2/auth/siwe
POST /v1/api/siwe
POST /v2/auth/verify
Team Management
V1 Endpoint B2B Endpoint GET /v1/teams
GET /v2/user/teams
GET /v1/teams/{teamId}/talent
GET /v2/teams/{team_nanoid}/users
GET /v1/teams/{teamId}/talent/{talentId}
GET /v2/teams/{team_nanoid}/member/{user_nanoid}/summary
DELETE /v1/teams/{teamId}/talent/{talentId}
DELETE /v2/teams/{team_nanoid}/member/{user_nanoid}
Payment Processing
V1 Endpoint B2B Endpoint POST /v1/payments/pay
POST /v2/payments
+ PUT /v2/payments
PUT /v1/payments/pay
POST /v2/payments
+ PUT /v2/payments
POST /v1/payments/batch-pay
POST /v2/payments
+ PUT /v2/payments
PUT /v1/payments/batch-pay
POST /v2/payments
+ PUT /v2/payments
POST /v1/payments/batch-pay/intents
POST /v2/payments
+ PUT /v2/payments
GET /v1/payments/
GET /v2/payments
Balance Management
V1 Endpoint B2B Endpoint GET /v1/riseid/{rise_id}/balance
GET /v2/balance?nanoid={nanoid}
Invites Management
V1 Endpoint B2B Endpoint GET /v1/invites/
GET /v2/invites
POST /v1/invites/
(employees/contractors)POST /v2/invites
POST /v1/invites/
(managers)POST /v2/invites/manager
+ PUT /v2/invites/manager
POST /v1/invites/warmed
POST /v2/invites
New B2B API Endpoints (Not in V1)
The B2B API introduces several new endpoints that weren’t available in V1:
Team Management (Enhanced)
GET /v2/teams/{team_nanoid}/settings
- Get team settings
PUT /v2/teams/{team_nanoid}/settings
- Update team settings
GET /v2/teams/{team_nanoid}
- Get team by nanoid
DELETE /v2/teams/{team_nanoid}
- Delete team by nanoid
PUT /v2/teams/{team_nanoid}
- Update team by nanoid
POST /v2/teams
- Create a team
GET /v2/teams/{team_nanoid}/member/{user_nanoid}/settings
- Get member settings
PUT /v2/teams/{team_nanoid}/member/{user_nanoid}/settings
- Update member settings
Authentication Migration
B2B Authentication (New)
Using the Rise SDK (Recommended):
const { RiseApiClient } = require ( '@riseworks/sdk' );
// Initialize SDK with Rise ID and private key
const client = new RiseApiClient ({
environment: 'prod' ,
riseIdAuth: {
riseId: process . env . RISE_ID ,
privateKey: process . env . PRIVATE_KEY
}
});
// SDK automatically handles SIWE authentication and JWT management
const user = await client . me . get ();
console . log ( 'Authenticated as:' , user . data . name );
Alternative: Manual Authentication (Advanced):
// Manual SIWE authentication flow (for advanced use cases)
class RiseAuth {
constructor ( baseUrl ) {
this . baseUrl = baseUrl ;
}
async authenticate ( walletAddress , privateKey , riseId ) {
// Step 1: Get SIWE message
const siweResponse = await fetch (
` ${ this . baseUrl } /v2/auth/siwe?wallet= ${ walletAddress } &riseid= ${ riseId } `
);
const { siwe } = siweResponse . data . data ;
// Step 2: Sign with wallet
const wallet = new ethers . Wallet ( privateKey );
const signature = await wallet . signMessage ( siwe );
// Extract nonce from SIWE message
const nonceMatch = siwe . match ( /Nonce: ( . + ) / );
const nonce = nonceMatch ? nonceMatch [ 1 ] : '' ;
// Step 3: Verify and get JWT
const verifyResponse = await fetch ( ` ${ this . baseUrl } /v2/auth/verify` , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ message: siwe , sig: signature , nonce })
});
const { jwt } = verifyResponse . data . data ;
return jwt ;
}
}
// Use JWT in requests (same as V1)
const apiResponse = await fetch ( ` ${ this . baseUrl } /v2/teams` , {
headers: { 'Authorization' : `Bearer ${ jwt } ` }
});
B2B Response:
{
"success" : true ,
"data" : {
"teams" : [
{
"nanoid" : "te-abc123def456" ,
"name" : "Engineering Team" ,
"created_at" : "2024-01-01T00:00:00Z"
}
]
}
}
B2B Error:
{
"success" : false ,
"data" : "Team te-abc123def456 not found"
}
ID System Changes
V1: Mixed ID System
Teams: 123
, 456
, 789
(numeric IDs)
Users: talentId
(numeric IDs)
RiseID: rise_id
(string format)
B2B: Nanoid System
Teams: te-abc123def456
Users: us-ghi789jkl012
Companies: co-def456ghi789
Payments: pa-pay123def456
Migration Checklist
Phase 1: Preparation
Phase 2: Core Migration
Phase 3: Advanced Features
Code Migration Examples
Team Member Retrieval
V1 Code:
const getTeamMembers = async ( teamId ) => {
const response = await fetch ( ` ${ this . baseUrl } /v1/teams/ ${ teamId } /talent` , {
headers: { 'Authorization' : `Bearer ${ jwt } ` }
});
const members = await response . json ();
return members ; // Returns array of members
};
B2B Code (Using SDK):
const { RiseApiClient } = require ( '@riseworks/sdk' );
const client = new RiseApiClient ({
environment: 'prod' ,
riseIdAuth: {
riseId: process . env . RISE_ID ,
privateKey: process . env . PRIVATE_KEY
}
});
const getTeamMembers = async ( teamNanoid ) => {
const response = await client . teams . getUsers ({
nanoid: teamNanoid
});
return response . data . users ; // Returns array of users
};
B2B Code (Manual HTTP):
const getTeamMembers = async ( teamNanoid ) => {
const response = await fetch ( ` ${ this . baseUrl } /v2/teams/ ${ teamNanoid } /users` , {
headers: { 'Authorization' : `Bearer ${ jwt } ` }
});
const result = await response . json ();
return result . data . users ; // Returns array of users
};
Payment Processing
V1 Code:
const payV1 = async ( teamId , recipients , token ) => {
const response = await fetch ( ` ${ this . baseUrl } /v1/payments/pay` , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ token } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
team_id: teamId ,
recipients: recipients . map ( r => ({
user_id: r . userId ,
amount: r . amount ,
currency: r . currency ,
description: r . description
}))
})
});
return await response . json ();
};
B2B Code (Using SDK - Automatic):
const { RiseApiClient } = require ( '@riseworks/sdk' );
const client = new RiseApiClient ({
environment: 'prod' ,
riseIdAuth: {
riseId: process . env . RISE_ID ,
privateKey: process . env . PRIVATE_KEY // Required for automatic signing
}
});
const payB2B = async ( teamNanoid , recipients ) => {
// SDK handles the entire payment flow automatically
const payment = await client . payments . sendPayment ({
from: teamNanoid ,
to: recipients ,
pay_now: true , // true = pay immediately, false = intent (pay later)
network: 'arbitrum'
});
return payment . data ;
};
// Usage example
const recipients = [
{
to: 'us-jRxg2LRL54DJ' ,
amount_cents: 300 ,
currency_symbol: 'USD' ,
invoice_description: 'Papa Sent you' ,
},
{
to: 'us-d6JHBF2kuZjE' ,
amount_cents: 700 ,
currency_symbol: 'USD' ,
invoice_description: 'Papa Sent you' ,
},
];
const payment = await payB2B ( 'te-bXy7gjb_Iga-' , recipients );
console . log ( 'Payment executed:' , payment );
B2B Code (Using SDK - Manual):
const { RiseApiClient } = require ( '@riseworks/sdk' );
const client = new RiseApiClient ({
environment: 'prod' ,
jwtToken: process . env . JWT_TOKEN // JWT token is sufficient for manual flow
});
const payB2BManual = async ( teamNanoid , recipients , walletAddress , privateKey ) => {
// Step 1: Create payment draft
const createResponse = await client . payments . getPaymentTypedData ({
from: teamNanoid ,
to: recipients ,
pay_now: true ,
network: 'arbitrum'
});
const { typed_data } = createResponse . data ;
console . log ( 'Payment draft created:' , typed_data );
// Step 2: Sign typed data
const { ethers } = require ( 'ethers' );
const wallet = new ethers . Wallet ( privateKey );
const signature = await wallet . signTypedData (
typed_data . domain ,
typed_data . types ,
typed_data . typed_data
);
// Step 3: Execute payment
const executeResponse = await client . payments . executePaymentWithSignedData ({
signer: walletAddress ,
from: teamNanoid ,
to: recipients ,
pay_now: true ,
typed_data: typed_data . typed_data ,
signature: signature
});
console . log ( 'Payment executed:' , executeResponse . data );
return executeResponse . data ;
};
B2B Code (Manual HTTP):
import { ethers } from 'ethers' ;
async function createPayment ( teamNanoid , recipients , walletAddress , privateKey , payNow = true ) {
// Step 1: Create payment draft
const createResponse = await fetch ( ` ${ this . baseUrl } /v2/payments` , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ jwt } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
from: teamNanoid ,
to: recipients ,
pay_now: payNow , // true = pay immediately, false = intent (pay later)
network: 'arbitrum'
})
});
if ( ! createResponse . ok ) {
const errorText = await createResponse . text ();
throw new Error ( `Failed to create payment draft: ${ createResponse . status } - ${ errorText } ` );
}
const { data : typedData } = await createResponse . json ();
console . log ( 'Payment draft created:' , typedData );
// Step 2: Sign typed data
const wallet = new ethers . Wallet ( privateKey );
const signature = await wallet . signTypedData (
typedData . domain ,
typedData . types ,
typedData . typed_data
);
// Step 3: Execute payment
const executeResponse = await fetch ( ` ${ this . baseUrl } /v2/payments` , {
method: 'PUT' ,
headers: {
'Authorization' : `Bearer ${ jwt } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
signer: walletAddress ,
from: teamNanoid ,
to: recipients ,
pay_now: payNow ,
typed_data: typedData . typed_data ,
signature: signature
})
});
const response = await executeResponse . json ();
console . log ( 'Payment executed:' , response . data );
return response . data ;
}
// Usage example
const to = [
{
to: 'us-jRxg2LRL54DJ' ,
amount_cents: 300 ,
currency_symbol: 'USD' ,
invoice_description: 'Papa Sent you' ,
},
{
to: 'us-d6JHBF2kuZjE' ,
amount_cents: 700 ,
currency_symbol: 'USD' ,
invoice_description: 'Papa Sent you' ,
},
];
const payment = await createPayment (
'te-bXy7gjb_Iga-' ,
to ,
'<WALLET_ADDRESS>' ,
'<WALLET_PRIVATE_KEY>' ,
true // true = pay immediately, false = pay intent (pay later)
);
Use pay_now: true
to execute payments immediately, or pay_now: false
to create a payment intent for later execution.
Balance Retrieval
B2B Code (Using SDK):
const { RiseApiClient } = require ( '@riseworks/sdk' );
const client = new RiseApiClient ({
environment: 'prod' ,
riseIdAuth: {
riseId: process . env . RISE_ID ,
privateKey: process . env . PRIVATE_KEY
}
});
const getBalance = async ( nanoid ) => {
const response = await client . balance . get ({
nanoid: nanoid
});
return response . data ; // Returns balance with account address and currency breakdown
};
B2B Code (Manual HTTP):
const getBalance = async ( nanoid ) => {
const response = await fetch ( ` ${ this . baseUrl } /v2/balance?nanoid= ${ nanoid } ` , {
headers: { 'Authorization' : `Bearer ${ jwt } ` }
});
const result = await response . json ();
return result . data ; // Returns balance with account address and currency breakdown
};
Common Migration Issues
Issue 1: Authentication Errors
Problem: Getting 401 errors after migration
Solution:
Update SIWE endpoint paths from /v1/api/siwe
to /v2/auth/siwe
and /v2/auth/verify
Check that JWT tokens are included as Authorization: Bearer <jwt>
headers
Verify JWT hasn’t expired (24-hour lifetime)
Problem: Getting 404 errors for resources that should exist
Solution:
Replace numeric IDs with nanoids
Update all endpoint URLs to use nanoid format
Check that you’re using the correct nanoid type (team, user, company)
Problem: Code expecting old response format
Solution:
Update response handling to use response.data.data
instead of direct properties
Handle the new { success, data }
wrapper format
Update error handling to use response.data
for error messages
Issue 4: Missing EIP-712 Signing
Problem: Getting errors about missing signatures
Solution:
Implement EIP-712 typed data signing for operations that require it
Use the two-step process (create + execute) for payments and team management
Ensure wallet is connected and has proper permissions
Support During Migration
Need Help? Our support team is available to help with your migration. Contact us at Hello@Riseworks.io for personalized assistance.
Important : The V1 API will be deprecated in the future. We recommend completing your migration as soon as possible to ensure continued access to Rise services.