Frontend Integration

Frontend Integration Guide

Ready to connect your application to BareCommerce Core? This guide covers authentication, API routes, integration patterns, and practical examples.

System Architecture

Key Points:

  • Your frontend communicates with BareCommerce API
  • Payment providers are external (Stripe, PayPal, Square)
  • Orders are created automatically from webhooks, not API calls
  • All data is stored in BareCommerce (you don't need a database)
  • Files are stored in Cloudflare R2 with no egress fees

Key Understanding: Orders Are Webhook-Driven

Important: BareCommerce Core creates orders exclusively via webhooks from payment providers. There is no API endpoint to manually create orders. You cannot POST to create an order.

Instead:

  1. Your frontend creates a Payment Intent with order metadata
  2. Payment provider processes the payment
  3. Payment provider sends a webhook to BareCommerce
  4. BareCommerce automatically creates the order
  5. Your frontend fetches the order via GET endpoint

The Order Flow

Storefront

Customer adds items to cart

Creates Payment Intent (with order metadata)

Payment Provider (Stripe/PayPal/Square)

Customer completes payment

Payment Provider sends webhook

BareCommerce creates order automatically

Frontend fetches order via GET /orders

Show confirmation to customer

Authentication

For Merchant Dashboard

Session-based login:

POST /api/auth/merchant/login
{
  "email": "merchant@example.com",
  "password": "password"
}

Response sets barecommerce_session cookie. OAuth (GitHub, Google) also supported.

For Storefronts & Integrations

API key authentication:

X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxx

API keys are scoped to stores and limited by permissions.

Core API Routes

Authentication

POST   /api/auth/merchant/signup
POST   /api/auth/merchant/login
POST   /api/auth/merchant/logout
GET    /api/auth/merchant/me
POST   /api/auth/merchant/avatar (v1.7 - Upload avatar)
GET    /api/auth/github
GET    /api/auth/google

Products

GET    /api/stores/{storeId}/products
POST   /api/stores/{storeId}/products
GET    /api/stores/{storeId}/products/{id}
PUT    /api/stores/{storeId}/products/{id}
DELETE /api/stores/{storeId}/products/{id}
POST   /api/stores/{storeId}/products/bulk (v1.7 - Bulk operations)
GET    /api/stores/{storeId}/products/attributes (v1.7 - Get attributes)
GET    /api/stores/{storeId}/products/import-schema (v1.7 - Import schema)
GET    /api/stores/{storeId}/products/by-variant-group?variantGroupId=xxx
GET    /api/stores/{storeId}/products/by-attributes?color=red&size=m

Categories

GET    /api/stores/{storeId}/categories
POST   /api/stores/{storeId}/categories
GET    /api/stores/{storeId}/categories/{id}
PUT    /api/stores/{storeId}/categories/{id}
DELETE /api/stores/{storeId}/categories/{id}

Customers

GET    /api/stores/{storeId}/customers
POST   /api/stores/{storeId}/customers
GET    /api/stores/{storeId}/customers/{id}
PUT    /api/stores/{storeId}/customers/{id}
DELETE /api/stores/{storeId}/customers/{id}

Orders (Read-Only)

GET    /api/stores/{storeId}/orders
GET    /api/stores/{storeId}/orders/{id}

⚠️ Important: Orders are created exclusively via payment provider webhooks. There are no POST/PUT/DELETE endpoints for orders.

Media

GET    /api/stores/{storeId}/media
POST   /api/stores/{storeId}/media
GET    /api/stores/{storeId}/media/{id}
PUT    /api/stores/{storeId}/media/{id}
DELETE /api/stores/{storeId}/media/{id}

Pages

GET    /api/stores/{storeId}/pages
POST   /api/stores/{storeId}/pages
GET    /api/stores/{storeId}/pages/{id}
PUT    /api/stores/{storeId}/pages/{id}
DELETE /api/stores/{storeId}/pages/{id}

Webhooks

GET    /api/stores/{storeId}/webhooks
POST   /api/stores/{storeId}/webhooks
GET    /api/stores/{storeId}/webhooks/{id}
PUT    /api/stores/{storeId}/webhooks/{id}
DELETE /api/stores/{storeId}/webhooks/{id}

API Keys

GET    /api/stores/{storeId}/api-keys
POST   /api/stores/{storeId}/api-keys
GET    /api/stores/{storeId}/api-keys/{id}
PUT    /api/stores/{storeId}/api-keys/{id}
DELETE /api/stores/{storeId}/api-keys/{id}

Audit Logs

GET    /api/stores/{storeId}/audit-logs
GET    /api/stores/{storeId}/audit-logs/{id}

Response Format

Single Resource:

{
  "item": { ...fields... }
}

List:

{
  "items": [...],
  "total": 100
}

Error:

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human readable message",
    "details": { ...context... }
  }
}

Common Error Codes

CodeHTTPDescription
VALIDATION_ERROR400Invalid field values
UNAUTHORIZED401Auth required
FORBIDDEN403Insufficient permissions
NOT_FOUND404Resource not found
CONFLICT409Duplicate or state conflict
RATE_LIMITED429Too many requests
INTERNAL_ERROR500Server error

Database Schema at a Glance

Products

id, storeId, title, slug, price, sku, barcode
variantGroupId (groups variants)
attributes (JSON: color, size, etc)
status (draft|published|archived|deleted)
stock, trackStock, allowBackorder
categoryIds, mediaIds (JSON arrays)

Orders

id, orderNumber (auto-generated)
customerId, storeId
status (pending|paid|fulfilled|cancelled)
total, subtotal, tax, shipping, discount
currency (default: USD)
paymentProvider, paymentId, paymentStatus
items (OrderItem[])
shippingAddress, billingAddress (JSON)
placedAt, paidAt, fulfilledAt, cancelledAt

