JavaScript/TypeScript SDK
The official JavaScript and TypeScript SDK for Unified Commerce Platform. Built with modern TypeScript, featuring full type safety, React hooks, and comprehensive error handling.
Version: 2.1.0 | License: MIT | Bundle Size: ~45KB (minified + gzipped)
Installation
Install the SDK using your preferred package manager:
# npm
npm install @unified-commerce/sdk
# yarn
yarn add @unified-commerce/sdk
# pnpm
pnpm add @unified-commerce/sdk
# bun
bun add @unified-commerce/sdk
TypeScript Configuration
For the best TypeScript experience, ensure your tsconfig.json
includes:
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020"],
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true
}
}
Quick Start
Basic Setup
import { UnifiedCommerce } from '@unified-commerce/sdk';
const client = new UnifiedCommerce({
apiKey: process.env.UNIFIED_COMMERCE_API_KEY,
environment: 'production', // or 'sandbox' for testing
});
// Query products
const products = await client.products.list({
limit: 10,
category: 'electronics'
});
console.log(products);
React Setup
The SDK includes built-in React hooks for seamless integration:
import { UnifiedCommerceProvider, useProducts } from '@unified-commerce/sdk/react';
// Wrap your app with the provider
function App() {
return (
<UnifiedCommerceProvider
apiKey={process.env.NEXT_PUBLIC_UNIFIED_COMMERCE_API_KEY}
environment="production"
>
<ProductList />
</UnifiedCommerceProvider>
);
}
// Use hooks in your components
function ProductList() {
const { data: products, loading, error } = useProducts({
limit: 20,
category: 'electronics'
});
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
Configuration
Client Options
interface UnifiedCommerceConfig {
// Required: Your API key
apiKey: string;
// Environment: 'production' | 'sandbox'
environment?: string;
// Custom API endpoint (optional)
apiUrl?: string;
// Request timeout in milliseconds (default: 30000)
timeout?: number;
// Maximum retry attempts (default: 3)
maxRetries?: number;
// Enable debug logging (default: false)
debug?: boolean;
// Custom headers to include in all requests
headers?: Record<string, string>;
// HTTP agent for Node.js environments
httpAgent?: any;
}
const client = new UnifiedCommerce({
apiKey: process.env.UNIFIED_COMMERCE_API_KEY,
environment: 'production',
timeout: 60000,
maxRetries: 5,
debug: process.env.NODE_ENV === 'development',
headers: {
'X-Custom-Header': 'value'
}
});
Environment Variables
Store your configuration in environment variables:
# .env.local
UNIFIED_COMMERCE_API_KEY=uc_live_xxxxxxxxxxxxx
NEXT_PUBLIC_UNIFIED_COMMERCE_API_KEY=uc_live_xxxxxxxxxxxxx # For client-side Next.js
Authentication
API Key Authentication
The SDK uses API key authentication. All requests include the API key in the Authorization header:
const client = new UnifiedCommerce({
apiKey: 'uc_live_xxxxxxxxxxxxx'
});
// The SDK automatically includes:
// Authorization: Bearer uc_live_xxxxxxxxxxxxx
Per-Request Authentication
Override the API key for specific requests:
const products = await client.products.list(
{ limit: 10 },
{ apiKey: 'different_api_key' }
);
Token Refresh (Coming Soon)
OAuth token refresh will be supported in version 2.2:
const client = new UnifiedCommerce({
oauth: {
clientId: 'your_client_id',
clientSecret: 'your_client_secret',
refreshToken: 'refresh_token'
}
});
Core Concepts
Products
// List products with filters
const products = await client.products.list({
category: 'electronics',
minPrice: 100,
maxPrice: 1000,
inStock: true,
limit: 20,
offset: 0,
sortBy: 'price',
sortOrder: 'asc'
});
// Get a single product
const product = await client.products.get('product-123');
// Create a product
const newProduct = await client.products.create({
name: 'Wireless Headphones',
description: 'Premium noise-cancelling headphones',
price: 299.99,
category: 'electronics',
sku: 'WH-1000XM5',
inventory: {
quantity: 100,
trackInventory: true
}
});
// Update a product
const updated = await client.products.update('product-123', {
price: 279.99,
inventory: {
quantity: 150
}
});
// Delete a product
await client.products.delete('product-123');
Orders
// Create an order
const order = await client.orders.create({
items: [
{
productId: 'product-123',
quantity: 2,
price: 299.99
},
{
productId: 'product-456',
quantity: 1,
price: 149.99
}
],
customer: {
id: 'customer-789',
email: 'customer@example.com',
name: 'John Doe'
},
shippingAddress: {
street: '123 Main St',
city: 'San Francisco',
state: 'CA',
postalCode: '94105',
country: 'US'
},
billingAddress: {
// Same as shipping or different
},
paymentMethod: {
type: 'card',
token: 'pm_xxxxxxxxxxxxx'
}
});
// List orders
const orders = await client.orders.list({
customerId: 'customer-789',
status: 'pending',
limit: 20
});
// Get order details
const orderDetails = await client.orders.get('order-123');
// Update order status
await client.orders.update('order-123', {
status: 'shipped',
tracking: {
carrier: 'UPS',
trackingNumber: '1Z999AA10123456784'
}
});
// Cancel an order
await client.orders.cancel('order-123', {
reason: 'Customer requested cancellation'
});
Customers
// Create a customer
const customer = await client.customers.create({
email: 'customer@example.com',
name: 'John Doe',
phone: '+1234567890',
addresses: [{
type: 'shipping',
street: '123 Main St',
city: 'San Francisco',
state: 'CA',
postalCode: '94105',
country: 'US'
}]
});
// List customers
const customers = await client.customers.list({
search: 'john',
limit: 20
});
// Update customer
await client.customers.update('customer-123', {
phone: '+9876543210'
});
Inventory
// Get inventory for a product
const inventory = await client.inventory.get('product-123');
// Update inventory
await client.inventory.update('product-123', {
quantity: 100,
location: 'warehouse-1',
reservedQuantity: 5
});
// Bulk update
await client.inventory.bulkUpdate([
{ productId: 'product-123', quantity: 100 },
{ productId: 'product-456', quantity: 50 }
]);
// Track inventory movements
const movements = await client.inventory.movements('product-123', {
startDate: '2024-01-01',
endDate: '2024-01-31'
});
React Hooks
useProducts
import { useProducts } from '@unified-commerce/sdk/react';
function ProductList() {
const {
data: products,
loading,
error,
refetch,
hasMore,
loadMore
} = useProducts({
category: 'electronics',
limit: 20
});
if (loading) return <Spinner />;
if (error) return <Error message={error.message} />;
return (
<>
<ProductGrid products={products} />
{hasMore && (
<button onClick={loadMore}>Load More</button>
)}
</>
);
}
useOrder
import { useOrder } from '@unified-commerce/sdk/react';
function OrderDetails({ orderId }: { orderId: string }) {
const { data: order, loading, error, update } = useOrder(orderId);
const handleUpdateStatus = async () => {
await update({
status: 'shipped',
tracking: { carrier: 'UPS', trackingNumber: '123456' }
});
};
if (loading) return <Spinner />;
if (error) return <Error message={error.message} />;
return (
<div>
<h1>Order {order.id}</h1>
<button onClick={handleUpdateStatus}>Mark as Shipped</button>
</div>
);
}
useCreateOrder
import { useCreateOrder } from '@unified-commerce/sdk/react';
function Checkout({ cart }) {
const { createOrder, loading, error } = useCreateOrder();
const handleCheckout = async () => {
try {
const order = await createOrder({
items: cart.items,
customer: { /* ... */ },
shippingAddress: { /* ... */ }
});
// Redirect to success page
router.push(`/orders/${order.id}/success`);
} catch (err) {
console.error('Checkout failed:', err);
}
};
return (
<button onClick={handleCheckout} disabled={loading}>
{loading ? 'Processing...' : 'Place Order'}
</button>
);
}
useInventory
import { useInventory } from '@unified-commerce/sdk/react';
function InventoryStatus({ productId }: { productId: string }) {
const {
data: inventory,
loading,
update,
subscribe // Real-time updates
} = useInventory(productId);
useEffect(() => {
const unsubscribe = subscribe((updated) => {
console.log('Inventory updated:', updated);
});
return unsubscribe;
}, [subscribe]);
const handleUpdateQuantity = async (quantity: number) => {
await update({ quantity });
};
if (loading) return <Spinner />;
return (
<div>
<p>Available: {inventory.quantity}</p>
<button onClick={() => handleUpdateQuantity(inventory.quantity + 10)}>
Add 10
</button>
</div>
);
}
Error Handling
Error Types
The SDK provides typed errors for better error handling:
import {
UnifiedCommerceError,
AuthenticationError,
ValidationError,
NotFoundError,
RateLimitError,
NetworkError
} from '@unified-commerce/sdk';
try {
const product = await client.products.get('invalid-id');
} catch (error) {
if (error instanceof NotFoundError) {
console.error('Product not found:', error.message);
} else if (error instanceof AuthenticationError) {
console.error('Invalid API key:', error.message);
} else if (error instanceof RateLimitError) {
console.error('Rate limit exceeded. Retry after:', error.retryAfter);
} else if (error instanceof ValidationError) {
console.error('Validation errors:', error.errors);
} else {
console.error('Unexpected error:', error);
}
}
Automatic Retries
The SDK automatically retries failed requests with exponential backoff:
const client = new UnifiedCommerce({
apiKey: 'your-api-key',
maxRetries: 5, // Retry up to 5 times
retryDelay: 1000, // Initial delay of 1 second
retryMultiplier: 2 // Double the delay each retry
});
// The SDK will automatically retry on:
// - Network errors
// - 5xx server errors
// - Rate limit errors (with retry-after header)
Custom Error Handling
const client = new UnifiedCommerce({
apiKey: 'your-api-key',
onError: (error) => {
// Custom error logging
console.error('SDK Error:', error);
// Send to error tracking service
Sentry.captureException(error);
}
});
Webhooks
Webhook Verification
import { verifyWebhook } from '@unified-commerce/sdk';
// Express.js example
app.post('/webhooks/unified-commerce', async (req, res) => {
const signature = req.headers['x-unified-commerce-signature'];
const payload = req.body;
try {
const event = verifyWebhook(
payload,
signature,
process.env.WEBHOOK_SECRET
);
// Handle the verified event
switch (event.type) {
case 'order.created':
await handleOrderCreated(event.data);
break;
case 'order.updated':
await handleOrderUpdated(event.data);
break;
case 'inventory.low':
await handleLowInventory(event.data);
break;
}
res.json({ received: true });
} catch (error) {
console.error('Webhook verification failed:', error);
res.status(400).json({ error: 'Invalid signature' });
}
});
Webhook Types
type WebhookEvent =
| { type: 'order.created'; data: Order }
| { type: 'order.updated'; data: Order }
| { type: 'order.cancelled'; data: Order }
| { type: 'payment.succeeded'; data: Payment }
| { type: 'payment.failed'; data: Payment }
| { type: 'inventory.low'; data: InventoryAlert }
| { type: 'customer.created'; data: Customer }
| { type: 'customer.updated'; data: Customer };
Advanced Features
GraphQL Support
Use GraphQL queries for more flexibility:
import { gql } from '@unified-commerce/sdk';
const CUSTOM_QUERY = gql`
query GetProductsWithReviews($category: String!) {
products(category: $category) {
id
name
price
reviews {
id
rating
comment
author {
name
}
}
}
}
`;
const result = await client.query({
query: CUSTOM_QUERY,
variables: { category: 'electronics' }
});
Batch Operations
// Batch create products
const products = await client.products.batchCreate([
{ name: 'Product 1', price: 99.99 },
{ name: 'Product 2', price: 149.99 },
{ name: 'Product 3', price: 199.99 }
]);
// Batch update
await client.products.batchUpdate([
{ id: 'product-1', price: 89.99 },
{ id: 'product-2', price: 139.99 }
]);
Pagination
// Cursor-based pagination
let cursor: string | undefined;
const allProducts: Product[] = [];
do {
const result = await client.products.list({
limit: 100,
cursor
});
allProducts.push(...result.data);
cursor = result.nextCursor;
} while (cursor);
// Or use async iterator
for await (const product of client.products.iterate({ category: 'electronics' })) {
console.log(product);
}
File Uploads
// Upload product image
const image = await client.products.uploadImage('product-123', {
file: imageFile, // File or Blob
alt: 'Product image',
position: 0
});
// Multiple images
await client.products.uploadImages('product-123', [
{ file: image1, alt: 'Front view' },
{ file: image2, alt: 'Side view' },
{ file: image3, alt: 'Back view' }
]);
Performance Optimization
Caching
import { UnifiedCommerce, CacheStrategy } from '@unified-commerce/sdk';
const client = new UnifiedCommerce({
apiKey: 'your-api-key',
cache: {
strategy: CacheStrategy.StaleWhileRevalidate,
ttl: 300, // 5 minutes
maxSize: 100 // Max 100 cached items
}
});
// This will be cached
const products = await client.products.list({ category: 'electronics' });
// This will use cached data and revalidate in background
const cachedProducts = await client.products.list({ category: 'electronics' });
Request Deduplication
// Multiple simultaneous requests for the same resource
// are automatically deduplicated
const [product1, product2, product3] = await Promise.all([
client.products.get('product-123'),
client.products.get('product-123'),
client.products.get('product-123')
]);
// Only one actual HTTP request is made
Lazy Loading
import { lazyLoadClient } from '@unified-commerce/sdk';
// Client is only initialized when first used
const getClient = lazyLoadClient({
apiKey: process.env.UNIFIED_COMMERCE_API_KEY
});
// Later in your code
const client = getClient();
const products = await client.products.list();
TypeScript Types
Generated Types
All API types are automatically generated from the GraphQL schema:
import type {
Product,
Order,
Customer,
Inventory,
OrderStatus,
PaymentMethod
} from '@unified-commerce/sdk/types';
function processOrder(order: Order): void {
console.log(order.id);
console.log(order.status); // Type: OrderStatus
console.log(order.items); // Type: OrderItem[]
}
Custom Type Guards
import { isProduct, isOrder, isCustomer } from '@unified-commerce/sdk';
function handleEntity(entity: unknown) {
if (isProduct(entity)) {
console.log('Product:', entity.name);
} else if (isOrder(entity)) {
console.log('Order:', entity.id);
} else if (isCustomer(entity)) {
console.log('Customer:', entity.email);
}
}
Testing
Mock Client
import { createMockClient } from '@unified-commerce/sdk/testing';
const mockClient = createMockClient({
products: {
list: jest.fn().mockResolvedValue({
data: [
{ id: '1', name: 'Test Product', price: 99.99 }
],
total: 1
})
}
});
// Use in tests
test('fetches products', async () => {
const products = await mockClient.products.list();
expect(products.data).toHaveLength(1);
});
Test Utilities
import {
mockProduct,
mockOrder,
mockCustomer
} from '@unified-commerce/sdk/testing';
const testProduct = mockProduct({
name: 'Test Product',
price: 99.99
});
const testOrder = mockOrder({
items: [{ product: testProduct, quantity: 2 }]
});
Changelog
Version 2.1.0 (Latest)
- Added React 19 support
- New
useOptimisticUpdate
hook for optimistic UI updates - Improved TypeScript types with stricter generics
- Performance improvements in caching layer
- Added support for Server Components in Next.js 15
Version 2.0.0
- Breaking: Dropped support for Node.js < 18
- New GraphQL client with automatic query optimization
- Added webhook verification utilities
- Improved error handling with typed errors
- Added request deduplication
Version 1.9.0
- Added batch operations support
- New file upload methods
- Improved retry logic
- Added cursor-based pagination
Resources
Support
Need help? We're here for you: