Files
nick-doc/03 - API Reference/Marketplace API.md
Siavash Sameni 9698ec5809 docs: align API reference and data model docs with code reality
API Reference (9 files updated):
- Marketplace API: corrected offer endpoints (scoped under /purchase-requests/:id/offers),
  marked phantom /search /stats /seller/:sellerId /withdraw routes as NOT IMPLEMENTED,
  documented PUT→PATCH mismatches, removed invalid SellerOffer 'active' status
- Dispute API: corrected resolve schema (action enum), categories (no 'fraud'),
  removed 'under_review' status, added security callouts (3 unguarded endpoints),
  route shadowing documented, all socket events marked as TODO stubs
- Notification API: corrected mark-all-read method+path, fixed broken GET /:id,
  added unread-count-update event, 90-day TTL documented
- Payment API: /create→/save, removed 10+ phantom endpoints, fixed release/refund
  paths (no /shkeeper/ segment), added 3 unauthenticated endpoint security warnings,
  stats undercounting documented, export privilege gap documented
- Authentication API: 8-digit→6-digit code, no-complexity warning on reset-with-code,
  rate limiter counts all attempts, passkey stub claims removed, deleteAccount bug noted
- Admin API: PUT→PATCH bug documented, wrong status values documented, hard vs soft
  delete clarified, scanner no-auth security bug, 3 NOT IMPLEMENTED endpoints
- Chat API: file upload wrong endpoint bug, archive PUT→PATCH bug, rate limits added
- Points API: corrected redeem schema, referral triggers on 'completed' only,
  leaderboard period ignored, removed 'refund' PointTransaction type
- Socket Events: removed request-cancelled, notification-read; added unread-count-update;
  dispute events all stubs; referral-signup is auth-domain not points-domain

Data Models (3 files updated):
- SellerOffer: removed 'active' from status enum, withdrawOffer() is dead code
- PurchaseRequest: added pending_payment/active statuses, added 'urgent' urgency,
  corrected description minimum (5 chars), removed finalized/archived
- Dispute: corrected action enum, categories (no fraud), removed under_review,
  security callout on unguarded status/resolve endpoints

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 14:57:47 +04:00

19 KiB

title, tags
title tags
Marketplace API
api
marketplace
reference

Marketplace API

Last updated: 2026-05-29 — aligned with code (see Doc vs Code Audit Report)

