Skip to content

builderblack/storefront-sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@builderblack/storefront-sdk

Typed TypeScript client for building headless storefronts (Next.js, Remix, Astro, native mobile apps, kiosks) against the BuilderBlack platform.

Heads up: this package is for frontend developers building shopper-facing storefronts. If you're building a partner app (analytics, ERP sync, marketing automations), use the partner API directly — see PUBLIC-API.md.

  • Native fetch only — works in browser, Node 18+, edge runtimes
  • Dual ESM + CommonJS exports
  • Zero runtime dependencies
  • Auto Idempotency-Key on writes
  • Auto X-Cart-Session capture from response headers
  • Customer JWT + cart session managed client-side

Install

npm install @builderblack/storefront-sdk

Quick start

import { createStorefrontClient } from '@builderblack/storefront-sdk';

const sf = createStorefrontClient({
  apiUrl:           'https://api.builderblack.com',
  tenantSlug:       'kartse',
  // Server-only — never expose in browser code. Issue from your
  // dashboard at app.builderblack.com/settings/api-tokens.
  storefrontToken:  process.env.BB_STOREFRONT_TOKEN,
});

// List products
const { data: products } = await sf.products.list({ limit: 24 });

// Get one product by slug
const { data: product } = await sf.products.getBySlug('widget-pro');

// Add to cart (creates a guest session on first call)
const { data: cart } = await sf.cart.addItem({
  variantId: product.variants?.[0].id,
  quantity:  1,
});

// Save the cart session for future visits
localStorage.setItem('bb_cart_session', sf.getCartSessionId() ?? '');

Two auth modes

Anonymous (default)

Public endpoints (products, collections, cart) work without auth. Pass tenantSlug so we know which store. Subject to per-IP rate limits (600 req/min default).

Storefront API token (server-side)

Bind a token to the client for elevated rate limits and longer cache TTLs (1h vs 5min):

const sf = createStorefrontClient({
  apiUrl:          'https://api.builderblack.com',
  tenantSlug:      'kartse',
  storefrontToken: process.env.BB_STOREFRONT_TOKEN,
});

Never expose the storefront token in browser JavaScript. It's a server-only credential. Use it in:

  • getServerSideProps / app router server components in Next.js
  • Remix loader functions
  • Astro Astro.locals server-side fetches
  • Backend-for-frontend (BFF) layers in native apps

Customer JWT (per shopper)

After a buyer logs in:

const { data } = await sf.customer.login({ email, password });
// `setCustomerToken` is called automatically by the SDK; subsequent
// /me/* calls authenticate as that customer.

const { data: profile } = await sf.customer.me();
const { data: orders }  = await sf.customer.listOrders();

// On logout
sf.customer.logout();

To persist the session across browser restarts, save the refresh_token (in an httpOnly cookie or localStorage) and call sf.customer.refreshAccessToken(refreshToken) on app boot.

Cart session lifecycle

Carts identify themselves one of two ways:

  • Customer cart — when setCustomerToken() has been called, the server uses customer_id from the JWT.
  • Guest cartX-Cart-Session: <uuid> header. The SDK creates this automatically on the first cart write; you persist the UUID client-side and pass it back on the next page load.
// On first visit — no session yet
const sf = createStorefrontClient({ apiUrl, tenantSlug });
await sf.cart.addItem({ variantId: 'v1', quantity: 1 });
// Server set X-Cart-Session in the response; SDK captured it
const session = sf.getCartSessionId();
localStorage.setItem('bb_cart_session', session ?? '');

// On return visit
const sf = createStorefrontClient({
  apiUrl,
  tenantSlug,
  cartSessionId: localStorage.getItem('bb_cart_session') ?? undefined,
});
const { data: cart } = await sf.cart.get(); // returns the persisted cart

When a guest logs in, the server auto-merges their guest cart into their customer cart.

Resources

Module Methods
sf.products list(params), getBySlug(slug), getById(id)
sf.collections list(), getBySlug(slug), listProducts(id, params)
sf.cart get(), setItems(items), addItem({variantId, quantity}), updateItem(id, qty), removeItem(id), clear()
sf.checkout getShippingRates(address), getTaxQuote({address, subtotal}), validateDiscount({code, ...}), placeOrder(input), getConfirmation(orderId)
sf.customer register(input), login(input), logout(), refreshAccessToken(refresh), me(), updateProfile(input), listAddresses(), addAddress(addr), listOrders(), getOrder(id), cancelOrder(id)
sf.navigation get(menuKey)'header', 'footer', 'mobile', 'legal'
sf.fx rates()
sf.theme live()
sf.raw Direct HTTP access (get / post / patch / put / delete) for endpoints not yet wrapped

Checkout flow

// 1. Get available shipping rates for the buyer's address
const { data: { methods } } = await sf.checkout.getShippingRates({
  country: 'IN', state: 'Karnataka', postal_code: '560001', city: 'Bengaluru',
});

// 2. Get tax quote
const { data: tax } = await sf.checkout.getTaxQuote({
  address: { country: 'IN', state: 'Karnataka', postal_code: '560001' },
  subtotal: '1499.00',
});

// 3. Optionally validate a discount code
const { data: discount } = await sf.checkout.validateDiscount({
  code: 'WEEKEND10',
  subtotal: '1499.00',
  items: [{ variant_id: 'v1', quantity: 1 }],
});

// 4. Place the order — Idempotency-Key auto-added by the SDK
const { data: order } = await sf.checkout.placeOrder({
  customer:         { email, first_name, last_name, phone },
  shipping_address: { /* full address */ },
  shipping_method:  methods[0].id,
  payment_method:   'razorpay',
  discount_code:    'WEEKEND10', // optional
});

// 5. Hand off to payment provider using order.payment_intent
// (Razorpay checkout SDK / Stripe Elements / etc.)

Error handling

Failed requests throw StorefrontApiError:

import { StorefrontApiError } from '@builderblack/storefront-sdk';

try {
  await sf.cart.addItem({ variantId, quantity: 99999 });
} catch (err) {
  if (err instanceof StorefrontApiError) {
    if (err.code === 'OUT_OF_STOCK') {
      // Show "only N left" UI
    }
    if (err.code === 'UNAUTHORIZED') {
      // Refresh customer token
    }
    console.error(err.status, err.code, err.message, err.details);
  }
}

See error code list.

Caching

The platform sets Cache-Control headers on GET responses:

  • Anonymous: public, max-age=60, s-maxage=300, stale-while-revalidate=600
  • With Storefront API token: s-maxage=3600 (1h CDN edge cache)

Use the SDK in a server-side renderer behind a CDN (Vercel Edge, Cloudflare Workers, your own Varnish) to serve product pages at edge speed without polling our origin.

Migrating from Shopify

If you have a Hydrogen / Storefront-Kit codebase, see STOREFRONT-API.md § 12 for a compatibility table.

License

MIT.

Links

  • Full API reference: STOREFRONT-API.md
  • Reference Next.js storefront: github.com/builderblack/storefront-starter
  • Bug reports: partners@builderblack.com

About

Typed TypeScript client for building headless storefronts (Next.js, Remix, Astro, native apps) against the BuilderBlack platform

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors