Skip to content

Admin API

Base URL: /api/admin/v1. These routes share domain logic with the Admin UI and are intended for agents, CI, and your own tools. See agents (MCP) if you are wiring an assistant.

GET /api/admin/v1/settings

Shop settings snapshot: general, currencies, locales, tax, shipping zones, SEO, address validation.

PATCH /api/admin/v1/settings

Update one section per request.

Body examples:

{ "general": { "shopName": "Acme", "contactEmail": "[email protected]" } }
{ "currencies": { "defaultCurrency": "USD", "currencies": ["USD", "EUR"] } }
{ "locales": { "defaultLocale": "en", "locales": ["en", "de"] } }
{ "tax": { "mode": "exclusive", "regions": [] } }
{ "shipping": { "zones": [] } }
{ "seo": { "metaTitle": "Acme Shop" } }
{ "addressValidation": { "provider": "noop" } }

Theme activation and plugin enablement use dedicated /themes and /plugins routes (not settings PATCH).

GET /api/admin/v1/themes

List registered themes, active theme id/manifest, and active theme settings values.

PATCH /api/admin/v1/themes

Activate a theme and/or save settings for the active theme.

{ "themeId": "@bermooda/theme-default" }
{ "settings": { "someKey": "value" } }

GET /api/admin/v1/plugins

List registered plugins, enabled ids, display order, and per-plugin settings.

PATCH /api/admin/v1/plugins

Enable/disable, reorder, and/or save settings.

{ "pluginId": "@bermooda/plugin-meilisearch", "enabled": true }
{ "order": ["@bermooda/plugin-meilisearch"] }
{ "pluginId": "@bermooda/plugin-meilisearch", "settings": { "apiKey": "..." } }

GET /api/admin/v1/categories

List category tree. Query: locale.

POST /api/admin/v1/categories

Body: { "title": "Shirts", "slug": "shirts", "locale": "en", "parentId": null, "position": 0 }name is accepted as an alias for title.

GET /api/admin/v1/categories/:id

Get a category (with children/products). Query: locale.

PATCH /api/admin/v1/categories/:id

Update title/slug/parent/position.

DELETE /api/admin/v1/categories/:id

Recursively delete a category and its descendants.

GET /api/admin/v1/products

List products (all — including unpublished).

Query params: page, limit, locale, currency, categoryId, published

POST /api/admin/v1/products

Create a product. The accepted shape matches the catalog core used by Admin (app/core/catalog/index.server.js).

GET /api/admin/v1/products/:id

Get a product by id.

PATCH /api/admin/v1/products/:id

Update a product.

DELETE /api/admin/v1/products/:id

Delete a product.

GET /api/admin/v1/collections

Query: page, limit, q, published.

POST /api/admin/v1/collections

GET /api/admin/v1/collections/:id

PATCH /api/admin/v1/collections/:id

DELETE /api/admin/v1/collections/:id

POST /api/admin/v1/imports

Import products from CSV (multipart or JSON payload — see the route module). Requires imports:write (or admin).

GET /api/admin/v1/inventory/locations

List locations with inventory levels.

POST /api/admin/v1/inventory/locations

Body: { "name": "Warehouse", "code": "WH1", "allowsPickup": false }.

PUT /api/admin/v1/inventory/levels

Set stock for a variant at a location. Requires inventory:write (or admin).

Body: { "variantId": "…", "locationId": "…", "quantity": 10 }

GET /api/admin/v1/orders

Query params: page, limit, status, customerId

GET /api/admin/v1/orders/:id

Get a single order with lines, shipments, and refunds.

PATCH /api/admin/v1/orders/:id

Body: { "status": "confirmed" }

Valid statuses: pending, confirmed, paid, fulfilled, cancelled, refunded.

POST /api/admin/v1/orders/:id/refunds

Body: { "amountCents": 1000, "reason": "Customer request", "providerRefundId": "optional" }

POST /api/admin/v1/orders/:id/shipments

Body: { "carrier": "FedEx", "trackingNumber": "...", "trackingUrl": "..." }

POST /api/admin/v1/orders/:id/returns

Create a return request for an order.

Body: { "reason": "Damaged item", "lines": [{ "orderLineId": "...", "quantity": 1 }] }

GET /api/admin/v1/returns

List returns with pagination. Also returns returnStatuses and returnResolutions.

Query params: page, limit, status, orderId, customerId

GET /api/admin/v1/returns/:id

Get a single return with lines and order summary.

POST /api/admin/v1/returns/:id/approve

Approve a requested return.

Body: { "resolution": "refund" } — optional; defaults to refund.

POST /api/admin/v1/returns/:id/receive

