Supercommerce API Docs
Store API

Back in Stock Module — Storefront

HTTP surface for back-in-stock ("notify me") requests on a sold-out variant. Signed-in shoppers and — when the operator allows it — guests with just an email address can ask to be told when…

HTTP surface for back-in-stock ("notify me") requests on a sold-out variant. Signed-in shoppers and — when the operator allows it — guests with just an email address can ask to be told when a variant can be ordered again. The message itself is a catalogued, operator-editable template (email + in-app + push), not an ad-hoc send.

Source: api-modules/back-in-stock/src/controllers/store-stock-notification.controller.ts.

This is an optional plugin. When BackInStockModule.forRoot() is removed from app.module.ts, every route below disappears, the inventory listener stops enqueueing restock sweeps, and the notify worker no longer registers.


Conventions

Authentication

EndpointAuth
POST /store/stock-notification/subscribeoptional (customer session or guest email)
GET /store/stock-notification/check-subscriptionoptional
GET /store/stock-notificationrequired (customer session)
DELETE /store/stock-notification/:idrequired (customer session)

The subscriber's identity is the email address, not the user id — a guest may subscribe with nothing else, and a guest who later signs up keeps the request they already made (the account is attached to the existing row).

  • Signed in: the session address is used. Passing a different email is 403 EMAIL_NOT_YOURS, so a session can't sign someone else up.
  • Anonymous: email is required (400 EMAIL_REQUIRED), and the operator must have back_in_stock.guest_enabled on.

Operator settings

Both public keys are readable from GET /store/settings/back_in_stock so the product page can decide whether to render the button before calling anything:

KeyPublicEffect
enabledyesMaster switch. Off ⇒ subscribe returns 403 and no one is notified.
guest_enabledyesOff ⇒ only signed-in customers may subscribe.
max_active_per_emailnoHow many variants one address may wait on at once (default 50).
expiry_daysnoWaiting requests older than this are dropped by a daily sweep (default 180; 0 disables).

Response envelope

{ "data": <payload>, "message": "Success", "statusCode": 200 }

Lists use the standard metadata: { total, limit, offset, hasMore } shape.

Error envelope

statusCodeerrorCode / codeWhen
400EMAIL_REQUIREDAnonymous caller with no email
400TOO_MANY_STOCK_SUBSCRIPTIONSThe address is already at max_active_per_email
403BACK_IN_STOCK_DISABLEDThe operator turned the feature off
403BACK_IN_STOCK_GUEST_DISABLEDAnonymous caller while guest_enabled is off
403EMAIL_NOT_YOURSSigned-in caller passed someone else's address
404NOT_FOUNDUnknown variant, or a subscription that isn't the caller's
409VARIANT_ALREADY_AVAILABLEThe variant can already be ordered

Domain types

type StockSubscription = {
  id: string;
  variantId: string;
  productId: string;
  productTitle: string | null;
  productSlug: string | null;
  variantSku: string | null;
  status: "waiting" | "notified" | "cancelled" | "expired";
  notifiedAt: string | null;   // ISO
  createdAt: string;           // ISO
};

A request is never hard-deleted. It moves to notified once the message goes out (so the same address isn't re-mailed on every subsequent restock), cancelled when withdrawn, or expired by the daily sweep.


Endpoints

POST /store/stock-notification/subscribe — Ask to be notified

Body

FieldTypeNotes
variantIdstringThe sold-out variant
emailstring?Required when anonymous; must match the session address when signed in

Idempotent. Subscribing again while a request is still waiting returns the existing one and emits nothing. Subscribing after being notified creates a fresh request — the shopper is asking about the next restock too.

Rejected with 409 when the variant is already orderable (including backorder / untracked variants, which are always orderable) — there is nothing to wait for. Check stock.isOrderable on GET /store/products/:slug before offering the button.

Response 201StockSubscription.

GET /store/stock-notification/check-subscription — Already waiting?

Query

NameTypeNotes
variantIdstringRequired
emailstring?Required when anonymous; must match the session address when signed in

Response 200

{
  "data": {
    "isSubscribed": true,
    "subscriptionId": "sub_123" // null unless the caller has a session
  }
}

subscriptionId is the withdraw handle, so it is only returned to a caller who proved they own the address by signing in.

GET /store/stock-notification — My requests

Session required. Paginated (limit / offset, standard QueryDto), newest first, optionally filtered by status. Scoped to the session's email address.

Response 200StockSubscription[] + pagination metadata.

DELETE /store/stock-notification/:id — Withdraw a request

Session required. Scoped by email as well as id, so a guessed id belonging to someone else is a 404, not a silent cancel. Returns 204.


How the notification is sent

A restock (inventory.stock.adjusted with a positive delta) or a policy change (inventory.policy.updated — turning on backorder, turning off tracking) enqueues one sweep per variant. The worker re-checks that the variant is genuinely orderable, then walks the waiting rows oldest-first, in batches.

Each subscriber gets:

  • Email — resolved through the operator-editable catalog as back_in_stock.available|customer. Editable under Admin → Templates → Email Templates, including its enable toggle. Guests receive this too; it is the only channel that can reach them.
  • In-app + push — for subscribers with an account, dispatched through the notification orchestrator (which respects their per-category preferences). Editable under Admin → Templates → In-App / Push Notifications.

Template variables: {{product_title}}, {{product_slug}}, {{product_url}}, {{variant_sku}}, {{variant_id}}, {{product_id}}. product_url is absolute when the operator has set storefront_urls.store_url (or the SEO canonical base), and relative otherwise.


  • catalogstock.isOrderable / stock.status on the product detail decide whether to offer the button. See Catalog.
  • settings — the back_in_stock group above. See Settings.
  • notifications — the in-app + push feed the message lands in.

On this page