193 lines
7.0 KiB
Markdown
193 lines
7.0 KiB
Markdown
# API
|
|
|
|
## Base
|
|
|
|
REST API under `/api/v1`.
|
|
|
|
Responses use:
|
|
|
|
```json
|
|
{ "data": {} }
|
|
```
|
|
|
|
Collections include pagination metadata.
|
|
|
|
## Public endpoints
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
`POST /api/v1/admin/bulk` supports `ARCHIVE`, `PRICING_REFRESH`, and `TAGS` actions. `TAGS` accepts `add` and/or `remove` arrays and applies labels to the selected items' Products.
|
|
|
|
GET /api/v1/admin/dashboard
|
|
GET /api/v1/admin/exports/inventory.json
|
|
GET /api/v1/admin/exports/inventory.csv
|
|
GET /api/v1/admin/exports/inventory.xls
|
|
POST /api/v1/admin/exports/inventory.json/jobs
|
|
GET /api/v1/admin/exports/jobs/:id
|
|
GET /api/v1/admin/exports/jobs/:id/download
|
|
GET /api/v1/admin/settings
|
|
PATCH /api/v1/admin/settings
|
|
|
|
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. Refresh enqueue resolves the provider from an active Product-level
|
|
mapping and returns `409` when no mapping exists.
|
|
|
|
## 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_FOUND`
|
|
- `INVENTORY_NOT_FOUND`
|
|
- `INVENTORY_EDIT_LOCKED`
|
|
- `INVALID_STATUS_TRANSITION`
|
|
- `LISTING_REQUIREMENTS_NOT_MET`
|
|
- `SALE_PRICE_REQUIRED`
|
|
- `SALE_ITEM_NOT_AVAILABLE`
|
|
- `PRICING_PROVIDER_FAILED`
|
|
- `IMAGE_LIMIT_EXCEEDED`
|
|
- `UNAUTHORIZED`
|
|
- `FORBIDDEN`
|
|
|
|
## 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.
|
|
|
|
Public listing and product details include nullable `sellerDescription` from
|
|
`general.publicDescription` in seller settings. Authenticated, seller-scoped
|
|
`PATCH /api/v1/admin/settings` accepts this optional plain-text field (trimmed,
|
|
maximum 2,000 characters); send an empty string to remove it. Omitted fields
|
|
retain their current values. Private settings are not exposed in public DTOs.
|