Supercommerce API Docs
Admin API

Cart Module — Admin

HTTP surface for platform-admin oversight of carts: paginated browse + detail view (priced, vendor-allocated), force-discard, manual reservation release, and a suite of analytics…

HTTP surface for platform-admin oversight of carts: paginated browse + detail view (priced, vendor-allocated), force-discard, manual reservation release, and a suite of analytics queries (funnel, abandonment, top-removed variants, coupon usage, gift attach rate, per-customer cohort).

Source: api-modules/cart/src/controllers/admin-cart.controller.ts, api-modules/cart/src/controllers/admin-cart-analytics.controller.ts.

Carts are first-class entities — every storefront mutation transitions a single row through a pending → checkout_prepared → converted (or abandoned / discarded) lifecycle. The admin surface exposes the same view the storefront sees plus the operational escape hatches needed to unstick reservations.


Conventions

Authentication

All endpoints require a Better-Auth admin session and a role granting the matching cart:* permission.

Endpoint groupPermission
GET /admin/carts, GET /admin/carts/:idcart: view
DELETE /admin/carts/:id, POST /admin/carts/:id/release-reservationscart: manage
GET /admin/cart-analytics/**cart: view

Response envelope

Successful responses are wrapped by ResponseInterceptor:

{
  "data": <payload>,
  "message": "Success",
  "statusCode": 200,
  "metadata": { /* optional, e.g. pagination */ }
}

Error envelope

statusCodeerrorCode examples
400BAD_REQUEST, VALIDATION_ERROR
401UNAUTHORIZED
403FORBIDDEN
404NOT_FOUND
500INTERNAL_SERVER_ERROR, DATABASE_ERROR

Money fields

All money values are integer subunits (paise / cents). Service-layer pricing is single-currency-per-tenant.


Domain types

CartListItem

type CartStatus = "pending" | "checkout_prepared" | "converted" | "abandoned" | "discarded";
type Platform   = "APP" | "WEB" | "BOTH";

type CartListItem = {
  cartId: string;
  cartToken: string;
  customerId: string | null;        // null for guest carts
  status: CartStatus;
  platform: Platform;
  lineCount: number;
  vendorIds: string[];              // distinct vendor ids present in the cart
  lastActivityAt: string;           // ISO
  createdAt: string;                // ISO
};

CartResponse

The full vendor-allocated view used by both storefront and admin. Identical shape to the storefront response — admin sees the same priced breakdown the customer does.

type CartResponse = {
  cartId: string;
  cartToken: string;
  customerId: string | null;
  status: CartStatus;
  platform: Platform;
  version: number;                        // optimistic-lock counter
  bags: Array<{
    vendorId: string;
    vendor: { name: string; slug: string; logo: string | null } | null;
    lines: CartLineResponse[];
    subtotal: number;                     // subunits
    discountAllocated: number;
    totalBeforeShippingAndTax: number;
    shipping: { cost: number } | null;    // null when no shipping provider resolves
  }>;
  cartTotals: {
    subtotal: number;
    discountTotal: number;
    shippingTotal: number;
    total: number;
  };
  appliedCoupons: Array<{
    code: string;
    discountId: string;
    individualUse: boolean;
    freeShipping: boolean;
    allocations: Array<{ vendorId: string; amount: number }>;
  }>;
  pendingGifts: Array<{
    ruleId: string;
    slotCount: number;
    alreadySelectedVariantIds: string[];
    optionVariantIds: string[];
  }>;
  deliveryAddressId: string | null;
  deliveryAddress: AddressResponse | null;  // resolved fresh on every read
  lastActivityAt: string;
  createdAt: string;
};

AddressResponse is the same shape returned by /store/addresses — see customer.md.


Browse + admin actions

Base path: /admin/carts.

GET /admin/carts — List carts

Required permission: cart: view. Uses offset-based pagination (not page/limit) and supports first-class filters for status, customer, vendor, and a lower-bound on lastActivityAt.

Query

NameTypeDefaultNotes
statusCartStatus?Filter by lifecycle status
customerIdstring?Filter to one customer
vendorIdstring?Filter to carts containing at least one line from this vendor
limitint501..500
offsetint0>= 0
activeSinceISO datetime?Inclusive lower bound on lastActivityAt

