Overview
The rating system in IOTA Repstation allows parties to rate each other after completing a deal. Ratings are permanent, blockchain-recorded assessments that build into reputation profiles over time.
Rating Requirements
Deal-Bound Ratings
All ratings must be tied to a specific deal:
Deal must be in CLOSED state
Only deal participants can rate each other
Each participant can rate the other party once per deal
Ratings reference the specific deal and subject
Score Range
Ratings use a standardized 1-100 score system:
1-20 : Very Poor
21-40 : Poor
41-60 : Average
61-80 : Good
81-100 : Excellent
Rating Categories
Categories help organize different aspects of performance:
Common Categories
reliability - Did they deliver as promised?
communication - How well did they communicate?
quality - Was the work/product high quality?
speed - How quickly did they complete the work?
professionalism - Were they professional throughout?
Custom Categories
Applications can define their own categories:
// NFT Marketplace
const categories = [
'artwork_quality' ,
'authenticity' ,
'shipping_speed' ,
'packaging'
];
// Service Platform
const categories = [
'technical_skill' ,
'deadline_adherence' ,
'code_quality' ,
'project_management'
];
Creating Ratings
Basic Rating
const { endorsement_id } = await client . rate ({
signer: raterWallet ,
deal_id: completedDealId ,
score: 85 ,
category: 'reliability'
});
Multiple Category Ratings
Rate different aspects separately:
// Rate communication
await client . rate ({
signer: buyerWallet ,
deal_id: dealId ,
score: 92 ,
category: 'communication'
});
// Rate delivery speed
await client . rate ({
signer: buyerWallet ,
deal_id: dealId ,
score: 78 ,
category: 'speed'
});
// Rate product quality
await client . rate ({
signer: buyerWallet ,
deal_id: dealId ,
score: 95 ,
category: 'quality'
});
Rating Management
Updating Ratings
Ratings can be updated using the endorsement capability:
await client . updateRating ({
signer: raterWallet ,
endorsement_id: endorsementId ,
endorsement_cap_id: endorsementCapId ,
new_score: 90 , // Updated score
});
Revoking Ratings
Ratings can be completely revoked:
await client . revokeRating ({
signer: raterWallet ,
endorsement_id: endorsementId ,
endorsement_cap_id: endorsementCapId
});
Revoked ratings are permanently removed and cannot be restored. Use updates instead of revocation when possible.
Rating Aggregation
Global Reputation
All ratings for a user are aggregated globally:
const profile = await client . getReputationProfile ({
walletAddress: userWallet
});
console . log ( `Global average: ${ profile . global . average } /100` );
console . log ( `Total ratings: ${ profile . global . count } ` );
App-Scoped Reputation
Ratings are also tracked per application:
// Each app namespace maintains separate stats
profile . appScoped . forEach ( app => {
console . log ( `App: ${ app . appOwner } ` );
console . log ( `Average: ${ app . stats . average } /100` );
console . log ( `Count: ${ app . stats . count } ` );
});
Rating Data Structure
Endorsement Object
interface Endorsement {
id : string ;
rater : string ; // Wallet address of rater
deal_id : string ; // Associated deal
score : number ; // 1-100 rating score
category : string ; // Rating category
timestamp : string ; // When rating was created
last_updated ?: string ; // When rating was last modified
}
Rating Statistics
interface RatingStats {
average : number ; // Average of all ratings
count : number ; // Total number of ratings
distribution ?: { // Optional score distribution
excellent : number ; // 81-100 scores
good : number ; // 61-80 scores
average : number ; // 41-60 scores
poor : number ; // 21-40 scores
very_poor : number ; // 1-20 scores
};
}
Best Practices
1. Meaningful Categories
Use categories that matter to your use case:
// Good for marketplaces
const marketplaceCategories = [
'product_quality' ,
'shipping_speed' ,
'customer_service' ,
'value_for_money'
];
// Good for freelancing
const freelanceCategories = [
'skill_level' ,
'communication' ,
'deadline_compliance' ,
'work_quality'
];
2. Encourage Honest Ratings
Design your UI to promote fair ratings:
function RatingComponent ({ onSubmit }) {
const [ scores , setScores ] = useState ({});
return (
< div className = "rating-form" >
< h3 > Rate Your Experience </ h3 >
< RatingSlider
label = "Communication (How well did they communicate?)"
value = { scores . communication || 50 }
onChange = { ( score ) => setScores ({ ... scores , communication: score }) }
helpText = "Consider responsiveness, clarity, and professionalism"
/>
< RatingSlider
label = "Quality (How was the work quality?)"
value = { scores . quality || 50 }
onChange = { ( score ) => setScores ({ ... scores , quality: score }) }
helpText = "Consider attention to detail and meeting requirements"
/>
< button onClick = { () => submitRatings ( scores ) } >
Submit Ratings
</ button >
</ div >
);
}
3. Rating Timing
Prompt for ratings at the right time:
class OrderService {
async markOrderDelivered ( orderId : string ) {
const order = await this . getOrder ( orderId );
// Close the deal first
await this . reputation . closeDeal ({
signer: this . adminWallet ,
deal_id: order . reputationDealId
});
// Send rating reminders after short delay
setTimeout (() => {
this . sendRatingReminder ( order . buyerId , order . id );
this . sendRatingReminder ( order . sellerId , order . id );
}, 24 * 60 * 60 * 1000 ); // 24 hours
}
}
Error Handling
Common rating errors:
try {
await client . rate ({
signer: wallet ,
deal_id: dealId ,
score: score ,
category: category
});
} catch ( error ) {
switch ( error . code ) {
case 'DEAL_NOT_CLOSED' :
showError ( 'Deal must be completed before rating' );
break ;
case 'ALREADY_RATED' :
showError ( 'You have already rated this deal. Use update instead.' );
break ;
case 'NOT_DEAL_PARTICIPANT' :
showError ( 'Only deal participants can rate each other' );
break ;
case 'INVALID_SCORE' :
showError ( 'Rating must be between 1 and 100' );
break ;
case 'CANNOT_RATE_SELF' :
showError ( 'You cannot rate yourself' );
break ;
}
}
Integration Examples
E-commerce Rating Flow
class EcommerceRatings {
async handleOrderCompletion ( orderId : string ) {
const order = await this . db . orders . findById ( orderId );
// Close reputation deal
await this . reputation . closeDeal ({
signer: this . adminWallet ,
deal_id: order . reputationDealId
});
// Enable rating UI for both parties
await this . enableRatings ( order . buyerId , order . sellerId , order . id );
}
async submitBuyerRating ( buyerId : string , orderId : string , ratings : any ) {
const order = await this . db . orders . findById ( orderId );
// Rate seller on multiple categories
for ( const [ category , score ] of Object . entries ( ratings )) {
await this . reputation . rate ({
signer: buyerId ,
deal_id: order . reputationDealId ,
score: score as number ,
category
});
}
}
}
class ServiceRatings {
async completeProject ( projectId : string , clientId : string , providerId : string ) {
const project = await this . getProject ( projectId );
// Close deal
await this . reputation . closeDeal ({
signer: clientId ,
deal_id: project . dealId
});
// Client rates provider
await this . reputation . rate ({
signer: clientId ,
deal_id: project . dealId ,
score: project . clientRating . skill ,
category: 'technical_skill'
});
// Provider rates client
await this . reputation . rate ({
signer: providerId ,
deal_id: project . dealId ,
score: project . providerRating . clarity ,
category: 'requirements_clarity'
});
}
}
Next Steps
Reputation Profiles Learn how ratings build into comprehensive reputation profiles.
Rating API Explore the complete rating management API.
Deal Management Understand the deal lifecycle that enables ratings.
Integration Guide Build rating interfaces for your application.