Variants

Variants are just Products with the same variantGroupId:

- Product 1: Blue Shirt / M
- Product 2: Blue Shirt / L  
- Product 3: Red Shirt / M

Query with:

GET /api/stores/{storeId}/products/by-variant-group?variantGroupId=vg_123

Integration Patterns

Pattern 1: Public Storefront

Your Job:

  1. Fetch and display products
  2. Build shopping cart
  3. Create Payment Intent with order metadata
  4. Send to payment provider

BareCommerce Job:

  1. Receive webhook from payment provider
  2. Create order automatically
  3. Make available via GET /orders

Flow:

1. Display products
2. Customer adds items
3. Create Payment Intent
4. Payment Provider
5. Payment webhook
6. BareCommerce creates order
7. GET /orders to fetch
8. Show confirmation

Pattern 2: Merchant Dashboard

Operations:

  • Create/read/update/delete products
  • Create/read/update/delete categories
  • View orders (read-only)
  • Manage customers
  • View activity logs
  • Configure store

Auth: Session (merchant login)

Pattern 3: Headless / Programmatic

Operations:

  • Fetch products
  • Listen to webhooks
  • Read orders
  • Sync to custom systems

Auth: API Key

Common Tasks

Fetch Products

const response = await fetch(
  `https://api.barecommercecore.com/api/stores/${storeId}/products?status=published&limit=20`,
  { headers: { "X-API-Key": apiKey } }
);
const { items } = await response.json();

Fetch Variants

const response = await fetch(
  `https://api.barecommercecore.com/api/stores/${storeId}/products/by-variant-group?variantGroupId=vg_123`,
  { headers: { "X-API-Key": apiKey } }
);
const { items: variants } = await response.json();

Fetch Orders

const response = await fetch(
  `https://api.barecommercecore.com/api/stores/${storeId}/orders?status=paid`,
  { headers: { "X-API-Key": apiKey } }
);
const { items: orders } = await response.json();

Create Payment Intent with Metadata

const stripe = require("stripe")(STRIPE_SECRET_KEY);
 
const paymentIntent = await stripe.paymentIntents.create({
  amount: 9999, // $99.99 in cents
  currency: "usd",
  metadata: {
    store_id: storeId,
    customer_id: customerId,
    items: JSON.stringify([
      { productId: "prod_1", quantity: 2, unitPrice: "29.99" }
    ]),
    subtotal: "59.98",
    tax: "4.80",
    shipping: "10.00"
  }
});
 
return { clientSecret: paymentIntent.client_secret };

Webhooks

Events You'll Receive

order.created        ← Order created from payment
order.updated        - Order status changed
product.created      - New product
product.updated      - Product changed
category.created     - New category
customer.created     - New customer

Webhook Payload

{
  "id": "webhook_event_id",
  "event": "order.created",
  "timestamp": "2024-01-15T10:30:00Z",
  "storeId": "store_123",
  "data": {
    "id": "order_123",
    "orderNumber": "ORD-000001",
    "customerId": "cust_456",
    "total": "99.99",
    "status": "paid",
    "items": [...],
    ...all order fields...
  }
}

Verify Webhook Signature

All webhooks are signed with HMAC-SHA256:

import crypto from "crypto";
 
function verifySignature(body: string, signature: string, secret: string) {
  const hash = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  
  return crypto.timingSafeEqual(
    Buffer.from(hash),
    Buffer.from(signature)
  );
}
 
export async function POST(request: Request) {
  const signature = request.headers.get("x-signature");
  const body = await request.text();
  
  if (!verifySignature(body, signature!, WEBHOOK_SECRET)) {
    return Response.json({ error: "Invalid" }, { status: 401 });
  }
  
  const event = JSON.parse(body);
  
  if (event.event === "order.created") {
    const order = event.data;
    
    // Send confirmation email
    await sendOrderConfirmation(order);
    
    // Notify fulfillment
    await notifyWarehouse(order);
    
    // Update inventory
    await updateInventory(order.items);
  }
  
  return Response.json({ ok: true });
}

Pagination

All list endpoints support:

?limit=50&offset=0
  • limit: 1-200 (default 50)
  • offset: Skip count (default 0)

Error Handling

async function apiCall(url: string, options: RequestInit) {
  try {
    const response = await fetch(url, options);
    
    if (!response.ok) {
      const { error } = await response.json();
      
      switch (error.code) {
        case "VALIDATION_ERROR":
          error.details?.forEach(({ field, reason }) => {
            console.error(`${field}: ${reason}`);
          });
          break;
        
        case "UNAUTHORIZED":
          redirect("/login");
          break;
        
        case "RATE_LIMITED":
          await new Promise(r => setTimeout(r, 1000));
          return apiCall(url, options); // Retry
          break;
        
        default:
          console.error(error.message);
      }
      
      throw new Error(error.code);
    }
    
    return response.json();
  } catch (err) {
    console.error("API error:", err);
    throw err;
  }
}

Integration Checklist

  • Understand orders are webhook-driven only
  • Set up payment provider (Stripe/PayPal/Square)
  • Create API key or set up session auth
  • Implement product fetching
  • Implement category browsing
  • Implement variant selection
  • Build shopping cart
  • Create Payment Intent with metadata
  • Build checkout flow
  • Implement webhook receiver
  • Verify webhook signatures
  • Handle order.created webhook
  • Fetch orders via GET /orders
  • Show order confirmation
  • Implement error handling
  • Test in payment provider test mode
  • Deploy to staging
  • Test end-to-end
  • Deploy to production
  • Switch to live API keys
  • Monitor webhook delivery

Next Steps

For detailed technical specs, see the FRONTEND_INTEGRATION_GUIDE.md in the barecommerce-core repository.