Skip to content

REST API

All routes are mounted under the /api prefix. The full interactive spec is available at GET /api/reference (Swagger UI) and GET /api/doc (OpenAPI 3.0 JSON).

Authentication: API key via x-api-key header, or a Better Auth session cookie for browser clients.

Successful responses: { data: ... }. List endpoints include meta.pagination. Errors return { error: { code, message } }.

X-Request-Id: Every response includes this header with a unique request identifier.


MethodPathDescription
GET/api/docOpenAPI 3.0 JSON spec
GET/api/referenceSwagger UI (interactive explorer)

All core routes and plugin routes registered via router() appear in the spec automatically.


MethodPathDescription
GET/api/healthServer status, version, database connectivity

Probes the database connection. Returns 503 if the database is unreachable.

// healthy
{ "status": "ok", "version": "0.1.0" }
// unhealthy
{ "status": "error", "version": "0.1.0", "database": "unreachable" }

Body size: 1 MB maximum. Requests exceeding this receive 413 Payload Too Large.

Rate limiting: Returns 429 Too Many Requests when exceeded.

Rate limit headers on every response:

HeaderDescription
X-RateLimit-LimitMax requests in the current window
X-RateLimit-RemainingRemaining requests in this window
X-RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds until retry (only on 429)

CSRF: Mutation methods (POST, PUT, PATCH, DELETE) validate the Origin header for browser requests. API-key requests are exempt.


Base path: /api/catalog

MethodPathDescription
GET/catalog/entitiesList catalog entities
GET/catalog/entities/:idOrSlugGet entity by UUID or slug
POST/catalog/entitiesCreate a catalog entity
PATCH/catalog/entities/:idUpdate an entity
DELETE/catalog/entities/:idDelete an entity
POST/catalog/entities/:id/publishTransition to active status
POST/catalog/entities/:id/archiveTransition to archived status
POST/catalog/entities/:id/discontinueTransition to discontinued status

GET /catalog/entities query parameters:

ParameterTypeDescription
typestringFilter by entity type (product, digitalDownload, etc.)
statusstringFilter by status (draft, active, archived, discontinued)
categorystringFilter by category ID
brandstringFilter by brand ID
pagenumberPage number (default 1)
limitnumberItems per page (default 20, max 100)
sortstringSort field and direction (e.g. createdAt:desc)
includestringComma-separated: attributes, variants, categories, brands, media, inventory, pricing

POST /catalog/entities body:

{
"type": "product",
"slug": "blue-widget",
"status": "draft",
"metadata": {}
}
MethodPathDescription
PUT/catalog/entities/:id/attributes/:localeSet localized attributes
GET/catalog/entities/:id/attributes/:localeGet localized attributes

PUT body:

{
"title": "Blue Widget",
"description": "A fine blue widget.",
"seoTitle": "Buy Blue Widget",
"seoDescription": "Best blue widget online."
}
MethodPathDescription
GET/catalog/categoriesList all categories
POST/catalog/categoriesCreate a category
PATCH/catalog/categories/:categoryIdUpdate a category
DELETE/catalog/categories/:categoryIdDelete a category
POST/catalog/entities/:id/categories/:categoryIdAdd entity to a category
DELETE/catalog/entities/:id/categories/:categoryIdRemove entity from a category
MethodPathDescription
GET/catalog/brandsList all brands
POST/catalog/brandsCreate a brand
PATCH/catalog/brands/:brandIdUpdate a brand
DELETE/catalog/brands/:brandIdDelete a brand
POST/catalog/entities/:id/brands/:brandIdAdd entity to a brand
DELETE/catalog/entities/:id/brands/:brandIdRemove entity from a brand
MethodPathDescription
POST/catalog/entities/:id/optionsCreate an option type
POST/catalog/options/:optionTypeId/valuesCreate an option value
POST/catalog/entities/:id/variantsCreate a single variant
POST/catalog/entities/:id/variants/generateGenerate variants from an option matrix

Base path: /api/carts

MethodPathDescription
POST/cartsCreate a new cart
GET/carts/:idGet cart with line items
POST/carts/:id/itemsAdd an item to the cart
PATCH/carts/:id/items/:itemIdUpdate item quantity
DELETE/carts/:id/items/:itemIdRemove an item from the cart

POST /carts body:

{
"currency": "USD",
"customerId": "optional-uuid"
}

POST /carts/:id/items body:

{
"entityId": "uuid",
"variantId": "uuid-or-omit",
"quantity": 2,
"unitPriceSnapshot": 1999
}

PATCH /carts/:id/items/:itemId body:

{ "quantity": 3 }

MethodPathDescription
POST/api/checkoutCreate an order from a cart

Body:

{
"cartId": "uuid",
"paymentMethodId": "pm_...",
"currency": "USD",
"customerId": "optional",
"customerGroupIds": ["optional"],
"promotionCodes": ["SAVE10"],
"shippingAddress": {
"line1": "123 Main St",
"city": "Springfield",
"state": "IL",
"postalCode": "62701",
"country": "US"
}
}

Returns the created order. If after-hooks produce non-fatal errors, the response includes meta.hookErrors.

Failure: 422 with { error: { code: "CHECKOUT_FAILED", message: "..." } }.


Base path: /api/orders

MethodPathDescription
GET/ordersList orders
GET/orders/:idOrNumberGet order by UUID or order number (ORD-YYYY-NNNNNN)
PATCH/orders/:id/statusChange order status
GET/orders/:id/fulfillmentsList fulfillments for an order

GET /orders query parameters:

ParameterTypeDescription
statusstringFilter by status
pagenumberPage number
limitnumberItems per page

PATCH /orders/:id/status body:

{
"status": "confirmed",
"reason": "optional reason string"
}

Valid transitions: pending → confirmed → processing → partially_fulfilled | fulfilled → refunded. Cancel is allowed from pending, confirmed, processing, partially_fulfilled.


Base path: /api/inventory

MethodPathDescription
GET/inventory/checkCheck stock for one or more entities
POST/inventory/adjustAdjust an inventory level
POST/inventory/reserveReserve inventory
POST/inventory/releaseRelease a reservation
POST/inventory/warehousesCreate a warehouse
GET/inventory/warehousesList warehouses

GET /inventory/check query parameters:

ParameterTypeDescription
entityIdsstringComma-separated entity UUIDs

POST /inventory/adjust body:

{
"entityId": "uuid",
"variantId": "optional-uuid",
"warehouseId": "uuid",
"type": "restock",
"quantity": 50
}

Base path: /api/pricing

MethodPathDescription
POST/pricing/pricesCreate a price record
GET/pricing/pricesList prices
POST/pricing/modifiersCreate a price modifier

GET /pricing/prices query parameters:

ParameterTypeDescription
entityIdstringFilter by entity ID
variantIdstringFilter by variant ID
currencystringFilter by currency code
customerGroupIdstringFilter by customer group

POST /pricing/prices body:

{
"entityId": "uuid",
"variantId": "optional-uuid",
"currency": "USD",
"amount": 2999
}

Base path: /api/promotions

MethodPathDescription
POST/promotionsCreate a promotion
GET/promotionsList active promotions
POST/promotions/validateValidate a promotion code against a cart
POST/promotions/:id/deactivateDeactivate a promotion

POST /promotions body:

{
"code": "SAVE10",
"name": "Save 10%",
"type": "percentage_off_order",
"value": 10,
"validFrom": "2025-01-01T00:00:00Z",
"validUntil": "2025-12-31T23:59:59Z"
}

validFrom and validUntil are ISO 8601 strings coerced to Date objects on the server.

POST /promotions/validate body:

{
"code": "SAVE10",
"currency": "USD",
"subtotal": 5000,
"lineItems": [
{
"entityId": "uuid",
"entityType": "product",
"quantity": 1,
"unitPrice": 5000,
"totalPrice": 5000
}
],
"customerId": "optional",
"customerGroupIds": ["optional"]
}

Base path: /api/search

MethodPathDescription
GET/searchFull-text search across catalog entities
GET/search/suggestAutocomplete prefix suggestions

GET /search query parameters:

ParameterTypeDescription
qstringSearch query
typestringFilter by entity type
categorystringFilter by category
brandstringFilter by brand
statusstringFilter by status
pagenumberPage number (default 1)
limitnumberResults per page (default 20, max 100)
facetsstringComma-separated facet fields to return

Response includes data (hits array) and meta with total, page, limit, facets.

GET /search/suggest query parameters:

ParameterTypeDescription
prefixstringPrefix to match
typestringFilter by entity type
limitnumberMax suggestions (default 10)

Base path: /api/media

MethodPathDescription
POST/media/uploadUpload a file (multipart/form-data)
GET/media/:idGet media URL (redirects 302)
DELETE/media/:idDelete a media asset
POST/media/attachAttach a media asset to an entity

POST /media/upload fields (multipart/form-data):

FieldTypeRequired
fileFileYes
altstringNo

GET /media/:id query parameters:

ParameterValueDescription
signed"true"Return a signed URL with expiry instead of a public URL

POST /media/attach body:

{
"entityId": "uuid",
"mediaAssetId": "uuid",
"role": "thumbnail"
}

MethodPathDescription
POST/api/payments/webhookPayment provider webhook receiver

Accepts raw webhook payloads from the configured payment adapter. On payment_intent.succeeded with metadata.orderId, transitions the order to confirmed automatically.


Base path: /api/webhooks

Requires webhooks:manage permission.

MethodPathDescription
POST/webhooksRegister a webhook endpoint
GET/webhooksList registered endpoints
DELETE/webhooks/:idDelete a webhook endpoint

Base path: /api/me

Requires an authenticated Better Auth session cookie. All routes return 401 without a session.

MethodPathDescription
GET/me/profileGet current customer profile
PATCH/me/profileUpdate current customer profile
GET/me/addressesList customer addresses
POST/me/addressesAdd a new address
DELETE/me/addresses/:idDelete an address
GET/me/ordersList orders for the current customer
GET/me/orders/:idOrNumberGet a specific order by UUID or order number
GET/me/orders/:idOrNumber/trackingGet fulfillment tracking for an order
GET/me/orders/:orderId/downloadsGet download links for digital items
POST/me/orders/:orderId/reorderCreate a new cart pre-filled from a previous order

GET /me/orders query parameters:

ParameterTypeDescription
statusstringFilter by order status
pagenumberPage number
limitnumberItems per page

Base path: /api/analytics

MethodPathDescription
GET/analytics/metaList available models, measures, and dimensions
POST/analytics/queryExecute an analytics query

POST /analytics/query body: See Analytics reference for the full query format.


Base path: /api/audit

Requires audit:read permission.

MethodPathDescription
GET/auditList audit entries
GET/audit/:entityType/:entityIdAudit history for a specific entity

GET /audit query parameters:

ParameterTypeDescription
entityTypestringFilter by entity type (e.g. order, catalog_entity, inventory)
entityIdstringFilter by entity UUID
eventstringFilter by event name (e.g. orders.statusChange)
actorIdstringFilter by actor
fromstringISO 8601 start date
tostringISO 8601 end date
limitnumberMax entries (default 50, max 100)

Base path: /api/auth

Authentication is handled by Better Auth. These are the core sign-up/sign-in endpoints. Better Auth exposes additional endpoints for password reset, email verification, sessions, and OAuth.

MethodPathDescription
POST/auth/sign-up/emailRegister a new user
POST/auth/sign-in/emailSign in with email and password
GET/auth/get-sessionGet the current session

POST /auth/sign-up/email body:

{
"email": "user@example.com",
"password": "secret",
"name": "Jane Doe"
}

POST /auth/sign-in/email body:

{
"email": "user@example.com",
"password": "secret"
}

Base path: /api/admin/jobs

Requires jobs:admin permission.

MethodPathDescription
GET/admin/jobs/failedList failed background jobs
POST/admin/jobs/:id/retryRe-enqueue a failed job

GET /admin/jobs/failed query parameters:

ParameterTypeDescription
pagenumberPage number
limitnumberItems per page

POST /admin/jobs/:id/retry returns the updated job record.

The cron job runner endpoint:

MethodPathDescription
GET/api/jobs/runProcess pending jobs (cron target)

