Marketplace Module
The marketplace module provides AI-powered conversational commerce functionality enabling users to discover, search, and purchase products from multiple marketplaces (Etsy, Tokopedia) using natural language and pay with USDC cryptocurrency. Built for seamless cross-border shopping with blockchain payment integration.
Import
const marketplace = await brdzSDK.marketplace;
Methods Overview
| Method | Description | Auth Required | HTTP Endpoint |
|---|---|---|---|
sendMessage | Send message to AI assistant | ❌ | POST /marketplace/chat |
searchProducts | Search products across marketplaces | ❌ | POST /marketplace/search |
createOrder | Create new order | ✅ | POST /marketplace/orders |
getOrder | Get order details | ✅ | GET /marketplace/orders/:order_id |
getUserOrders | Get user order history | ✅ | GET /marketplace/orders |
Chat Operations
sendMessage
Interact with AI-powered shopping assistant using natural language. Powered by Groq AI (Llama 3.1 70B) with intent detection (SEARCH, BUY, INFO, HELP).
const chat = await brdzSDK.marketplace;
// First message
const response1 = await chat.sendMessage({
message: "I'm looking for a gift for my girlfriend"
});
console.log('AI:', response1.reply);
console.log('Intent:', response1.intent); // INFO, SEARCH, BUY, HELP
// Continue conversation with history
const response2 = await chat.sendMessage({
message: "She likes handmade jewelry",
conversation_history: [
{
role: "user",
content: "I'm looking for a gift for my girlfriend"
},
{
role: "assistant",
content: response1.reply
}
]
});
console.log('AI:', response2.reply);
// Token usage tracking
console.log(`Tokens used: ${response2.usage.total_tokens}`);
Parameters:
message(string, required): User's message to the AI assistantconversation_history(array, optional): Previous conversation messages for context (default: [])
Returns: AI response with reply, intent detection, and token usage
Response Structure:
{
success: true,
reply: "AI assistant's response text",
intent: "SEARCH", // SEARCH, BUY, INFO, HELP
usage: {
prompt_tokens: 245,
completion_tokens: 128,
total_tokens: 373
}
}
Search Operations
searchProducts
Search for products across Etsy (USD) and Tokopedia (IDR) marketplaces. Uses AI-powered query generation to optimize search results. Products are normalized into unified schema with automatic currency conversion for IDR items.
const marketplace = await brdzSDK.marketplace;
// Basic search (Etsy only)
const results1 = await marketplace.searchProducts({
query: "handmade ceramic mug"
});
console.log(`Found ${results1.count} products`);
// Multi-marketplace search
const results2 = await marketplace.searchProducts({
query: "ceramic travel mug",
sources: ["etsy", "tokopedia"],
limit: 20
});
// Display products
results2.products.forEach((product, index) => {
console.log(`\n${index + 1}. ${product.title}`);
console.log(` Price: ${product.pricing.currency} ${product.pricing.total}`);
console.log(` Source: ${product.source}`);
console.log(` Shop: ${product.vendor.shop_name}`);
// Show original price for IDR products
if (product.pricing.original_currency === 'IDR') {
console.log(` Original: IDR ${product.pricing.original_price.toLocaleString()}`);
console.log(` FX Rate: ${product.pricing.fx_rate}`);
}
console.log(` Rating: ${product.metadata?.rating || 'N/A'}`);
console.log(` URL: ${product.url}`);
});
// Filter by price
const affordableProducts = results2.products.filter(
p => p.pricing.total < 30
);
console.log(`\n${affordableProducts.length} products under $30`);
// AI-generated search queries
console.log(`\nAI Search Queries Used:`);
results2.search_queries.forEach(q => console.log(` - ${q}`));
Parameters:
query(string, required): Search query (e.g., 'handmade ceramic mug')sources(array, optional): Marketplaces to search: ['etsy', 'tokopedia'] (default: ['etsy'])limit(number, optional): Maximum products to return (default: 10, max: 50)
Returns: Normalized products with unified schema, sorted by price
Response Structure:
{
success: true,
query: "handmade ceramic travel mug",
products: [
{
productId: "etsy-123456",
title: "Handmade Ceramic Travel Mug",
description: "Beautiful handcrafted ceramic...",
image: "https://i.etsystatic.com/...",
images: ["https://i.etsystatic.com/..."],
source: "etsy",
url: "https://www.etsy.com/listing/123456",
vendor: {
name: "Etsy - PotteryShop",
marketplace: "etsy",
shop_name: "PotteryShop",
shop_url: "https://www.etsy.com/shop/PotteryShop"
},
pricing: {
price: 28.50,
currency: "USD",
original_price: 28.50,
shipping: 5.00,
total: 33.50
},
availability: "in_stock",
metadata: {
rating: 4.8,
num_favorers: 1250,
tags: ["ceramic", "handmade", "travel mug"]
}
}
],
count: 10,
search_queries: [
"handmade ceramic travel mug",
"pottery travel cup"
]
}
Order Operations
createOrder
Create a new marketplace order for selected product. Calculates USDC payment amount with automatic FX conversion for IDR products. Saves order to database with PENDING status.
const marketplace = await brdzSDK.marketplace;
// Step 1: Search products
const searchResults = await marketplace.searchProducts({
query: "handmade ceramic mug",
sources: ["etsy"]
});
// Step 2: Select product
const selectedProduct = searchResults.products[0];
// Step 3: Create order
const order = await marketplace.createOrder({
product: selectedProduct,
recipient: {
name: "John Doe",
phone: "+628123456789",
address: "Jl. Sudirman No. 123, Jakarta Selatan 12190, Indonesia",
email: "john@example.com",
notes: "Please call before delivery"
},
wallet_address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
chain_id: "sepolia"
});
console.log('Order created:', order.order.order_id);
console.log(`Pay: ${order.payment_details.usdc_amount} USDC`);
console.log('Contract:', order.payment_details.contract_address);
// Step 4: Execute payment (using Web3)
const Web3 = require('web3');
const web3 = new Web3(window.ethereum);
const BRDZ_PAYMENT_ABI = [{
"inputs": [
{"type": "address", "name": "brdzWallet"},
{"type": "uint256", "name": "amount"},
{"type": "string", "name": "orderId"}
],
"name": "completePayment",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}];
const contract = new web3.eth.Contract(
BRDZ_PAYMENT_ABI,
order.payment_details.contract_address
);
const amountInWei = web3.utils.toWei(
order.payment_details.usdc_amount.toString(),
'mwei' // USDC has 6 decimals
);
// Execute payment
const tx = await contract.methods
.completePayment(
order.payment_details.wallet_address,
amountInWei,
order.order.order_id
)
.send({ from: userWalletAddress });
console.log('Payment TX:', tx.transactionHash);
Parameters:
product(object, required): Product details from search resultsrecipient(object, required): Delivery recipient informationname(string, required): Recipient namephone(string, required): Phone numberaddress(string, required): Delivery addressemail(string, optional): Email addressnotes(string, optional): Delivery notes
wallet_address(string, required): User's wallet address for payment trackingchain_id(string, optional): Blockchain network (default: 'sepolia')
Returns: Order details with payment information
Response Structure:
{
success: true,
order: {
order_id: "BRDZ-1705308000000-a1b2c3d4",
user_id: 456,
product_data: { ... },
vendor_data: { ... },
pricing_data: {
original_price: 28.50,
original_currency: "USD",
usd_amount: 33.50,
usdc_amount: 33.50,
shipping: 5.00,
total_usd: 33.50
},
recipient_data: { ... },
payment_token: "USDC",
token_amount: 33.50,
payment_status: "PENDING",
created_at: "2024-01-15T10:00:00Z"
},
payment_details: {
order_id: "BRDZ-1705308000000-a1b2c3d4",
usdc_amount: 33.50,
contract_address: "0x7E93334bf4Cd3Bd15D2203D7E6d5A59A891C4a48",
chain_id: "sepolia",
wallet_address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}
}
getOrder
Retrieve complete order details including product info, pricing, recipient data, payment status, and blockchain transaction hash. Users can only access their own orders.
const marketplace = await brdzSDK.marketplace;
const order = await marketplace.getOrder('BRDZ-1705308000000-a1b2c3d4');
console.log('Order ID:', order.order.order_id);
console.log('Status:', order.order.payment_status);
console.log('Amount:', order.order.token_amount, 'USDC');
// Display product info
console.log('\nProduct:');
console.log(' Title:', order.order.product_data.title);
console.log(' Source:', order.order.product_data.source);
console.log(' URL:', order.order.product_data.url);
// Display recipient info
console.log('\nRecipient:');
console.log(' Name:', order.order.recipient_data.name);
console.log(' Phone:', order.order.recipient_data.phone);
console.log(' Address:', order.order.recipient_data.address);
// Payment tracking
if (order.order.blockchain_tx_hash) {
const explorerUrl = `https://sepolia.etherscan.io/tx/${order.order.blockchain_tx_hash}`;
console.log('\nTransaction:', explorerUrl);
}
// Status timeline
console.log('\nTimeline:');
console.log(' Created:', order.order.created_at);
if (order.order.paid_at) {
console.log(' Paid:', order.order.paid_at);
}
if (order.order.completed_at) {
console.log(' Completed:', order.order.completed_at);
}
Parameters:
order_id(string, required): Order ID (format: BRDZ-{timestamp}-{uuid})
Returns: Complete order details
Response Structure:
{
success: true,
order: {
order_id: "BRDZ-1705308000000-a1b2c3d4",
user_id: 456,
product_data: { ... },
vendor_data: { ... },
pricing_data: { ... },
recipient_data: { ... },
payment_token: "USDC",
token_amount: 33.50,
payment_status: "PAID",
blockchain_tx_hash: "0xabc123...",
created_at: "2024-01-15T10:00:00Z",
paid_at: "2024-01-15T10:05:00Z",
completed_at: null
}
}
getUserOrders
Retrieve paginated order history for authenticated user. Supports filtering by payment status.
const marketplace = await brdzSDK.marketplace;
// Get recent orders (default: 10)
const orders = await marketplace.getUserOrders();
console.log(`Total orders: ${orders.pagination.total}`);
console.log(`Showing: ${orders.orders.length}`);
// Display orders
orders.orders.forEach((order, index) => {
console.log(`\n${index + 1}. ${order.product_data.title}`);
console.log(` Order ID: ${order.order_id}`);
console.log(` Amount: ${order.pricing_data.usdc_amount} USDC`);
console.log(` Status: ${order.payment_status}`);
console.log(` Source: ${order.product_data.source}`);
console.log(` Created: ${order.created_at}`);
});
// Pagination
if (orders.pagination.has_more) {
console.log('\nLoading more orders...');
const nextPage = await marketplace.getUserOrders({
limit: 10,
offset: 10
});
console.log(`Next page: ${nextPage.orders.length} orders`);
}
// Filter by status
const pendingOrders = await marketplace.getUserOrders({
status: 'PENDING',
limit: 50
});
console.log(`\nPending orders: ${pendingOrders.orders.length}`);
const completedOrders = await marketplace.getUserOrders({
status: 'COMPLETED',
limit: 50
});
console.log(`Completed orders: ${completedOrders.orders.length}`);
// Calculate total spending
const totalSpent = orders.orders
.filter(o => o.payment_status !== 'FAILED' && o.payment_status !== 'CANCELLED')
.reduce((sum, o) => sum + o.pricing_data.usdc_amount, 0);
console.log(`\nTotal spent: ${totalSpent.toFixed(2)} USDC`);
Parameters:
limit(number, optional): Maximum orders to return (default: 10, max: 100)offset(number, optional): Number of orders to skip (default: 0)status(string, optional): Filter by status: PENDING, PAID, COMPLETED, FAILED, CANCELLED
Returns: Paginated order list
Response Structure:
{
success: true,
orders: [
{
order_id: "BRDZ-1705308000000-a1b2c3d4",
user_id: 456,
product_data: {
id: "etsy-123456",
title: "Handmade Ceramic Travel Mug",
image: "https://i.etsystatic.com/...",
source: "etsy"
},
vendor_data: {
name: "Etsy - PotteryShop",
marketplace: "etsy"
},
pricing_data: {
usdc_amount: 33.50,
original_currency: "USD"
},
payment_status: "PAID",
blockchain_tx_hash: "0xabc123...",
created_at: "2024-01-15T10:00:00Z",
paid_at: "2024-01-15T10:05:00Z"
}
],
pagination: {
total: 15,
limit: 10,
offset: 0,
has_more: true
}
}
Complete Usage Examples
Conversational Product Discovery
// Complete AI-assisted shopping flow
async function conversationalShopping() {
const marketplace = await brdzSDK.marketplace;
const conversationHistory = [];
console.log('=== AI Shopping Assistant ===\n');
// Step 1: Initial conversation
const chat1 = await marketplace.sendMessage({
message: "I need a birthday gift for my mom"
});
console.log('You: I need a birthday gift for my mom');
console.log(`AI: ${chat1.reply}\n`);
conversationHistory.push(
{ role: "user", content: "I need a birthday gift for my mom" },
{ role: "assistant", content: chat1.reply }
);
// Step 2: Provide more context
const chat2 = await marketplace.sendMessage({
message: "She loves gardening and handmade pottery",
conversation_history: conversationHistory
});
console.log('You: She loves gardening and handmade pottery');
console.log(`AI: ${chat2.reply}\n`);
// Step 3: AI suggests search
if (chat2.intent === 'SEARCH') {
console.log('AI detected SEARCH intent - proceeding to product search\n');
// Step 4: Search products
const searchResults = await marketplace.searchProducts({
query: "handmade pottery planter",
sources: ["etsy", "tokopedia"],
limit: 10
});
console.log(`Found ${searchResults.count} products:\n`);
searchResults.products.slice(0, 3).forEach((product, index) => {
console.log(`${index + 1}. ${product.title}`);
console.log(` Price: $${product.pricing.total}`);
console.log(` Shop: ${product.vendor.shop_name}\n`);
});
return searchResults;
}
}
// Usage
await conversationalShopping();
Complete Purchase Flow
// End-to-end purchase workflow
async function completePurchaseFlow(searchQuery) {
const marketplace = await brdzSDK.marketplace;
console.log('=== Complete Purchase Flow ===\n');
try {
// Step 1: Search products
console.log('Step 1: Searching products...');
const searchResults = await marketplace.searchProducts({
query: searchQuery,
sources: ["etsy"],
limit: 5
});
if (searchResults.products.length === 0) {
throw new Error('No products found');
}
console.log(`Found ${searchResults.count} products\n`);
// Step 2: Select product
const selectedProduct = searchResults.products[0];
console.log('Step 2: Product selected:');
console.log(` ${selectedProduct.title}`);
console.log(` Price: $${selectedProduct.pricing.total}\n`);
// Step 3: Create order
console.log('Step 3: Creating order...');
const order = await marketplace.createOrder({
product: selectedProduct,
recipient: {
name: "Jane Smith",
phone: "+628123456789",
address: "Jl. Sudirman No. 456, Jakarta",
email: "jane@example.com"
},
wallet_address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
chain_id: "sepolia"
});
console.log(`Order created: ${order.order.order_id}`);
console.log(`Amount: ${order.payment_details.usdc_amount} USDC\n`);
// Step 4: Execute payment
console.log('Step 4: Processing payment...');
console.log('(Execute Web3 transaction here)');
return order;
} catch (error) {
console.error(`Purchase failed: ${error.message}`);
throw error;
}
}
// Usage
await completePurchaseFlow("handmade ceramic planter");
Order Tracking Dashboard
// Build order tracking dashboard
async function orderTrackingDashboard() {
const marketplace = await brdzSDK.marketplace;
console.log('=== Order Tracking Dashboard ===\n');
// Get all orders
const allOrders = await marketplace.getUserOrders({
limit: 100
});
// Calculate statistics
const stats = {
total: allOrders.pagination.total,
pending: 0,
paid: 0,
completed: 0,
failed: 0,
totalSpent: 0
};
allOrders.orders.forEach(order => {
stats[order.payment_status.toLowerCase()]++;
if (['PAID', 'COMPLETED'].includes(order.payment_status)) {
stats.totalSpent += order.pricing_data.usdc_amount;
}
});
// Display dashboard
console.log('📊 Order Statistics:');
console.log(` Total Orders: ${stats.total}`);
console.log(` Pending: ${stats.pending}`);
console.log(` Paid: ${stats.paid}`);
console.log(` Completed: ${stats.completed}`);
console.log(` Failed: ${stats.failed}`);
console.log(` Total Spent: ${stats.totalSpent.toFixed(2)} USDC\n`);
// Recent orders
console.log('📦 Recent Orders:');
allOrders.orders.slice(0, 5).forEach((order, index) => {
const statusEmoji = {
'PENDING': '⏳',
'PAID': '✅',
'COMPLETED': '🎉',
'FAILED': '❌'
};
console.log(`${index + 1}. ${statusEmoji[order.payment_status]} ${order.product_data.title}`);
console.log(` ${order.pricing_data.usdc_amount} USDC - ${order.payment_status}\n`);
});
return stats;
}
// Usage
await orderTrackingDashboard();
Multi-Marketplace Price Comparison
// Compare prices across marketplaces
async function priceComparison(searchQuery) {
const marketplace = await brdzSDK.marketplace;
console.log(`=== Price Comparison: "${searchQuery}" ===\n`);
// Search both marketplaces
const results = await marketplace.searchProducts({
query: searchQuery,
sources: ["etsy", "tokopedia"],
limit: 20
});
// Separate by marketplace
const etsyProducts = results.products.filter(p => p.source === 'etsy');
const tokopediaProducts = results.products.filter(p => p.source === 'tokopedia');
console.log(`Etsy: ${etsyProducts.length} products`);
console.log(`Tokopedia: ${tokopediaProducts.length} products\n`);
// Price analysis
const getPriceStats = (products) => {
const prices = products.map(p => p.pricing.total);
return {
min: Math.min(...prices),
max: Math.max(...prices),
avg: prices.reduce((a, b) => a + b, 0) / prices.length
};
};
const etsyStats = getPriceStats(etsyProducts);
const tokopediaStats = getPriceStats(tokopediaProducts);
console.log('💰 Price Analysis:');
console.log('\nEtsy (USD):');
console.log(` Min: $${etsyStats.min.toFixed(2)}`);
console.log(` Max: $${etsyStats.max.toFixed(2)}`);
console.log(` Avg: $${etsyStats.avg.toFixed(2)}`);
console.log('\nTokopedia (converted to USD):');
console.log(` Min: $${tokopediaStats.min.toFixed(2)}`);
console.log(` Max: $${tokopediaStats.max.toFixed(2)}`);
console.log(` Avg: $${tokopediaStats.avg.toFixed(2)}`);
// Best deals
const allProducts = [...etsyProducts, ...tokopediaProducts]
.sort((a, b) => a.pricing.total - b.pricing.total);
console.log('\n🏆 Top 3 Best Deals:');
allProducts.slice(0, 3).forEach((product, index) => {
console.log(`${index + 1}. ${product.title}`);
console.log(` $${product.pricing.total} (${product.source})\n`);
});
return { etsy: etsyStats, tokopedia: tokopediaStats };
}
// Usage
await priceComparison("ceramic coffee mug");
Conversation Manager
// Maintain conversation context
class ConversationManager {
constructor() {
this.history = [];
this.maxHistory = 10;
}
async sendMessage(message) {
const marketplace = await brdzSDK.marketplace;
const response = await marketplace.sendMessage({
message,
conversation_history: this.history.slice(-this.maxHistory * 2)
});
// Add to history
this.history.push(
{ role: "user", content: message },
{ role: "assistant", content: response.reply }
);
return response;
}
clearHistory() {
this.history = [];
}
getIntent() {
return this.history.length > 0
? this.history[this.history.length - 1].intent
: null;
}
}
// Usage
const chat = new ConversationManager();
await chat.sendMessage("I need a gift");
await chat.sendMessage("For my girlfriend");
await chat.sendMessage("She likes pottery");
Error Handling
// Comprehensive error handler
class MarketplaceErrorHandler {
static async safeOperation(operation, fallback = null) {
try {
return await operation();
} catch (error) {
return this.handleError(error, fallback);
}
}
static handleError(error, fallback = null) {
const errorMap = {
'Message required': {
userMessage: 'Please enter a message',
action: 'RETRY'
},
'Search query required': {
userMessage: 'Please enter a search term',
action: 'RETRY'
},
'Authentication required': {
userMessage: 'Please log in to continue',
action: 'LOGIN'
},
'Access denied': {
userMessage: 'You can only view your own orders',
action: 'REDIRECT',
fallback: '/my-orders'
},
'Order not found': {
userMessage: 'Order not found',
action: 'REDIRECT',
fallback: '/orders'
}
};
const errorKey = Object.keys(errorMap).find(key =>
error.message.includes(key)
);
const errorInfo = errorMap[errorKey] || {
userMessage: 'Something went wrong. Please try again.',
action: 'RETRY',
fallback: fallback
};
console.error('Error:', error.message);
console.log('User message:', errorInfo.userMessage);
return {
success: false,
error: error.message,
userMessage: errorInfo.userMessage,
action: errorInfo.action,
fallback: errorInfo.fallback
};
}
}
// Usage
const result = await MarketplaceErrorHandler.safeOperation(
() => marketplace.createOrder(orderData),
'/products'
);
if (!result.success) {
alert(result.userMessage);
switch (result.action) {
case 'LOGIN':
window.location.href = '/login';
break;
case 'REDIRECT':
window.location.href = result.fallback;
break;
}
}
Payment Execution Helper
// Complete payment execution with error handling
class PaymentExecutor {
constructor(web3Provider) {
this.web3 = new Web3(web3Provider);
this.contractABI = [{
"inputs": [
{"type": "address", "name": "brdzWallet"},
{"type": "uint256", "name": "amount"},
{"type": "string", "name": "orderId"}
],
"name": "completePayment",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}];
}
async executePayment(order, userAddress) {
try {
const { usdc_amount, contract_address, wallet_address, order_id } = order.payment_details;
const contract = new this.web3.eth.Contract(
this.contractABI,
contract_address
);
const amountInWei = this.web3.utils.toWei(
usdc_amount.toString(),
'mwei'
);
console.log('Executing payment...');
console.log(`Amount: ${usdc_amount} USDC`);
const tx = await contract.methods
.completePayment(wallet_address, amountInWei, order_id)
.send({ from: userAddress });
console.log('Payment successful!');
console.log(`TX Hash: ${tx.transactionHash}`);
return {
success: true,
txHash: tx.transactionHash
};
} catch (error) {
console.error('Payment failed:', error.message);
return {
success: false,
error: error.message
};
}
}
}
// Usage
const paymentExecutor = new PaymentExecutor(window.ethereum);
const result = await paymentExecutor.executePayment(order, userWalletAddress);
Order Status Flow
The order processing follows these states:
- PENDING: Order created, awaiting payment
- PAID: Payment confirmed on blockchain
- COMPLETED: Product shipped and delivered (manual for MVP)
- FAILED: Payment or order processing failed
- CANCELLED: Order cancelled by user or system
Marketplace Support
Supported marketplaces for product search:
- Etsy (International): USD products, international shipping
- Tokopedia (Indonesia): IDR products with auto FX conversion, domestic shipping
Payment Configuration
Smart contract payment details:
- Contract: BRDZPayment.sol
- Address:
0x7E93334bf4Cd3Bd15D2203D7E6d5A59A891C4a48 - Network: Sepolia testnet (production will use mainnet)
- Token: USDC (6 decimals)
- Event: PaymentCompleted (auto-monitored by blockchain relayer)
Important Notes
- Chat and search endpoints do not require authentication
- Order operations require authentication with valid JWT token
- Users can only access their own orders
- Product availability is scraped in real-time but may change
- IDR products automatically converted to USDC using FX service
- Blockchain relayer automatically monitors payment events
- Order fulfillment is manual for MVP (admin must contact merchant)
Best Practices
- Maintain conversation history for better AI responses
- Handle scraper timeouts gracefully
- Verify wallet connection before payment
- Monitor pending orders for payment confirmation
- Show clear error messages to users
- Log all operations for debugging
- Test payment flow on testnet before production