Response 200 — paginated envelope of CartListItem[].


GET /admin/carts/:id — Get cart detail

Required permission: cart: view. Returns the fully priced, vendor-allocated view (same shape as the storefront cart response).

Response 200CartResponse.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown cart id

DELETE /admin/carts/:id — Force-discard a cart

Required permission: cart: manage. Soft-transitions the cart to discarded. Active inventory reservations held by the cart are released as part of the transition.

Response 204 No Content.

Errors

StatusCodeWhen
404NOT_FOUNDUnknown cart id

POST /admin/carts/:id/release-reservations — Release reservations

Required permission: cart: manage. Operational escape hatch — releases every active inventory reservation batch held by the cart without changing cart status. Use when an abandoned-but-not-yet-expired cart is blocking stock that needs to be freed manually.

Response 200

{ "data": { "releasedBatches": 2 }, "message": "Success", "statusCode": 200 }

Errors

StatusCodeWhen
404NOT_FOUNDUnknown cart id

Cart analytics

Base path: /admin/cart-analytics. Every endpoint requires cart: view.

The window query is shared across most endpoints:

NameTypeDefaultNotes
fromISO datetime?30 days agoInclusive
toISO datetime?nowInclusive
granularity"hourly" | "daily""daily"Bucket size for the funnel

All analytics return data scoped to the entire platform (vendorId: null); the parallel vendor-self endpoints under /vendor/cart-analytics scope to the active vendor.


GET /admin/cart-analytics/funnel — Platform funnel rollup

QueryAnalyticsRangeQuery (above).

Response 200

type FunnelBucket = {
  bucketAt: string;                  // ISO; start of the bucket window
  cartsCreated: number;
  itemsAdded: number;
  itemsRemoved: number;
  couponsApplied: number;
  giftsAttached: number;
  checkoutsPrepared: number;
  cartsAbandoned: number;
  uniqueActiveCarts: number;
};

type FunnelResponse = {
  granularity: "hourly" | "daily";
  vendorId: string | null;           // null at this endpoint
  buckets: FunnelBucket[];
  totals: Omit<FunnelBucket, "bucketAt">;
};

GET /admin/cart-analytics/abandonment — Abandonment summary

QueryAnalyticsRangeQuery.

Response 200

type AbandonmentResponse = {
  vendorId: string | null;           // null at this endpoint
  cartsCreated: number;
  cartsAbandoned: number;
  checkoutsPrepared: number;
  abandonmentRate: number;           // cartsAbandoned / cartsCreated, 0..1
  checkoutRate: number;              // checkoutsPrepared / cartsCreated, 0..1
};

GET /admin/cart-analytics/top-abandoned-variants — Most-removed variants

Query

NameTypeDefaultNotes
from, to, granularityShared window
limitint101..100

Response 200

type TopVariantsResponse = {
  vendorId: string | null;
  items: Array<{
    variantId: string;
    vendorId: string | null;
    removedCount: number;
  }>;
};

GET /admin/cart-analytics/coupon-usage — Coupons applied count

QueryAnalyticsRangeQuery.

Response 200 — service-defined payload (couponsApplied total over the window).


GET /admin/cart-analytics/gift-attach-rate — Gift attach rate

QueryAnalyticsRangeQuery.

Response 200 — service-defined payload (giftsAttached / cartsCreated).


GET /admin/cart-analytics/cohort/:customerId — Per-customer event breakdown

Path params

NameNotes
customerIdBetter-Auth user id

QueryAnalyticsRangeQuery.

Response 200

type CohortResponse = {
  customerId: string;
  byEvent: Array<{ eventType: string; total: number }>;
};

  • admin-rbac — gates every endpoint via cart:view / cart:manage. See admin-rbac.md.
  • order — converted carts produce orders via the order placement flow.
  • inventory — owns the reservation batches that release-reservations flushes.
  • discount — produces the appliedCoupons[] snapshot embedded in CartResponse.
  • free-gift — produces the pendingGifts[] selection state.
  • customer — provides the AddressResponse resolved into deliveryAddress. See customer.md.
  • shipping — supplies the per-bag shipping cost.

On this page