All RebelFi APIs use consistent, industry-standard data formats for monetary values, rates, timestamps, and other common types.
Design Philosophy
These data shapes follow industry standards from Fireblocks, Coinbase, and Circle. Priority is smallest responses with minimal redundancy. Clients format display strings and cache token metadata.
Standard Types
Amount
Used for all single-token monetary values.
Format :
{
"amount" : "1.11" , // Decimal string (human-readable)
"currency" : "USDC" // Token symbol
}
Industry Standard : Matches Fireblocks, Coinbase, Circle exactly (2 fields)
Why Strings? : Avoids JavaScript floating-point precision issues (e.g., 1.11 becoming 1.1099999999)
Client Usage :
// Display
const display = ` ${ amount . amount } ${ amount . currency } ` ; // "1.11 USDC"
// Calculations (use Decimal.js or BigDecimal for precision)
import Decimal from 'decimal.js' ;
const value = new Decimal ( amount . amount );
// Convert to base units (if needed for transaction construction)
const baseUnits = parseFloat ( amount . amount ) * Math . pow ( 10 , tokenDecimals );
Examples :
{ "amount" : "1.11" , "currency" : "USDC" }
{ "amount" : "0.5" , "currency" : "SOL" }
{ "amount" : "1000.00" , "currency" : "USDT" }
Token Metadata : Decimals, mintAddress, etc. available via GET /api/tokens (cache client-side)
Base units are NOT included in GET responses (blockchain implementation detail). Responses use human-readable decimal amounts only.
USD Aggregate
Used for cross-token totals and portfolio summaries.
Simple String (when currency is obvious from context):
{
"totalUsd" : "3.61" ,
"availableUsd" : "1.50" ,
"allocatedUsd" : "2.11"
}
Object Form (when multiple currencies possible):
{
"amount" : "3.61" ,
"currency" : "USD"
}
Usage :
Cross-token aggregates (total balances, total yield, performance metrics)
Portfolio-level summaries
Org-level reporting
Client Formatting :
const display = `$ ${ totalUsd } USD` ; // "$3.61 USD"
Stablecoin = $1 USD Assumption : This API assumes all stablecoins have a 1:1 peg with USD for aggregation purposes.This simplification works because:
Platform currently only deals with stablecoins (USDC, USDT, etc.)
Avoids price oracle dependency and complexity
Provides intuitive USD totals for proving ROI
Future enhancement: Integrate price oracle for non-stablecoin tokens.
APY / Rate
Annual Percentage Yield as a simple percentage string.
Format :
{
"currentAPY" : "6.25" , // 6.25% APY
"weightedAvgAPY" : "5.83" , // 5.83% weighted average
"currentApy" : "6.0" // Some endpoints use lowercase
}
Why Percentage Format? :
APY = Annual Percentage Yield (semantically correct)
Matches traditional finance APIs
More intuitive than decimal format (0.0625)
Client Usage :
// Display
const display = ` ${ currentAPY } %` ; // "6.25%"
// As decimal for calculations
const decimal = parseFloat ( currentAPY ) / 100 ; // 0.0625
// As basis points
const bps = Math . round ( parseFloat ( currentAPY ) * 100 ); // 625
Field Names : Implementation uses currentAPY, currentApy, weightedAvgAPY (not just apy)
Store and transmit as percentage string to avoid floating-point precision issues. Convert to decimal only for calculations.
Timestamp
All date/time values use dual representation.
Format :
{
"iso" : "2025-01-30T10:30:00Z" , // ISO 8601 (primary)
"unix" : 1706611800 // Unix timestamp (seconds)
}
When to Use Each :
iso : Human-readable, timezone-aware, sortable, primary format for display
unix : Epoch calculations, time comparisons, systems that prefer Unix time
Client Usage :
// Parse ISO string
const date = new Date ( timestamp . iso );
// Use Unix timestamp
const epochSeconds = timestamp . unix ;
const epochMillis = timestamp . unix * 1000 ;
Used for all paginated list endpoints.
Format :
{
"total" : 150 , // Total items matching query
"limit" : 50 , // Items per page (requested)
"offset" : 0 , // Starting position
"hasMore" : true // More pages available
}
Request Parameters :
limit - Number of items to return (default: 50, max: 100)
offset - Number of items to skip (default: 0)
Example :
// Request next page
const response = await fetch (
`/api/core/operations/history?limit=20&offset=20`
);
const { items , total , hasMore } = await response . json ();
if ( hasMore ) {
// Fetch next page with offset=40
}
Error Response
Standard error format for HTTP 4xx/5xx responses.
Format :
{
"code" : "INVALID_TOKEN_SYMBOL" , // Machine-readable error code
"message" : "Token 'XYZ' not found" , // Human-readable message
"details" : { // Additional context (optional)
"availableTokens" : [ "USDC" , "USDT" , "SOL" ],
"requested" : "XYZ"
}
}
Usage :
HTTP status code indicates error category (400, 404, 500)
code: Use for programmatic error handling
message: Display to users or log
details: Include helpful context (available options, validation errors)
Common Error Codes :
Code HTTP Status Description
UNAUTHORIZED401 Invalid or missing authentication credentials FORBIDDEN403 Insufficient permissions for this action NOT_FOUND404 Resource not found VALIDATION_ERROR400 Request validation failed INSUFFICIENT_BALANCE400 Not enough available funds INVALID_TOKEN_SYMBOL400 Token symbol not recognized OPERATION_IN_PROGRESS409 Another operation is already running on this wallet RATE_LIMIT_EXCEEDED429 Too many requests INTERNAL_ERROR500 Internal server error
Example :
{
"code" : "INSUFFICIENT_BALANCE" ,
"message" : "Available balance is less than requested amount" ,
"details" : {
"available" : "500.00" ,
"requested" : "1000.00" ,
"shortfall" : "500.00"
}
}
Response Optimization
These data shapes prioritize:
Smallest responses : 2-field Amount vs 5-field MoneyAmount (~70% size reduction)
Minimal redundancy : Token metadata fetched separately, cached client-side
Industry alignment : Matches Fireblocks/Coinbase/Circle standards
Developer experience : Predictable, consistent formats across all endpoints
Token metadata (decimals, mintAddress, blockchain) is available via a separate endpoint:
Pattern : Fetch once, cache client-side.
Why Not in Every Response? :
Reduces response size by ~70%
Matches industry standards (Fireblocks, Coinbase, Circle)
Metadata rarely changes
Example :
// Fetch and cache tokens once
const tokens = await fetch ( '/api/tokens' ). then ( r => r . json ());
const tokenMap = new Map ( tokens . map ( t => [ t . symbol , t ]));
// Use cached metadata
const usdcDecimals = tokenMap . get ( 'USDC' ). decimals ; // 6
Best Practices
Always Use Strings for Money
Never use JavaScript Number type for monetary values. Always use string representation and parse with a decimal library. // ✅ CORRECT
import Decimal from 'decimal.js' ;
const amount = new Decimal ( "1.11" );
// ❌ WRONG
const amount = 1.11 ; // Floating-point precision issues!
Display Formatting Client-Side
Handle Errors Programmatically
Use the error code field for programmatic error handling, not the message. try {
const result = await createOperation ( ... );
} catch ( error ) {
if ( error . code === 'INSUFFICIENT_BALANCE' ) {
// Handle insufficient balance
showError ( `Need ${ error . details . shortfall } more ${ token } ` );
} else if ( error . code === 'OPERATION_IN_PROGRESS' ) {
// Handle conflict
showError ( 'Another operation is running, please wait' );
}
}
Migration Notes
If you’re upgrading from a previous API version or custom implementation:
Switch to 2-Field Amount : Replace any 5-field MoneyAmount with { amount, currency }
Use Percentage for APY : Replace decimal APY (0.0625) with percentage string (“6.25”)
Add Timestamp Dual Format : Include both iso and unix in timestamp fields
Handle USD Aggregates as Strings : Parse USD totals as simple strings, not objects
Examples by Use Case
Creating an Operation
const response = await fetch ( '/api/v1/allocations' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ token } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
opWalletId: 123 ,
amount: "1000.00" , // String, not number
asset: "USDC" // Symbol, not ID
})
});
const result = await response . json ();
// result.reservedAmount is an Amount object: { amount: "1000.00", currency: "USDC" }
Displaying Portfolio Summary
const stats = await fetch ( '/api/core/wallets/stats' )
. then ( r => r . json ());
// Display USD totals
console . log ( `Total: $ ${ stats . data . balances . totalUsd } USD` );
console . log ( `Available: $ ${ stats . data . balances . availableUsd } USD` );
// Display APY
console . log ( `Average APY: ${ stats . data . performance . weightedAvgAPY } %` );
// Display per-token breakdown
stats . data . balances . byToken . forEach ( tokenBalance => {
console . log ( ` ${ tokenBalance . total } ${ tokenBalance . currency } ` );
});
Handling Errors
try {
const result = await createSupplyOperation ( opWalletId , "500.00" , "USDC" );
} catch ( error ) {
// error is an Error Response object
console . error ( `Error [ ${ error . code } ]: ${ error . message } ` );
if ( error . details ) {
console . error ( 'Details:' , error . details );
}
// Programmatic handling
switch ( error . code ) {
case 'INSUFFICIENT_BALANCE' :
alert ( `You need ${ error . details . shortfall } more USDC` );
break ;
case 'INVALID_TOKEN_SYMBOL' :
alert ( `Token not supported. Available: ${ error . details . availableTokens . join ( ', ' ) } ` );
break ;
}
}