Mark an approved return as received and restock inventory.

POST /api/admin/v1/returns/:id/complete

Complete a received return with refund, store credit, or exchange.

Body: { "resolution": "refund", "refundAmountCents": 1000 }refundAmountCents is optional; defaults to line totals.

POST /api/admin/v1/returns/:id/cancel

Cancel a return before it is received.

GET /api/admin/v1/reviews

List reviews with pagination. Also returns reviewStatuses.

Query params: page, limit, status (pending, approved, rejected, or all), productId, customerId

GET /api/admin/v1/reviews/:id

Get a single review with product title and customer summary.

PATCH /api/admin/v1/reviews/:id

Body: { "status": "approved" } — one of pending, approved, or rejected.

DELETE /api/admin/v1/reviews/:id

Delete a review permanently.

GET /api/admin/v1/customers

Query params: page, limit

GET /api/admin/v1/customers/:id

Get a customer with addresses.

PATCH /api/admin/v1/customers/:id

Body: { "name": "Jane Doe", "phone": "+1555...", "preferredLocale": "en" }

GET /api/admin/v1/customers/:id/consent

Get parsed consent flags and erasure state for a customer.

PATCH /api/admin/v1/customers/:id/consent

Update stored consent preferences.

Body: { "analytics": true, "marketing": false } — include only fields to change.

GET /api/admin/v1/customers/:id/data-export

Export all personal data for a customer as a portable JSON bundle.

POST /api/admin/v1/customers/:id/erase

Anonymize a customer’s personal data while preserving order history. Returns { customerId, anonymizedEmail }. Responds with 409 when the customer was already erased.

GET /api/admin/v1/admin-users

List admin and staff users.

GET /api/admin/v1/admin-users/:id

Get an admin/staff user.

PATCH /api/admin/v1/admin-users/:id

Body: { "role": "admin" } or { "role": "staff" }

Successful Admin API mutations (non-GET) are recorded with actorType: api_key (API key id / label). Admin UI mutations use actorType: admin. Domain events use actorType: system.

GET /api/admin/v1/audit-logs

List audit log entries with pagination. Also returns supportedEvents (domain events recorded by the system subscriber).

Query params: page (default 1), limit (default 50, max 100), action, entityType, actorId

GET /api/admin/v1/audit-logs/:id

Get a single audit log entry.

POST /api/admin/v1/media

Upload a file (multipart/form-data, field file). Requires media:write (or admin). Returns { media } (201).

GET /api/admin/v1/media/:id

Get media metadata. Requires media:read (or admin).

GET /api/admin/v1/discounts

Query params: page, limit, active

POST /api/admin/v1/discounts

GET /api/admin/v1/discounts/:id

PATCH /api/admin/v1/discounts/:id

DELETE /api/admin/v1/discounts/:id

GET /api/admin/v1/api-keys

List all API keys (key hashes are never returned). Query: page, limit.

POST /api/admin/v1/api-keys

Create an API key. The raw key is returned once.

Body: { "label": "CI", "scopes": ["admin"], "expiresAt": null }

GET /api/admin/v1/api-keys/:id

Get an API key metadata record.

DELETE /api/admin/v1/api-keys/:id

Revoke (permanently delete) an API key.

For the first key with no existing credentials, use CLI seed/bootstrap or POST /api/admin/v1/setup/api-key. See Authentication.

Manage outbound webhook subscriptions here. Delivery format, signatures, retries, and the event list are documented on Webhooks.

GET /api/admin/v1/webhook-subscriptions

List webhook subscriptions with pagination. Also returns supportedEvents.

Query params: page (default 1), limit (default 50, max 100).

POST /api/admin/v1/webhook-subscriptions

Body:

{
"url": "https://example.com/webhook",
"events": ["order.created", "payment.refunded"],
"secret": "whsec_your_secret_here",
"label": "My ERP"
}

Use "*" in the events array to receive all domain events.

GET /api/admin/v1/webhook-subscriptions/:id

Get a subscription plus its recent delivery history.

PATCH /api/admin/v1/webhook-subscriptions/:id

Update a subscription. Supported fields: active, label, url, events, secret.

DELETE /api/admin/v1/webhook-subscriptions/:id

Delete a webhook subscription and all its delivery records.

GET /api/admin/v1/marketing/segments

List marketing segments with pagination.

Query params: page (default 1), limit (default 50, max 100).

POST /api/admin/v1/marketing/segments

{
"name": "VIP customers",
"rules": {
"minOrders": 3,
"minSpentCents": 10000,
"customerGroupId": "..."
}
}

GET /api/admin/v1/marketing/segments/:id

Get a segment by id (includes parsed rules).

