Skip to content
BuildBase

Items

Let your sellers list what they sell inside your app: a ready form from your item types, hooks for your own screens, or your server on their behalf.

An item is one thing a seller in your app lists: a course, a ticket, a used phone. Each item is written against one of your item types, which decides its fields, how it is priced and what a buyer gets. Your sellers never visit the BuildBase console and never get a BuildBase login: they list items inside your app.

Note

Arrives with selling. Items arrive with selling and run on the same Stripe keys: test keys in Staging for test sales, live keys in Production once live selling is open for your app. Buyers pay for items through checkout.

Requires @buildbase/sdk 1.2.0 or later. <SellerItems>, the item hooks and the item.* events in its catalog arrive with it; earlier versions have none of them.

Walkthrough

New to selling? Zero to first sale: marketplace and Zero to first sale: storefront walk the whole flow once, from Stripe keys to a refund and going live.

When to use it

Every listing is an item: give sellers the ready screen, build your own on the hooks, or let your server list for them (an import from another system, say).

Before you start

  • Selling on, and at least one published item type.
  • The seller has started selling in your app (<SellerHome>). Drafts can be saved while Stripe checks them; publishing needs a seller who can take sales, approved by you if you approve sellers.

Set it up in the console

Nothing to set up for items themselves. To review new items, turn on approval in the item type (Review and refunds), then work the queue at Billing, Selling, Items, Needs review: Approve or Reject with a reason the seller reads.

The Items tab on Needs review: one item waiting, with Approve and Reject in its row menu

Marketplace and storefront

Listing works the same in both shapes. The shape decides where the item's sales are charged, not how it is listed.

What the seller sees

<SellerItems>: their items by status, and each item's form drawn from its type. Problems show beside the field they point at. What the buyer gets is added in the form too, as the type allows: a message, a private link, something the seller delivers by hand (manual), a licence key the platform makes, or something your app delivers (webhook_only). Files, access and bundles have their own screens.

SellerItems with the item form open: title, summary, a USD price of $45.00, and the message a buyer gets after paying

What the buyer sees

Published items through usePublishedItems, signed in or not, and an unlisted item by its link: the public fields, prices and what they get.

Emails and webhooks

The seller gets Item Approved or Item Not Approved from your app's sender when you decide a reviewed item (turn either off under Notifications, System, Selling). Your server gets item.created, item.updated, item.published, item.rejected and item.archived (webhooks).

Limits

Your server sends up to 50 items per bulk call and up to 50 metadata keys per item. A type with a listing limit caps live items by the seller's plan in your app (ITEM_LISTING_LIMIT). A price that has sold never changes: retire it and add another.

Staging and Production

Live sales need live sellers: each seller finishes Stripe's onboarding again in live mode, in Production (go live).

Three ways for a seller to list

WayWhat your app does
A ready screenPlaces <SellerItems /> on a page, signed in as the seller
Your own screensBuilds them on useItemTypes, useSellerItems, useSaveItem and usePublishItem
Your server for themCalls /api/v1/server/commerce/items with an organization API key, on a seller's behalf, one item or many

A seller must have started selling (the person or the workspace, as on the selling page) before adding items. Drafts can be written while Stripe is still checking them; going live needs a seller who can take sales.

The ready screen

import { SellerItems } from '@buildbase/sdk/react';

export function MyItems() {
  return <SellerItems subject={{ user: true }} />;
}

subject is the seller: { user: true } for the signed-in person, or a workspace id. The screen lists the seller's items by status and opens each item's form, drawn from the type's live version: the title, a link name made from it, a summary and description, your fields, options and prices in the currencies and price modes the type allows, stock, and a message or private link a buyer gets. A workspace member without workspace:selling:manage sees the items and cannot change them.

Your own screens

import {
  useItemTypes,
  usePublishItem,
  useSaveItem,
} from '@buildbase/sdk/react';

const { itemTypes } = useItemTypes();
const { save, problems } = useSaveItem({ user: true });
const { run } = usePublishItem({ user: true });

const item = await save({
  typeKey: 'course',
  title: 'Intro to pottery',
  slug: 'intro-to-pottery',
  variants: [
    {
      id: 'standard',
      prices: [{ id: 'usd', currency: 'usd', mode: 'fixed', amount: 4500 }],
      stock: { mode: 'none' },
    },
  ],
});
if (item) await run(item._id, 'publish');

Amounts are in minor units: 4500 is $45.00. A save your item type refuses leaves problems, each with the field it points at (title, variants.standard.prices.usd, data.level) and a sentence to show beside it.

