Seller tools
Bulk uploads, inventory management, and pricing suggestions
One-by-one listing creation, no inventory management.
- Bulk upload via CSV/spreadsheet
- Inventory dashboard
- Auto-relist sold items
- Pricing suggestions
- Listing templates
- CSV import for multiple items
- Photo batch upload
- Field mapping UI
- Validation and error handling
- All listings in one view
- Filter by status (active, sold, draft)
- Bulk actions (edit, delete, relist)
- Sales analytics per item
- Market price comparison
- Price drop suggestions
- "Sell fast" pricing
- Competitor analysis
- Save listing templates
- Quick duplicate listings
- Category-specific defaults
- Auto-fill common fields
async function importListingsFromCSV(
sellerId: string,
file: File
): Promise<ImportResult> {
const rows = await parseCSV(file);
const results: ImportResult = { success: [], errors: [] };
for (const [index, row] of rows.entries()) {
try {
const validated = listingSchema.parse({
title: row.title,
description: row.description,
price: parseFloat(row.price),
categoryId: await getCategoryId(row.category),
brandId: await getBrandId(row.brand),
conditionId: await getConditionId(row.condition),
photos: row.photos?.split(',').map(url => url.trim()),
});
const item = await createItem(sellerId, validated);
results.success.push({ row: index + 1, itemId: item.id });
} catch (error) {
results.errors.push({ row: index + 1, error: error.message });
}
}
return results;
}
async function bulkUpdateItems(
sellerId: string,
itemIds: string[],
updates: Partial<Item>
) {
// Verify ownership
const items = await db.query.items.findMany({
where: and(
inArray(items.id, itemIds),
eq(items.sellerId, sellerId),
),
});
if (items.length !== itemIds.length) {
throw new Error('Some items not found or not owned');
}
await db.update(items)
.set(updates)
.where(inArray(items.id, itemIds));
}
// Bulk delete
async function bulkDeleteItems(sellerId: string, itemIds: string[]) {
await db.delete(items)
.where(and(
inArray(items.id, itemIds),
eq(items.sellerId, sellerId),
));
}
async function getPriceSuggestion(item: {
title: string;
categoryId: string;
brandId?: string;
conditionId: string;
}): Promise<PriceSuggestion> {
const similarItems = await db.query.items.findMany({
where: and(
eq(items.categoryId, item.categoryId),
item.brandId ? eq(items.brandId, item.brandId) : undefined,
eq(items.status, 'sold'),
),
orderBy: desc(items.soldAt),
limit: 20,
});
if (similarItems.length < 3) {
return { suggestion: null, confidence: 'low' };
}
const prices = similarItems.map(i => i.price);
const avg = prices.reduce((a, b) => a + b, 0) / prices.length;
const median = prices.sort()[Math.floor(prices.length / 2)];
return {
suggestion: Math.round(median),
sellFast: Math.round(median * 0.85),
maximize: Math.round(median * 1.15),
marketRange: { min: Math.min(...prices), max: Math.max(...prices) },
confidence: similarItems.length > 10 ? 'high' : 'medium',
};
}
Build all listings view with status filters and basic bulk actions.
Create CSV import UI with field mapping and error handling.
Implement price suggestion API, market comparison, and price drop alerts.
Add save/load templates, quick duplicate, and auto-fill fields.
- Listings table view
- Status filters
- Search and sort
- Bulk select UI
- Bulk edit modal
- Bulk delete with confirmation
- Bulk relist
- CSV template download
- CSV upload and parse
- Field mapping UI
- Import progress and results
- Price suggestion API
- Suggestion display on listing form
- Market comparison view
On this page