PATCH /api/admin/v1/marketing/segments/:id

Update a segment name and/or rules.

DELETE /api/admin/v1/marketing/segments/:id

Delete a segment and its campaigns.

GET /api/admin/v1/marketing/campaigns

List email campaigns with pagination.

POST /api/admin/v1/marketing/campaigns

Create a campaign for a segment.

{
"segmentId": "...",
"name": "Summer sale",
"subject": "Don't miss out",
"bodyHtml": "<p>Hi {{name}}, ...</p>"
}

GET /api/admin/v1/marketing/campaigns/:id

Get a campaign by id.

POST /api/admin/v1/marketing/campaigns/:id/send

Send a draft or scheduled campaign to matching segment customers with marketing consent.

GET /api/admin/v1/marketing/abandoned-cart-sequences

List abandoned-cart sequence steps with pagination.

POST /api/admin/v1/marketing/abandoned-cart-sequences

{
"name": "First reminder",
"stepNumber": 1,
"delayMinutes": 60,
"subject": "You left items in your cart"
}

GET /api/admin/v1/marketing/abandoned-cart-sequences/:id

Get a sequence step by id.

PATCH /api/admin/v1/marketing/abandoned-cart-sequences/:id

Update a sequence step (including active toggle).

POST /api/admin/v1/marketing/abandoned-cart-sequences/run

Queue abandoned-cart sequence processing. Returns { queued: true } with status 202.

Shared query params (where relevant): startDate, endDate (ISO date YYYY-MM-DD), limit (default 20, max 100), locale (default shop locale).

Paid sales metrics use order statuses paid, fulfilled, and refunded.

GET /api/admin/v1/reports/overview

Overview KPIs for the range: revenue, paid/total orders, tax, discounts, refunds, AOV, checkout conversion.

Response: { "overview": { ... } }

GET /api/admin/v1/reports/sales-over-time

Daily buckets: orders, revenue, tax, discounts.

Response: { "salesOverTime": [ ... ] }

GET /api/admin/v1/reports/sales-by-product

Top products by revenue (limit).

Response: { "salesByProduct": [ ... ] }

GET /api/admin/v1/reports/sales-by-category

Revenue by category (limit, titles honor locale).

Response: { "salesByCategory": [ ... ] }

GET /api/admin/v1/reports/ops

Operational metrics: abandoned checkouts and recent orders (date-ranged); low stock count + sample variants (current snapshot).

Response: { "ops": { "range", "asOf", "abandonedCheckouts", "recentOrders", "lowStock" } }

GET /api/admin/v1/reports/customers

Customer analytics for the range: new customers, returning customers, paid orders split new vs returning, top customers by revenue.

Guest orders (no customerId) are excluded from order-based metrics.

Response: { "customers": { ... } }

GET /api/admin/v1/reports/inventory

Snapshot inventory analytics: low stock, out of stock, stock value, by location.

Optional query: currency (default shop default), threshold (default 5). Date params are ignored.

Response: { "inventory": { ... } }

GET /api/admin/v1/reports/exports

Scheduled export health: schedule counts, recent runs (no CSV body), failure rate in range.

Response: { "exports": { ... } }

GET /api/admin/v1/reports/dashboard

Composed payload: overview, salesOverTime, salesByProduct, salesByCategory, and ops.

Response: { "report": { ... } }

GET /api/admin/v1/scheduled-exports

List scheduled CSV exports with pagination. Also returns exportTypes and exportSchedules.

Query params: page (default 1), limit (default 50, max 100).

POST /api/admin/v1/scheduled-exports

Body:

{
"label": "Weekly orders",
"exportType": "orders",
"schedule": "weekly",
"recipientEmail": "[email protected]",
"filters": { "startDate": "2026-01-01", "endDate": "2026-01-31" }
}

GET /api/admin/v1/scheduled-exports/:id

Get a scheduled export plus its recent runs.

DELETE /api/admin/v1/scheduled-exports/:id

Delete a scheduled export.

POST /api/admin/v1/scheduled-exports/:id/run

Queue an immediate run of a scheduled export.

GET /api/admin/v1/export-runs/:id

Get export run metadata. Pass includeContent=true to include the CSV payload.

Also registered (see route modules under app/routes/api/admin/v1/):

Resource Notes
pages, menus CMS content
channels, companies, quotes Channels / B2B
gift-cards, loyalty, wishlists Engagement
pos, subscriptions (+ plans) POS / subscriptions
storage Storage provider status
media, media/:id Upload + get media metadata
address-validation/* Providers + validate
back-in-stock-subscriptions Waitlist management
Order/shipment PDF documents Invoice + packing slip