Your server, for a seller

const res = await fetch(`${serverUrl}/api/v1/server/commerce/items/bulk`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${orgId}:${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    items: [
      {
        seller: { type: 'workspace', id: workspaceId },
        typeKey: 'course',
        title: 'Intro to pottery',
        slug: 'intro-to-pottery',
        variants: [
          /* as above */
        ],
        metadata: { erpId: 'SKU-1042' },
      },
    ],
  }),
});
const { results } = await res.json();
// [{ ok: true, item }, { ok: false, code, message, problems }]

Up to 50 items per call, each answered in the order sent, so one bad row does not stop the rest. Your server can also read, save, publish, unlist, archive, approve and reject single items under /api/v1/server/commerce/items/:id. It is the only writer of metadata (up to 50 keys, never shown to sellers or buyers) and of fields you marked as app only. The API key's role needs the Items resource.

Going live

Publish puts an item live, so buyers can find it. It checks the item against its type version, that the seller can take sales (and that you approved them, if you approve sellers), and your listing limit when the type has one. What stops it is answered as a list, kept on the item until the next try.

Unlist keeps an item for sale by its link only. Archive stops new sales; everyone who bought it keeps what they got. A draft that never went live can be deleted; anything else is archived instead.

A price that has sold is never changed: retire it and add a new one, so every order keeps exactly what it paid.

Reviewing items

When an item type asks you to approve new items, Publish sends the item to your review queue instead: Billing > Selling > Items, "Needs review", oldest first. Approve it to put it live, or reject it with a reason the seller sees. A rejected item becomes a draft again when its seller edits it. Editing a live item does not send it back to review.

The seller hears your decision by email, from your app's own sender. Turn either message off under Messaging > Notification events > System > Selling, for example to send your own from your server instead.

Buyers

Published items are public to your app's users:

const res = await fetch(`${serverUrl}/api/v1/public/items?typeKey=course`, {
  headers: { 'x-session-id': sessionId },
});
const { docs } = await res.json();

Filter by typeKey, by seller (sellerType and sellerId) or by title (q). A person who sells is named in seller.subject.id by their seller id (the same as seller.id), never their user id; sellerType=user takes that seller id, or the person's user id. GET /api/v1/public/items/:id also answers an unlisted item. A buyer sees only the fields you made public, what each variant costs, and what they get (never the message or link itself), and never metadata.

Webhooks

EventWhen
item.createdA seller, your server or an import created an item
item.updatedIts content changed
item.publishedIt went live; action is approve when you approved it in review
item.rejectedYou rejected it in review; item.review.reason says why
item.archivedIt stopped selling

Each carries { item, by, action }: the item as your server reads it, metadata included, and who made the change (seller, app or owner).

Errors

A refused request answers { error, message, code }, and problems when there are fields to fix. The console shows the message; the SDK shows each code in the reader's language and puts each problem beside its field.

codeWhat the person seesWhat to do
SELLING_UNAVAILABLESelling is not open for this app yet, or is turned off (publishing and approving wait)The app owner turns selling on, or contacts BuildBase support to open it
SELLER_NOT_FOUNDStart selling before adding itemsStart selling first (<SellerHome>)
SELLER_TERMINALThis seller can no longer sellNothing: a closed seller's account cannot list again
ITEM_NOT_FOUNDNo item with that idReload the list: the item was deleted, or is another seller's
ITEM_INVALIDThe first problem, or how many things to fix before savingFix each entry in problems; each names its field
ITEM_ACCESS_NOT_ALLOWEDThis item type does not let sellers give access to that resource typeUse a resource type the item type lists for sellers; the app owner sets them on the type
ITEM_SLUG_TAKENYou already have an item with this slugPick another slug
ITEM_RESOURCE_TAKENAnother live item already sells thisArchive the other item, or sell something else
ITEM_TYPE_NOT_SELLABLENo published, active item type with that key (or the type is gone, or not for this kind of seller)Pick a live type; the app owner publishes or restores it under Billing > Item types
ITEM_LISTING_LIMITYou have listed as many of these as your plan allows. Archive one, or upgrade, to list another (402)Archive an item, or move to a plan with more listings
ITEM_STATE_CONFLICTThis item changed meanwhile. Reload it and try again (or the action does not fit its status)Reload the item and try again

Permissions

The console's Items resource governs the Items tab: reading every item, and approving, rejecting and archiving them. Owners and admins hold it.