Query parameters: queue (default "default"), limit (default 10). Requires *:* permission via x-api-key.


Added by @porulle/plugin-marketplace. All paths prefixed with /api/marketplace/.

MethodPathDescription
GET/vendorsList vendors
POST/vendorsRegister a vendor
GET/vendors/:idVendor detail
PATCH/vendors/:idUpdate vendor
POST/vendors/:id/approveApprove vendor
POST/vendors/:id/rejectReject with reason
POST/vendors/:id/suspendSuspend vendor
POST/vendors/:id/reinstateReinstate vendor
GET/vendors/:id/documentsList documents
POST/vendors/:id/documentsUpload document
POST/vendors/:id/documents/:docId/approveApprove document
POST/vendors/:id/documents/:docId/rejectReject document
GET/vendors/:id/balanceBalance ledger
GET/vendors/:id/performancePerformance metrics and rating

Scoped automatically to actor.vendorId.

MethodPathDescription
GET/vendor/meOwn vendor profile
PATCH/vendor/meUpdate own profile
GET/vendor/me/ordersOwn sub-orders
POST/vendor/me/orders/:id/confirmConfirm sub-order
POST/vendor/me/orders/:id/shipShip with tracking number
POST/vendor/me/orders/:id/deliverMark delivered
POST/vendor/me/orders/:id/cancelCancel sub-order
GET/vendor/me/payoutsPayout history
GET/vendor/me/balanceBalance ledger
GET/vendor/me/reviewsReviews received
GroupPaths
Commission rulesGET /commission-rules, POST /commission-rules, PATCH /commission-rules/:id, DELETE /commission-rules/:id
PayoutsGET /payouts, POST /payouts/run, POST /payouts/:id/retry
Sub-orders (admin)GET /sub-orders, GET /sub-orders/:id, PATCH /sub-orders/:id/status
DisputesPOST /disputes, GET /disputes, POST /disputes/:id/respond, POST /disputes/:id/escalate, POST /disputes/:id/resolve
ReturnsPOST /returns, POST /returns/:id/ship-back, POST /returns/:id/receive
ReviewsPOST /vendors/:id/reviews, GET /vendors/:id/reviews, PATCH /vendors/:id/reviews/:reviewId

Endpoint groupRequired permission
POST /webhooks, GET /webhooks, DELETE /webhooks/:idwebhooks:manage
GET /audit, GET /audit/:entityType/:entityIdaudit:read
POST /pricing/prices, POST /pricing/modifierspricing:create
GET /pricing/pricespricing:update
POST /promotionspromotions:create
PATCH /promotions/:id, POST /promotions/:id/deactivatepromotions:update
POST /marketplace/vendors/:id/approve, .../suspendmarketplace:admin
GET /admin/jobs/failed, POST /admin/jobs/:id/retryjobs:admin

Events that trigger delivery when a matching endpoint is registered:

EventTrigger
orders.createNew order created via checkout
orders.statusChangeOrder transitions to a new status
catalog.createNew catalog entity created
catalog.updateCatalog entity updated
catalog.deleteCatalog entity deleted
inventory.afterAdjustInventory level adjusted
customers.createNew customer profile created
customers.updateCustomer profile updated
pricing.createNew price record created
pricing.updatePrice record updated
promotions.createNew promotion created
promotions.updatePromotion updated or deactivated
fulfillment.createNew fulfillment record created
cart.afterAddItemItem added to a cart

{
"error": {
"code": "NOT_FOUND",
"message": "Entity not found."
}
}
CodeHTTP statusDescription
NOT_FOUND404Resource does not exist
VALIDATION_FAILED422Input validation failed
CHECKOUT_FAILED422Checkout pipeline error
FORBIDDEN403Insufficient permissions
CONFLICT409Conflicting state (e.g., duplicate slug)
TOO_MANY_REQUESTS429Rate limit exceeded
PAYLOAD_TOO_LARGE413Request body exceeds 1 MB

All list endpoints accept page and limit query parameters. limit is capped at 100.

{
"data": [],
"meta": {
"pagination": {
"page": 1,
"limit": 20,
"total": 142,
"totalPages": 8
}
}
}