"Jual Bekas, Tawar Langsung" — Indonesian P2P marketplace for preloved & unwanted items with AI-powered instant negotiation.
Like Mercari/Poshmark/Carousell but Indonesian-native: COD-first, WA-integrated, bahasa Indonesia 100%, with AI @tawar agent that negotiates on buyer's behalf so they don't wait hours for seller response.
| belantara.com | belantara.net |
|---|---|
| Product-centric (1 product, many sellers) | Listing-centric (1 item = 1 listing, no stock) |
| New goods, stock-based | Preloved/bekas/unwanted new-in-box |
| Compare prices across sellers | Negotiate price with owner |
| Cart + checkout flow | Single-item buy + offer flow |
| Scraped from Shopee/Tokped | User-generated listings + seed data |
| Resource | Purpose |
|---|---|
| Worker | Main app (SSR + API) |
| D1 | Primary database |
| R2 | User-uploaded photos |
| KV (CACHE) | Page/query cache |
| KV (SESSIONS) | Auth sessions |
| Workers AI | @tawar negotiation agent, photo analysis, description gen |
| Cron | Listing expiry, stale cleanup, stats |
Fork from belantara.com worker-cf, rewrite schema + pages. Keep: layout system, CSS design system (with color palette change), auth (OTP), helpers, CDN image system.
belantara.com = Emerald/Gold (marketplace prosperity) belantara.net = Coral/Teal (personal, friendly, P2P warmth)
--coral: #e8604c (warm, approachable, "deal" energy)
--coral-dark: #c04a38
--coral-light: #fde8e4
--teal: #0d9488 (trust, communication)
--teal-dark: #0f766e
--teal-light: #ccfbf1
--cream: #fdf8f6 (warm background, not cold white)
--card-bg: #fefcfa
-- USERS (buyers & sellers same table, everyone can sell)
users (
id, phone UNIQUE, name, avatar, city, lat, lng,
bio, rating_avg, rating_count, listing_count, sold_count,
wa_verified, ktp_verified, badge_fast_shipper, badge_responsive,
joined_at, last_active
)
-- LISTINGS (1 item = 1 listing, NO stock)
listings (
id, slug UNIQUE, user_id (seller),
title, description, category_id, subcategory_id,
condition ENUM(baru_segel, seperti_baru, bagus, layak_pakai, butuh_perbaikan),
price INTEGER (asking price in IDR),
min_price INTEGER (lowest acceptable, private to seller),
original_price INTEGER (optional, for "was Rp..." display),
brand, size, color,
images TEXT (JSON array of R2 keys, max 12),
delivery_options TEXT (JSON: {cod: bool, kirim: bool, gosend: bool}),
shipping_from_city, shipping_from_lat, shipping_from_lng,
view_count, like_count, chat_count, offer_count,
status ENUM(active, reserved, sold, deleted, expired),
featured_until (paid bump expiry),
expires_at (auto-expire after 30 days if not renewed),
created_at, updated_at
)
-- CATEGORIES (2-level: parent + sub)
categories (
id, parent_id, name, name_en, slug UNIQUE, icon,
listing_count
)
-- OFFERS / NEGOTIATIONS
offers (
id, listing_id, buyer_id, seller_id,
amount INTEGER (offered price),
counter_amount INTEGER (seller counter),
status ENUM(pending, accepted, countered, declined, expired, withdrawn),
message TEXT (buyer's note),
ai_handled INTEGER DEFAULT 0 (was this auto-responded by @tawar agent?),
ai_response TEXT (what AI said),
expires_at (24h auto-expire),
created_at, updated_at
)
-- CHATS (in-app messaging between buyer & seller per listing)
chats (
id, listing_id, buyer_id, seller_id,
created_at
)
chat_messages (
id, chat_id, sender_id,
message TEXT, type ENUM(text, offer, image, system),
offer_id (link to offers table if type=offer),
is_read INTEGER DEFAULT 0,
created_at
)
-- ORDERS (after offer accepted or buy-now)
orders (
id, order_code UNIQUE, listing_id,
buyer_id, seller_id,
amount INTEGER, shipping_cost INTEGER,
delivery_method ENUM(cod, kirim, gosend),
payment_method, payment_status ENUM(pending, paid, escrow, released, refunded),
order_status ENUM(new, confirmed, shipped, delivered, completed, disputed, cancelled),
midtrans_order_id, midtrans_payment_url,
shipping_tracking, meetup_location, meetup_time,
buyer_confirmed_at, auto_release_at (72h after delivery),
notes, created_at, updated_at
)
-- REVIEWS (after order completed)
reviews (
id, order_id, listing_id,
reviewer_id (buyer), reviewed_id (seller),
rating 1-5, comment, images,
created_at
)
-- LIKES / SAVES (wishlist + "offer to likers")
likes (
id, user_id, listing_id, created_at,
UNIQUE(user_id, listing_id)
)
-- REPORTS (fraud/spam flagging)
reports (
id, reporter_id, listing_id, user_id,
reason ENUM(palsu, spam, penipuan, barang_terlarang, lainnya),
description, status ENUM(pending, reviewed, actioned),
created_at
)
-- WA CONVERSATIONS (AI chat state)
wa_conversations (phone PK, name, city, state, context, last_active)
-- OTP
otp_requests (id, phone, code_hash, expires_at, attempts, verified, purpose, created_at)
-- SEARCH HISTORY (for trending)
search_log (id, query, result_count, user_id, created_at)
min_price (private):Kamu adalah agen negosiasi untuk {seller_name} di Belantara.net.
Barang: {title}, Kondisi: {condition}, Harga: Rp{price}
Harga minimum yang bisa diterima: Rp{min_price}
Pembeli menawar: Rp{offer_amount}
Pesan pembeli: {message}
Aturan:
- Jika tawaran >= harga minimum, TERIMA
- Jika tawaran 80-99% dari harga minimum, COUNTER di harga minimum
- Jika tawaran < 80% harga minimum, TOLAK dengan sopan
- Selalu gunakan bahasa Indonesia yang ramah dan kasual
- Jangan pernah ungkapkan harga minimum ke pembeli
Buyer can also send @tawar [listing-id] [harga] via WA to the Belantara.net bot.
| Route | Page | Description |
|---|---|---|
/ |
Home | Hero, trending, newest, categories |
/cari?q=&cat=&kondisi=&kota=&sort=&hmin=&hmax= |
Search | Filtered listing grid |
/kategori |
Categories | All categories grid |
/kategori/:slug |
Category | Listings in category |
/barang/:slug |
Listing Detail | Photos, price, seller, offer button, similar items |
/jual |
Post Listing | Photo upload + AI auto-fill form |
/jual/:id/edit |
Edit Listing | Edit existing listing |
/chat |
Inbox | All conversations |
/chat/:id |
Chat Thread | Messages with buyer/seller |
/profil/:slug |
User Profile | Public profile, listings, reviews |
/profil/saya |
My Profile | Dashboard, my listings, orders, stats |
/pesanan |
Orders | Buy/sell order history |
/pesanan/:code |
Order Detail | Status tracking |
/checkout/:listing_id |
Checkout | Pay for accepted offer |
/akun |
Account Settings | Profile edit, preferences |
| Endpoint | Method | Description |
|---|---|---|
/api/listings |
GET | Search/filter listings |
/api/listings |
POST | Create listing (auth) |
/api/listings/:id |
GET | Listing detail |
/api/listings/:id |
PUT | Update listing (auth, owner) |
/api/listings/:id |
DELETE | Delete listing (auth, owner) |
/api/listings/:id/like |
POST | Like/unlike toggle |
/api/listings/:id/offer |
POST | Make an offer |
/api/offers/:id |
PUT | Accept/counter/decline offer |
/api/upload |
POST | Upload photos to R2 |
/api/chat/:listing_id |
GET/POST | Get/send messages |
/api/orders |
POST | Create order |
/api/orders/:code |
GET/PUT | Order detail/update |
/api/users/me |
GET/PUT | Profile |
/api/users/:slug |
GET | Public profile |
/api/auth/otp/request |
POST | Request OTP |
/api/auth/otp/verify |
POST | Verify OTP, get JWT |
/api/tawar |
POST | AI negotiation endpoint |
/api/webhooks/midtrans |
POST | Payment callback |
/api/wa/webhook |
POST | WA relay webhook |
/api/admin/* |
* | Admin endpoints |
Scrape active preloved/bekas listings (NOT store inventory) from:
Shopee — filter by condition=used or category "Preloved"
Tokopedia — filter by condition=2 (Bekas/Used)
users from seller data (name, city, rating)listing (1 item each)platform_source: shopee|tokopedia for attribution1. Fashion Wanita (Atasan, Celana, Dress, Jaket, Sepatu, Tas, Aksesoris, Hijab)
2. Fashion Pria (Kemeja, Celana, Sepatu, Sneakers, Jaket, Tas, Jam Tangan)
3. HP & Gadget (Smartphone, Tablet, Earphone, Charger, Casing, Smartwatch)
4. Elektronik (Laptop, TV, Speaker, Kamera, Konsol Game)
5. Kecantikan (Skincare, Makeup, Parfum, Hair Care, Tools)
6. Bayi & Anak (Baju Bayi, Stroller, Mainan, Perlengkapan)
7. Rumah & Dapur (Perabot, Dekorasi, Alat Masak, Storage)
8. Buku & ATK (Novel, Buku Pelajaran, Komik, Majalah, ATK)
9. Olahraga (Sepeda, Gym, Outdoor, Jersey, Sepatu Olahraga)
10. Hobi & Koleksi (Action Figures, Lego, Board Games, Vinyl, Koin)
11. Otomotif (Sparepart, Aksesoris Mobil, Aksesoris Motor, Helm)
12. Gaming (Konsol, Game Bekas, Aksesoris, PC Parts)
13. Muslim Fashion (Gamis, Koko, Mukena, Sajadah, Peci)
14. Luxury & Vintage (Tas Branded, Jam Mewah, Antik, Vintage)
15. Lainnya (Tiket, Voucher, Alat Musik, Pet Supplies)
+------------------+
| [PHOTO 4:5] |
| "SEPERTI BARU" | (condition badge, top-left overlay)
| "2 jam lalu" | (time badge, top-right)
+------------------+
| Rp 350.000 | (price, bold)
| ~~Rp 500.000~~ | (original price, strikethrough)
| Kaos Nike Dri... | (title, 2 lines max)
| Jakarta Selatan | (city, small gray)
| ♡ 5 💬 2 | (likes, chats count)
+------------------+
[PHOTO CAROUSEL with dots]
[Share] [Like ♡]
Rp 350.000 (kondisi: Seperti Baru)
~~Harga Asli: Rp 500.000~~ -30%
Kaos Nike Dri-FIT Original
"Beli di store, cuma pakai 2x, ukuran kebesaran..."
Kategori: Fashion Pria > Kaos
Ukuran: L | Warna: Hitam
Pengiriman: COD, JNE, GoSend
── Penjual ──
[Avatar] @budisport (★4.8, 23 terjual)
Jakarta Selatan | Online 5 menit lalu
[Chat] [Lihat Profil]
── Barang Serupa ──
[horizontal scroll of similar items]
═══════════════════════
[STICKY BOTTOM BAR]
[Chat Penjual] [Tawar 💬] [Beli Langsung]
═══════════════════════
┌─────────────────────────┐
│ Tawar Harga │
│ │
│ Harga penjual: Rp350.000│
│ │
│ Tawaran kamu: │
│ [Rp ___________] │
│ │
│ Pesan (opsional): │
│ [_________________] │
│ │
│ [Kirim Tawaran] │
│ │
│ AI @tawar akan bantu │
│ negosiasi jika penjual │
│ tidak online │
└─────────────────────────┘
Step 1: [Take Photo / Gallery] (up to 12 photos)
AI auto-analyzes first photo...
Step 2: [Title] (AI pre-filled)
[Description] (AI pre-filled)
[Category] (AI suggested)
[Condition ▼] (5 options)
[Brand] (optional)
[Size] (optional)
[Color] (optional)
Step 3: [Harga Jual: Rp ____]
[Harga Minimum: Rp ____] (opsional, rahasia)
"AI @tawar otomatis tolak tawaran di bawah harga minimum"
[Harga Asli: Rp ____] (opsional, untuk diskon display)
Step 4: [Pengiriman ✓]
☑ COD / Ketemuan
☑ Kirim (JNE/J&T/SiCepat)
☑ GoSend/GrabExpress (sekota)
Lokasi: [Kota ▼]
Step 5: [PASANG IKLAN] 🎉
| Revenue Stream | Price | Notes |
|---|---|---|
| Listing bumps (Angkat) | Rp5,000-20,000 | Push to top of feed for 24-48h |
| Spotlight (Sorotan) | Rp25,000 | Featured banner on category page |
| Transaksi Aman fee | 5% of sale | Escrow protection on shipped items |
| COD/Direct | FREE | No fee, no protection |
This domain MUST operate within these constraints — no exceptions:
If the plan above describes any flow that violates these constraints, treat the plan as ASPIRATIONAL only and rework before building. The constraint trifecta wins.
Ask AI to research, improve, or generate content.
Try: "Research competitors for this niche"