6.0 KiB
API
Base
REST API under /api/v1.
Responses use:
{ "data": {} }
Collections include pagination metadata.
Public endpoints
GET /api/v1/public/search
GET /api/v1/public/products/:slug
GET /api/v1/public/inventory
GET /api/v1/public/inventory/:id
GET /api/v1/public/listings
GET /api/v1/public/listings/:id
GET /api/v1/public/sellers
GET /api/v1/public/lookups/categories
GET /api/v1/public/lookups/conditions
GET /api/v1/public/currencies
GET /api/v1/public/exchange-rates
Authentication
POST /api/v1/auth/login
POST /api/v1/auth/logout
POST /api/v1/auth/forgot-password
POST /api/v1/auth/reset-password
GET /api/v1/auth/me
POST /api/v1/auth/mfa/enroll
POST /api/v1/auth/mfa/verify
POST /api/v1/auth/mfa/disable
GET /api/v1/auth/sessions
DELETE /api/v1/auth/sessions/:id
DELETE /api/v1/auth/sessions
POST /api/v1/auth/forgot-password always returns the same accepted response after validating an email-shaped request, whether or not an account exists. It sends an opaque, one-time reset token only through the configured mail adapter. POST /api/v1/auth/reset-password consumes that token, updates the password, and revokes all active sessions.
GET /api/v1/auth/sessions returns only the authenticated user's active sessions and marks the current session. It never returns session or CSRF token material. DELETE /api/v1/auth/sessions/:id revokes one session owned by the authenticated user. DELETE /api/v1/auth/sessions revokes all other active sessions while retaining the current session. Session revocation endpoints require CSRF validation.
Admin endpoints
GET /api/v1/admin/products
POST /api/v1/admin/products
GET /api/v1/admin/products/:id
PATCH /api/v1/admin/products/:id
GET /api/v1/admin/inventory
POST /api/v1/admin/inventory
GET /api/v1/admin/inventory/:id
PATCH /api/v1/admin/inventory/:id
POST /api/v1/admin/inventory/:id/list
POST /api/v1/admin/inventory/:id/archive
POST /api/v1/admin/inventory/:id/relist
POST /api/v1/admin/inventory/:id/pricing/refresh
GET /api/v1/admin/jobs/:id
GET /api/v1/admin/products/:id/provider-mappings
POST /api/v1/admin/products/:id/provider-mappings
POST /api/v1/admin/provider-mappings/:id/disable
GET /api/v1/admin/listings
GET /api/v1/admin/listings/:id
PATCH /api/v1/admin/listings/:id
POST /api/v1/admin/listings/:id/publish
POST /api/v1/admin/listings/:id/unpublish
POST /api/v1/admin/listings/:id/pending
POST /api/v1/admin/listings/:id/archive
POST /api/v1/admin/pricing/refresh
GET /api/v1/admin/jobs/:id
POST /api/v1/admin/inventory/:id/images
PATCH /api/v1/admin/inventory/:id/images/order
POST /api/v1/admin/images/:id/primary
DELETE /api/v1/admin/images/:id
GET /api/v1/admin/acquisitions
POST /api/v1/admin/acquisitions
GET /api/v1/admin/sales
POST /api/v1/admin/sales
POST /api/v1/admin/sales/:id/void
POST /api/v1/admin/pricing/observations
POST /api/v1/admin/inventory/:id/valuation
POST /api/v1/admin/inventory/:id/valuation/override
POST /api/v1/admin/inventory/:id/pricing/refresh
POST /api/v1/admin/bulk
GET /api/v1/admin/dashboard
GET /api/v1/admin/saved-views
POST /api/v1/admin/saved-views
PATCH /api/v1/admin/saved-views/:id
DELETE /api/v1/admin/saved-views/:id
Listing creation and lifecycle writes require an authenticated admin session and
the session-bound CSRF header. Publishing is seller-scoped and checks the
persisted product, category, condition, asking price, physical inventory, and
image prerequisites before changing a draft to AVAILABLE; sold and archived
physical inventory cannot be published. Unpublish changes
an available listing to CLOSED; pending changes are available from draft or
available listings.
POST /api/v1/admin/inventory/:id/images stores validated image metadata for an
owned physical inventory item. File bytes are handled by the future
ImageStorage adapter; JSON metadata and multipart image uploads are accepted.
Multipart uploads require width and height fields and validate the binary
signature before storage. Publication counts persisted inventory images rather
than trusting a listing request field.
Acquisition, sale, pricing, and dashboard routes are seller-scoped through the
authenticated admin session. All state-changing routes require the
session-bound CSRF header. Sale creation marks owned active inventory items as
SOLD; voiding retains the sale record, restores the items to ACTIVE, and
records an audit event. Pricing observations remain private; public listing
detail exposes only the latest calculated or manually overridden market value,
condition label, and public image URLs.
Pricing refresh returns 202 Accepted with a durable job identifier and
PENDING status. Poll the job endpoint for PROCESSING, COMPLETED, or
FAILED; job status reads are seller-scoped and expose only safe status/error
metadata.
Provider matching
The API must expose Product-level operations for:
- searching configured providers for candidate matches
- confirming a provider mapping
- manually searching/refining a provider query
- marking a provider not applicable
- disabling/replacing a mapping
Exact route naming may be finalized during API implementation, but these operations must remain Product-scoped.
Validation
Validate body, query, path, and response schemas.
Business validation occurs after request-shape validation.
Allowlist sortable fields.
Errors
Use machine-readable codes, including:
PRODUCT_NOT_FOUNDINVENTORY_NOT_FOUNDINVENTORY_EDIT_LOCKEDINVALID_STATUS_TRANSITIONLISTING_REQUIREMENTS_NOT_METSALE_PRICE_REQUIREDSALE_ITEM_NOT_AVAILABLEPRICING_PROVIDER_FAILEDIMAGE_LIMIT_EXCEEDEDUNAUTHORIZEDFORBIDDEN
Privacy
Public DTOs must never expose private acquisition, sale, buyer, internal, provider-debugging, pricing-history, or audit information.
Pagination and query state
Large collections use pagination. Public/admin filters and searches should be represented in URL query state where useful for shareability, refresh, and back/forward navigation.