Kaspa Forge
Deep dive

How Kaspa Marketplace Moderation, Search & Reputation Work

20 Aug 2026 By OfficeForge's AI team · human-reviewed 9 min read
Kaspa Marketplace Moderation, Search & Reputation

Kaspa Marketplace moderation is a three-layer system: AI-assisted content review that runs before any listing goes live, full-text search powered by SQLite FTS5 for buyer discovery, and opt-in seller reputation whose scores derive from on-chain escrow outcomes — not from platform-side ratings. The critical design choice is that marketplace metadata (titles, descriptions, photos, moderation verdicts) never controls escrowed funds. A listing is a bulletin board entry; the money lives in a separate on-chain covenant contract. This article walks through each layer, how they connect, and where the current boundaries are.

When a buyer opens the marketplace, the server renders listings server-side. The GET /api/safe/market/share endpoint produces pages with Open Graph tags — the foundation of any crypto marketplace SEO approach, since search engines and social previews see real content rather than a JavaScript shell.

Search runs on SQLite's FTS5 extension. The listings_fts table indexes title and description using the unicode61 tokenizer with diacritics removed, supporting both Latin and Cyrillic scripts. When a query arrives with a non-empty q parameter, the server routes it through FTS5's bm25 ranking algorithm with double weight on the title field. Prefix matching works across both alphabets: typing "camer" surfaces "Camera"; typing "СЕРВ" surfaces "сервис". User-supplied FTS syntax is stripped during tokenization — buyers cannot inject raw FTS5 operators.

Definition

FTS5 sync. INSERT, UPDATE, and DELETE on the listings table fire database triggers that keep the FTS index current. On startup, a self-heal check compares FTS shadow tables against the actual _docsize and rebuilds if they diverge — covering databases that existed before FTS was added.

If FTS5 fails for any reason — corruption, tokenizer error — the system silently falls back to a substring scan. Explicit price sorts are preserved even under search, so a buyer sorting by lowest price gets that order regardless of relevance ranking.

Browse is constrained at the database level: limit is always 1–100 (default 100), and all filtering — category, price range, Unicode case-insensitive substring, sort, offset, count — happens inside SQLite. The Rust server receives only the page of results.

The AI Moderation Pipeline

Every listing creation or edit enters pending_moderation status and returns immediately to the seller. A durable background worker (run_moderation_worker in listings.rs) picks up all rows without a verdict, including those left behind after a server restart.

The worker sends listing text to an OpenAI-compatible /chat/completions endpoint with temperature 0 and a system prompt (MODERATION_SOUL) that explicitly names reject categories: spam, pornography, malware, phishing, credential theft, stolen accounts, pirated content, and access-bypass tools. Obfuscation is judged by meaning, not keyword matching. Borderline cases receive a needs_review verdict rather than a pass.

For listings with photos, the request goes to a dedicated vision channel. Unreadable images downgrade an approved verdict to needs_review. All inputs — listing text, EXIF/metadata, and OCR-recognized text from images — are treated as untrusted data. Prompt injection cannot alter the moderation policy or the JSON response schema.

The verdict is written in a single guarded SQL update:

approved  → status becomes `published`
rejected  → status becomes `rejected`
anything  → status stays `pending_moderation`

The third case is a fail-safe: the listing is silently not published. A late model response never overwrites a manual human decision. needs_review triggers a Telegram alert to the arbiter bot.

Transport, config, or parser failures trigger durable exponential backoff (default 3 attempts, at 15- and 30-second intervals). After exhaustion, the listing stays unpublished and is flagged once for human review.

Admin surfaces

Two admin surfaces share a single authorization gate (admin_ok): a desktop web panel behind nginx basic-auth, and a Telegram Mini App inside the arbiter's private bot. The gate accepts either an admin token or a HMAC-verified Telegram initData payload tied to the arbiter's chat ID, with 24-hour anti-replay.

Admins can approve a listing — republishing it with a fresh 30-day window — or delete it, wiping photos and setting status to deleted. Rejected listings that are not manually approved within a configurable TTL (default 24 hours) are swept by a background loop and permanently deleted.

Seller Reputation: On-Chain Outcomes, Not Platform Ratings

Kaspa seller reputation is voluntary and disabled by default. The marketplace is anonymous by design — each listing uses fresh keys, so there is no inherent link between a seller's listings unless they opt in.

Enrollment works through a challenge-response protocol. Desk derives a reputation keypair from the master seed (domain kaspaforge/v1/reputation/0, index 0), requests a nonce from the server, and returns a BIP340 signature. This keypair is cryptographically separate from the Desk Sync identity — different derivation domain, no correlation.

Deal linking is forward-only. At listing creation, Desk attaches an attestation binding the reputation public key to the seller's key. The server validates this before spawning the deal and records the link in a rep_links table. There is no retroactive linking — this prevents cherry-picking favorable past outcomes.

Outcome classification from the chain

The server does not know how an escrow closed. The arbiter judges offline; the AI mediator verdict is reference-only. After an escrow deal closes, the watcher reads the spending transaction from the indexer and parses the covenant path selector from the signature script:

0 = release       1 = refund        2 = mutual
3 = dispute       4 = autoRelease
5 = arb→buyer     6 = arb→seller    7 = arb→split
8 = timeout       9 = timeout

Cross-checking the output layout produces outcome_kind, pct, and src in the deals table. The server retries for 48 hours; if the outcome cannot be determined, it is marked unknown. This runs on mainnet only.

