Skip to main content

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

MethodDescriptionAuth RequiredHTTP Endpoint
sendMessageSend message to AI assistantPOST /marketplace/chat
searchProductsSearch products across marketplacesPOST /marketplace/search
createOrderCreate new orderPOST /marketplace/orders
getOrderGet order detailsGET /marketplace/orders/:order_id
getUserOrdersGet user order historyGET /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 assistant
  • conversation_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 results
  • recipient (object, required): Delivery recipient information
    • name (string, required): Recipient name
    • phone (string, required): Phone number
    • address (string, required): Delivery address
    • email (string, optional): Email address
    • notes (string, optional): Delivery notes
  • wallet_address (string, required): User's wallet address for payment tracking
  • chain_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:

  1. PENDING: Order created, awaiting payment
  2. PAID: Payment confirmed on blockchain
  3. COMPLETED: Product shipped and delivered (manual for MVP)
  4. FAILED: Payment or order processing failed
  5. 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

  1. Maintain conversation history for better AI responses
  2. Handle scraper timeouts gracefully
  3. Verify wallet connection before payment
  4. Monitor pending orders for payment confirmation
  5. Show clear error messages to users
  6. Log all operations for debugging
  7. Test payment flow on testnet before production