All marketplace endpoints live under /api/marketplace/*. The router is composed of several files mounted from app.ts:

Core models: PurchaseRequest, SellerOffer, Category, RequestTemplate, ShopSettings, Review. Real-time updates are emitted on the request-<id>, seller-<id>, buyer-<id>, and sellers/buyers rooms — see Socket Events.

Categories

GET /api/marketplace/categories

Description: Flat list of all categories. Auth required: No Response 200: { success: true, data: [Category, ...] }

GET /api/marketplace/categories/tree

Description: Nested tree based on parentId. Auth required: No

GET /api/marketplace/categories/:id

Description: Single category by id. Auth required: No Errors: 404 not found.

Sellers

GET /api/marketplace/sellers

Description: Public seller directory (users with role: 'seller'). Includes aggregated stats (completed orders, ratings). Auth required: No

GET /api/marketplace/request-templates/sellers

Description: Sellers who currently expose at least one active RequestTemplate (used by the shop discovery page). Auth required: No

GET /api/marketplace/request-templates/sellers/:sellerId

Description: Public shop profile for a seller, including their templates and shop settings. Auth required: No

Purchase Requests

The buyer-facing CRUD plus seller-side workflow endpoints. Model: PurchaseRequest.

POST /api/marketplace/purchase-requests

Description: Create a purchase request (new controller path). Auth required: Bearer JWT (buyer) Request body:

{
  title: string;
  description: string;
  categoryId: string;
  productLink?: string;
  size?: string;
  color?: string;
  quantity?: number;          // default 1
  budget?: { min?: number; max?: number; currency: "USD" | "EUR" | "IRR" };
  urgency?: "low" | "medium" | "high";
  deliveryInfo?: {
    deliveryType: "physical" | "online";
    addressId?: string;       // when physical
    email?: string;           // when online
  };
  preferredSellerIds?: string[];
  attachments?: string[];     // URLs from [[File API]]
}

Response 201: { success, data: { purchaseRequest } } Side effects: Emits new-purchase-request to the sellers room (broadcast). Source: marketplaceController.createPurchaseRequest

POST /api/marketplace/purchase-requests/bulk

Description: Bulk creation (used by the template checkout flow). Auth required: Bearer JWT Request body: { items: Array<PurchaseRequestInput> }

GET /api/marketplace/purchase-requests

Description: List requests with filters. Buyers see their own; sellers see ones routed to them; admins see all. Auth required: Bearer JWT Query params: status, categoryId, urgency, search, page, limit, sortBy, sortOrder

Note: Use query params on this endpoint for filtering/searching. The separate search and stats endpoints documented in earlier versions do not exist — see below.

⚠️ NOT IMPLEMENTED: GET /api/marketplace/purchase-requests/search

This endpoint does not exist. Use query params (search, status, categoryId, etc.) on GET /api/marketplace/purchase-requests instead.

⚠️ NOT IMPLEMENTED: GET /api/marketplace/purchase-requests/stats

This endpoint does not exist in the backend.

GET /api/marketplace/purchase-requests/my

Description: Shortcut for the caller's own purchase requests. Auth required: Bearer JWT

GET /api/marketplace/purchase-requests/:id

Description: Single request with populated category and selected offer. Auth required: No (public read for shareable links) Errors: 404 not found.

PATCH /api/marketplace/purchase-requests/:id

Description: Buyer edits draft / pending request fields. Auth required: Bearer JWT (owner)

⚠️ KNOWN BUG: The frontend sends PUT but the backend registers PATCH. Requests from clients using PUT will receive 404. Use PATCH.

PATCH /api/marketplace/purchase-requests/:id/status

Description: Transition the request status (draftpendingpaymentprocessingdeliverydeliveredseller_paidcompleted, or cancelled). Auth required: Bearer JWT (owner or admin) Request body: { status: string } Side effects: Emits purchase-request-update to request-<id>.

DELETE /api/marketplace/purchase-requests/:id

Description: Cancel/delete a request that has no committed payment. Auth required: Bearer JWT (owner)

GET /api/marketplace/purchase-requests/:id/workflow-steps

Description: Returns the ordered workflow steps + current pointer used by the frontend stepper. Auth required: No

GET /api/marketplace/purchase-requests/:id/payment-status

Description: Returns the latest payment + escrow state for the request. Auth required: Bearer JWT

POST /api/marketplace/purchase-requests/:id/sync-payment-status

Description: Force a re-check against the payment provider (Payment API). Auth required: Bearer JWT

POST /api/marketplace/purchase-requests/:id/confirm-payment

Description: Legacy buyer-confirmation endpoint kept for old clients. Auth required: Bearer JWT

POST /api/marketplace/purchase-requests/:id/release-payment

Description: Triggers admin escrow release (mirror of POST /api/payment/shkeeper/:id/release). Auth required: Bearer JWT (admin)

PUT /api/marketplace/purchase-requests/:id/delivery (controller route)

Description: Seller submits shipping details (carrier, tracking number, expected date). Auth required: Bearer JWT (selected seller)

POST /api/marketplace/purchase-requests/:id/update-delivery (legacy)

Description: Older equivalent retained for compatibility.

POST /api/marketplace/requests/:id/start-delivery

Description: Marks the request as delivery and notifies the buyer. Auth required: Bearer JWT (seller) Side effects: Emits purchase-request-update event.

PATCH /api/marketplace/purchase-requests/:id/confirm-delivery

Description: Buyer confirms goods received (transitions to delivered). Auth required: Bearer JWT (buyer)

POST /api/marketplace/purchase-requests/:id/final-approval

Description: Buyer's final approval that releases escrow to the seller. Auth required: Bearer JWT (buyer)

GET /api/marketplace/buyers/:buyerId/purchase-requests

Description: Admin/seller view of a buyer's request history. Auth required: Bearer JWT

Delivery codes

Six-digit codes the buyer hands to the seller at handover. Backed by deliveryService.

POST /api/marketplace/purchase-requests/:id/delivery-code/generate

Description: Buyer generates a delivery code. Request must be in delivery status. Auth required: Bearer JWT (buyer) Response 200: { success: true, data: { deliveryCode: "123456" } } Errors: 400 wrong status, 403 not buyer, 404 request not found. Side effects: Emits delivery-code-generated on request-<id>.

POST /api/marketplace/purchase-requests/:id/delivery-code/verify

Description: Seller verifies the code. On success the status moves to delivered. Auth required: Bearer JWT (selected seller) Request body: { code: string } (exactly 6 chars) Errors: 400 bad code, 403 not the selected seller. Side effects: Emits delivery-confirmed and buyer-confirmed-delivery.

GET /api/marketplace/purchase-requests/:id/delivery-code

Description: Buyer or seller fetches the current code metadata. Auth required: Bearer JWT

GET /api/marketplace/purchase-requests/:id/delivery-code/status

Description: Returns { isValid, hasDeliveryCode, ... } so the UI can decide whether to show "regenerate". Auth required: Bearer JWT

Seller Offers

Model: SellerOffer.

Valid status values: pending | accepted | rejected | withdrawn

Note: The status value active does not exist on SellerOffer. Earlier docs were incorrect.

POST /api/marketplace/purchase-requests/:id/offers

Description: Submit an offer against the purchase request identified by :id in the path. The purchase request must be in pending, received_offers, or active status. Auth required: Bearer JWT (seller) Path param: :id — the purchaseRequestId (not a body field) Request body:

{
  price: { amount: number; currency: "USD" | "EUR" | "IRR" };
  deliveryEstimate: { days: number; note?: string };
  notes?: string;
  attachments?: string[];
}

Response 201: { success, data: { offer } } Side effects: Emits new-offer to buyer-<buyerId> and seller-offer-update to seller-<sellerId>.

PUT /api/marketplace/purchase-requests/:id/offers (legacy)

Description: Older offer-update endpoint kept for compatibility.

GET /api/marketplace/purchase-requests/:id/offers

Description: List all offers for a request. Auth required: No (buyers and prospective sellers compare offers)

GET /api/marketplace/purchase-requests/:id/has-offer

Description: Returns { hasOffer: boolean } for the caller (seller-side helper). Auth required: Bearer JWT (seller)

GET /api/marketplace/purchase-requests/:id/offers/:sellerId

Description: Fetch a specific seller's offer on a request. Auth required: No

⚠️ NOT IMPLEMENTED: GET /api/marketplace/offers/request/:requestId

This endpoint does not exist. Use GET /api/marketplace/purchase-requests/:id/offers instead.

⚠️ NOT IMPLEMENTED: GET /api/marketplace/offers/seller/:sellerId

This endpoint does not exist. getOffersBySeller() is an internal service method and is not exposed via HTTP.

PATCH /api/marketplace/offers/:id

Description: Seller edits their pending offer (price, delivery estimate, notes). Auth required: Bearer JWT (offer owner)

⚠️ KNOWN BUG: The frontend sends PUT but the backend registers PATCH. Requests from clients using PUT will receive 404. Use PATCH.

DELETE /api/marketplace/offers/:id

Description: Seller withdraws their offer. Auth required: Bearer JWT (offer owner)

PUT /api/marketplace/offers/:id/status

Description: Direct status mutation (admin override / counter-offer states). This is also the correct way to withdraw an offer programmatically — send { status: 'withdrawn' }. Auth required: Bearer JWT Request body: { status: "pending" | "accepted" | "rejected" | "withdrawn" }

⚠️ NOT IMPLEMENTED: POST /api/marketplace/offers/:id/withdraw

This endpoint does not exist. To withdraw an offer use PUT /api/marketplace/offers/:id/status with { status: 'withdrawn' }.

POST /api/marketplace/purchase-requests/:id/select-offer

Description: Buyer selects/accepts an offer; this triggers payment intent creation in Payment API and rejects all other offers automatically once payment lands. Auth required: Bearer JWT (buyer) Request body: { offerId: string } Side effects:

  • Updates PurchaseRequest selectedOfferId, status moves toward payment.
  • Emits seller-offer-update to all sellers for the request.

POST /api/marketplace/offers/:id/accept (legacy)

Description: Older synonym retained for backward compatibility with old clients.

DELETE /api/marketplace/offers/:id (controller route)

Description: Controller-pattern delete that also notifies the buyer.

Request Templates

A RequestTemplate is a re-usable "shop product" a seller can publish. Buyers convert templates into actual purchase requests via the shareable link, individually or in bulk (cart checkout).

POST /api/marketplace/request-templates

Description: Create a new template. Auth required: Bearer JWT (seller) Request body:

{
  title: string;                       // 1-200 chars
  description: string;                 // 1-2000
  categoryId: string;                  // MongoId
  productLink?: string;                // valid URL
  size?: string;                       // <=100
  color?: string;                      // <=100
  quantity?: number;                   // 1-10000
  budget?: { min?: number; max?: number; currency: "USD" | "EUR" | "IRR" };
  urgency?: "low" | "medium" | "high";
  deliveryInfo?: { deliveryType: "physical" | "online"; email?: string };
  maxUsage?: number | null;            // 0/null = unlimited
  expiresAt?: string | null;           // ISO date
  images?: string[];                   // URLs from [[File API]]
}

Response 201: { data: { template } } with a generated shareableLink.

GET /api/marketplace/request-templates

Description: Paginated list of the caller's templates. Auth required: Bearer JWT (seller) Query params: page, limit (1-100), isActive, categoryId, search

GET /api/marketplace/request-templates/stats

Description: Aggregate counts of the caller's templates (active, expired, usage). Auth required: Bearer JWT (seller)

GET /api/marketplace/request-templates/:id

Description: Full template by id (owner view). Auth required: Bearer JWT (owner)

PUT /api/marketplace/request-templates/:id

Description: Update the template. Same body as create. Auth required: Bearer JWT (owner)

DELETE /api/marketplace/request-templates/:id

Description: Delete a template. Auth required: Bearer JWT (owner)

PATCH /api/marketplace/request-templates/:id/toggle-status

Description: Toggle isActive. Auth required: Bearer JWT (owner)

Description: Public read of a template via its shareable slug. Used by the shop preview page. Auth required: No Errors: 404 link not found or template inactive/expired.

POST /api/marketplace/request-templates/:shareableLink/convert

Description: Buyer converts the template into a real PurchaseRequest. Auth required: Bearer JWT (buyer) Request body: Overrides (quantity, address, etc.) Response 201: { data: { purchaseRequest } }

POST /api/marketplace/request-templates/batch-convert

Description: Convert several templates at once (cart checkout). Auth required: Bearer JWT (buyer) Request body:

{
  items: Array<{
    shareableLink: string;
    quantity: number;        // 1-100
    sellerId: string;        // MongoId
  }>;
  status?: "pending" | "pending_payment" | "active";
}

POST /api/marketplace/request-templates/complete-payment

Description: Marks the requests created by batch-convert as paid (called after a successful checkout). Auth required: Bearer JWT Request body:

{
  requestIds: string[];      // 1+ MongoIds
  newStatus?: "pending" | "active" | "processing";
  paymentData?: Record<string, unknown>;
}

Shop Settings

Per-seller storefront preferences. Model: ShopSettings.

GET /api/marketplace/shop/settings/:sellerId

Description: Public shop settings for the given seller (used by the shop landing page). Auth required: No Response 200: { data: ShopSettings }

GET /api/marketplace/shop/settings

Description: The authenticated seller's own settings. Auth required: Bearer JWT (seller)

PUT /api/marketplace/shop/settings

Description: Update shop settings (banner, bio, policies, allowSellerReviews, allowTemplateReviews, ...). Auth required: Bearer JWT (seller)

Reviews

Model: Review. Reviews can target a seller or a template. Subject must be seller or template.

GET /api/marketplace/reviews/:subjectType/:subjectId

Description: Published reviews + aggregate stats. Honours allowSellerReviews / allowTemplateReviews from ShopSettings. Auth required: No Query params: page (default 1), limit (default 10) Response 200:

{
  "data": [Review, ...],
  "pagination": { "page": 1, "limit": 10, "total": 42, "pages": 5 },
  "stats": { "count": 42, "avg": 4.6, "one": 1, "two": 0, "three": 3, "four": 10, "five": 28 }
}

Errors: 400 bad subjectType / invalid id, 403 reviews disabled by seller.

GET /api/marketplace/reviews/:subjectType/:subjectId/summary

Description: Stats only (no review list). Auth required: No

POST /api/marketplace/reviews

Description: Submit a review. The server computes isVerifiedBuyer when purchaseRequestId is given and the request is in a terminal state (delivery, delivered, seller_paid, completed). Auth required: Bearer JWT Request body:

{
  subjectType: "seller" | "template";
  subjectId: string;
  rating: 1 | 2 | 3 | 4 | 5;
  comment?: string;
  purchaseRequestId?: string;
}

Errors: 400 validation, 403 reviews disabled, 404 template not found, 409 duplicate review. Response 201: { data: Review, stats: { ... } }

Payments (legacy under marketplace)

These routes are duplicates of the main Payment API kept under /api/marketplace/payments/* for backward compatibility with the early frontend. Prefer the canonical endpoints.

POST /api/marketplace/payments

GET /api/marketplace/payments

GET /api/marketplace/payments/:paymentId

PATCH /api/marketplace/payments/:paymentId

See Payment API for the canonical descriptions.

Verify Web3 payment (legacy)

POST /api/marketplace/payments/verify

Description: Legacy Web3 verification endpoint that records a transaction and moves the purchase request to processing. Modern flows use POST /api/payment/shkeeper/confirm-transaction instead. Auth required: Bearer JWT Request body:

{
  purchaseRequestId: string;
  sellerOfferId: string;
  buyerId: string;
  sellerId: string;
  amount: number;
  currency: "USDT" | string;
  paymentHash: string;
  paymentMethod?: string;
  token?: string;
  network?: string;
  escrowWalletAddress?: string;
  metadata?: Record<string, unknown>;
}

Side effects: Creates a Payment record, updates PurchaseRequest status, emits payment-received to user-<sellerId>.

Real-time events

Most marketplace mutations fan out via global.io to the rooms below — see Socket Events for payloads:

  • purchase-request-updaterequest-<id>
  • new-purchase-requestsellers
  • new-offerbuyer-<buyerId>
  • seller-offer-updateseller-<sellerId> (and global on payment confirm)
  • delivery-code-generated / delivery-confirmed / delivery-updaterequest-<id>
  • request-cancelleduser-<buyerId>, user-<sellerId>
  • transaction-completeduser-<buyerId>, user-<sellerId>