Aggregated metrics — successful deals, refunds, disputes with breakdown, total deals, enrollment date — are cached with a 60-second TTL. Cache misses for the same rep_pk collapse into a single flight to avoid stampedes. The bounded cache evicts the oldest entries without a global clear.

Sellers manage their reputation from Desk → Settings → Seller rating: enable, pause (badge hidden, history accumulates), or delete (irreversible, all-or-nothing — cannot selectively erase disputes). A seller who deletes and re-enrolls with the same keypair starts from zero.

Why Marketplace Metadata Never Touches Escrowed Funds

This is the most important architectural point in the system.

Definition

Escrow-backed listing. A marketplace listing connected to a separate on-chain escrow covenant via a join_code. The listing is a bulletin board entry in a platform database. The escrow contract is a Kaspa covenant enforced by consensus. The platform can moderate the listing; it cannot move the funds.

When a listing is created, the server spawns a draft escrow deal through the same Deals::create_deal path used by standalone Kaspa Escrow — there is no parallel money logic. A random 12-character join_code connects the listing to the deal.

When a buyer checks out (POST /api/safe/listings/:id/checkout), the server creates a distinct deal with a fresh request_id and writes an idempotent link in listing_orders. Repeated requests with the same request_id return the same join_code.

Editing a listing atomically revokes the old join_code and all unused buyer-order capabilities, transfers photo refs, and returns the listing to pending_moderation. The old conditions cannot be purchased through a copied link. Any funded buyer-order or funded canonical deal blocks editing entirely — the check runs inside the same SQLite transaction.

For repeatable listings, the watcher automatically re-issues the listing on a fresh deal after each funding. For non-repeatable listings, funding moves the status to reserved, and deal completion closes the listing.

If the marketplace server goes offline, in-progress escrow deals survive on-chain. The covenant paths — release, refund, dispute, timeout — are enforced by Kaspa's consensus layer (Kaspa wiki), not by the marketplace. This is the non-custodial guarantee: marketplace moderation can reject a listing, but it cannot freeze, redirect, or confiscate escrowed KAS.

Browse live listings or create your own at Kaspa Marketplace. Every listing is backed by an escrow contract — funds live on-chain, not in a platform database. Seller keys stay on your device in Desk.

Create a vault

Trade-offs and Honest Boundaries

  • AI moderation is a filter, not a guarantee. The system catches obvious policy violations and flags borderline cases for human review, but a determined adversary can craft listings that pass automated checks. The human arbiter layer exists for this reason. The digital-policy scope is intentionally narrow: only legal digital deliverables are permitted.
  • Opt-in reputation means absence ≠ bad seller. The system deliberately avoids penalizing anonymity. Fresh keys per listing are a privacy feature, not a deficiency. A buyer should evaluate the listing, the escrow terms, and the dispute window — not just the badge.
  • FTS5 search is single-instance. It is fast for the current scale, but it is not a distributed search engine. The silent fallback to substring scan ensures search never breaks entirely, at the cost of relevance ranking.
  • Listings expire after 30 days by browse filtering, not by status mutation. The join_code dies with the listing — an expired listing returns a 404 on get_listing. Sellers can extend from published status, and Desk warns three days before expiry.
  • Photo re-encoding strips all metadata — EXIF, IPTC, XMP, including GPS and camera model — and caps the long side at 2400 pixels. This protects seller privacy but means original fidelity is not preserved. Content-addressed storage (photo_id = sha256 of the normalized JPEG) enables deduplication and immutable caching with Cache-Control: public, max-age=31536000, immutable.
  • View counts are internal. GET listings/:id increments a views counter, but the field is not publicly returned and does not change updated_at. Only the listing owner sees view counts through GET listings/mine.

FAQ

How does Kaspa marketplace moderation work?

Every listing passes through an AI moderation pipeline before going live. The system evaluates text and photos against explicit policy categories — spam, malware, phishing, stolen goods, pirated content. Borderline cases are flagged for human review via a durable background worker that survives server restarts.

Is seller reputation mandatory on Kaspa Marketplace?

No. Reputation is opt-in and disabled by default. The marketplace is anonymous by design — each listing uses fresh keys. Sellers who enroll get a public badge backed by on-chain escrow outcomes, but the absence of a badge does not indicate a bad seller.

Can marketplace moderation freeze or redirect my escrowed funds?

No. Marketplace metadata — listings, moderation verdicts, photos — is completely separate from the escrow contract. Funds live in an on-chain covenant enforced by Kaspa's consensus layer. Moderation can reject a listing; it cannot touch escrowed KAS.

How does search ranking work in Kaspa Marketplace?

Search uses SQLite FTS5 with bm25 ranking. Title fields receive double weight. Prefix matching works across Latin and Cyrillic alphabets. If FTS5 fails for any reason, the system silently falls back to a substring scan. Explicit price sorts are preserved under search.

What happens to a rejected listing?

Rejected listings stay in the database with status rejected. If not manually approved by an admin within a configurable TTL (default 24 hours), a background sweep permanently deletes them and wipes associated photos.

What can I sell on Kaspa Marketplace?

Three categories: physical goods, digital deliverables, and services. Payment is always in KAS. OTC/crypto trading is not a marketplace category — it is handled separately through Kaspa Escrow. Only legal digital deliverables are permitted; malware, stolen credentials, and pirated content are rejected.

This article was researched, written and illustrated by OfficeForge's AI team — the same AI employees that built and run Kaspa Forge. Founder-directed, human-reviewed.

Non-custodial · open source

Put your KAS where theft can be cancelled

A covenant vault on Kaspa mainnet: your keys, your rules, our tooling. Free on-chain, forever.

Create a vault