DashboardDeveloper Portal

TypeScript SDK

View on GitHub

The official ElevatedPOS client for Node.js and TypeScript. Strongly typed, zero production dependencies — uses the platform fetch API.

npmv1.2.0MITESM + CJS

Installation

Package name: @elevatedpos/api-client

npm
npm install @elevatedpos/api-client
pnpm
pnpm add @elevatedpos/api-client
yarn
yarn add @elevatedpos/api-client

Authentication

The SDK supports API Key authentication for server-to-server use cases and OAuth 2.0 for partner integrations that act on behalf of a merchant.

API Key (server-side)

import { createClient } from '@elevatedpos/api-client';

const epos = createClient({
  apiKey: process.env.ELEVATEDPOS_API_KEY!,   // never expose this in the browser
  // baseUrl: 'https://sandbox.elevatedpos.com.au', // uncomment to use sandbox
});

OAuth 2.0 (partner apps)

After completing the OAuth flow and receiving tokens, pass the access token via the standard Authorization header by constructing a thin wrapper. Refer to the OAuth docs for the full flow.

// OAuth: use a proxy that injects the bearer token server-side
// and call your own backend endpoints to avoid exposing the token.
// The ElevatedPOS API also accepts:  Authorization: Bearer <access_token>
// Set this at the gateway level when forwarding merchant requests.

Quick Start

import { createClient } from '@elevatedpos/api-client';

const epos = createClient({ apiKey: process.env.ELEVATEDPOS_API_KEY! });

// List products with pagination
const { data: products, meta } = await epos.catalog.products.list({
  isActive: true,
  limit: 20,
});
console.log(`Showing ${products.length} of ${meta.totalCount} products`);

// Search customers
const { data: customers } = await epos.customers.list({ search: 'Jane' });

// Create an order
const { data: order } = await epos.orders.create({
  locationId: 'loc_01HXXXXXXXXXX',
  customerId: customers[0].id,
  lines: [
    { productId: products[0].id, quantity: 2, unitPrice: 4.50 },
  ],
});

console.log('Order created:', order.orderNumber, order.status);

// Adjust inventory after a manual count
await epos.inventory.stock.adjust(products[0].id, {
  locationId: 'loc_01HXXXXXXXXXX',
  quantity: -3,
  reason: 'manual_count',
});

// Accrue loyalty points
await epos.loyalty.accounts.accruePoints(customers[0].id, {
  orderId: order.id,
  points: 50,
  description: 'Purchase reward',
});

Method Reference

All methods are async and return typed promises. Errors throw ElevatedPOSApiError.

catalog.products

client.catalog.products.list(params?)Promise<PaginatedResponse<Product>>

List products. Filter by categoryId, search, isActive, limit, cursor.

client.catalog.products.get(id)Promise<ApiResponse<Product>>

Retrieve a single product by ID.

client.catalog.products.create(data)Promise<ApiResponse<Product>>

Create a new product.

client.catalog.products.update(id, data)Promise<ApiResponse<Product>>

Partial update a product.

client.catalog.products.delete(id)Promise<void>

Delete a product.

catalog.categories

client.catalog.categories.list()Promise<PaginatedResponse<Category>>

List all categories for the org.

client.catalog.categories.get(id)Promise<ApiResponse<Category>>

Retrieve a single category by ID.

orders

client.orders.list(params?)Promise<PaginatedResponse<Order>>

List orders. Filter by status, customerId, locationId, limit, cursor.

client.orders.get(id)Promise<ApiResponse<Order>>

Retrieve a full order with line items.

client.orders.create(data)Promise<ApiResponse<Order>>

Create a new order with line items.

client.orders.updateStatus(id, status)Promise<ApiResponse<Order>>

Transition an order to a new status.

customers

client.customers.list(params?)Promise<PaginatedResponse<Customer>>

List customers. Filter by search, limit, cursor.

client.customers.get(id)Promise<ApiResponse<Customer>>

Retrieve a single customer by ID.

client.customers.create(data)Promise<ApiResponse<Customer>>

Create a new customer record.

client.customers.update(id, data)Promise<ApiResponse<Customer>>

Partial update a customer.

inventory.stock

client.inventory.stock.list(params?)Promise<PaginatedResponse<StockLevel>>

List stock levels. Filter by locationId, lowStock, productId.

client.inventory.stock.get(productId, locationId)Promise<ApiResponse<StockLevel>>

Get stock level for a specific product at a location.

client.inventory.stock.adjust(productId, data)Promise<ApiResponse<StockAdjustment>>

Adjust inventory quantity with a reason.

loyalty.accounts

client.loyalty.accounts.get(customerId)Promise<ApiResponse<LoyaltyAccount>>

Get loyalty account for a customer.

client.loyalty.accounts.transactions(accountId, params?)Promise<PaginatedResponse<LoyaltyTransaction>>

List points transactions for an account.

client.loyalty.accounts.accruePoints(accountId, data)Promise<ApiResponse<LoyaltyTransaction>>

Add loyalty points to an account.

client.loyalty.accounts.redeemPoints(accountId, data)Promise<ApiResponse<LoyaltyTransaction>>

Redeem loyalty points from an account.

webhooks

client.webhooks.list()Promise<PaginatedResponse<Webhook>>

List all registered webhooks for the org.

client.webhooks.create(data)Promise<ApiResponse<Webhook>>

Register a new webhook endpoint. Secret returned only once.

client.webhooks.update(id, data)Promise<ApiResponse<Webhook>>

Update URL, events, label, or enabled state.

client.webhooks.delete(id)Promise<void>

Remove a webhook endpoint.

client.webhooks.test(id)Promise<ApiResponse<...>>

Send a test ping to the webhook URL.

client.webhooks.deliveries(id, params?)Promise<PaginatedResponse<WebhookDelivery>>

List recent delivery attempts with status and duration.

Webhook Verification

ElevatedPOS signs every delivery with X-ElevatedPOS-Signature: sha256=HMAC(secret, body). Use verifyWebhookSignature to validate incoming requests.

import { verifyWebhookSignature } from '@elevatedpos/api-client';

// Next.js App Router example
export async function POST(request: Request) {
  const rawBody = await request.text();
  const signature = request.headers.get('x-elevatedpos-signature') ?? '';

  const isValid = await verifyWebhookSignature(
    rawBody,
    signature,
    process.env.ELEVATEDPOS_WEBHOOK_SECRET!,
  );

  if (!isValid) {
    return new Response('Invalid signature', { status: 401 });
  }

  const event = JSON.parse(rawBody);
  console.log('Event type:', event.type);   // e.g. 'order.completed'
  console.log('Payload:', event.data);

  return new Response('OK', { status: 200 });
}

Register a webhook

const { data: webhook } = await epos.webhooks.create({
  url: 'https://yourapp.com/api/elevatedpos-webhook',
  events: ['order.completed', 'payment.captured', 'inventory.low_stock'],
  label: 'Production handler',
});

// IMPORTANT: save webhook.secret securely now — it is never shown again
// Store it in an environment variable or secrets manager, never log it

// Later: list deliveries for debugging
const { data: deliveries } = await epos.webhooks.deliveries(webhook.id);
deliveries.forEach((d) => {
  console.log(d.event, d.success, d.statusCode, `${d.durationMs}ms`);
});

Error Handling

All failed requests throw a typed ElevatedPOSApiError. Network timeouts throw with status === 0.

import { createClient, ElevatedPOSApiError } from '@elevatedpos/api-client';

const epos = createClient({ apiKey: process.env.ELEVATEDPOS_API_KEY! });

try {
  const { data: product } = await epos.catalog.products.get('nonexistent-id');
} catch (err) {
  if (err instanceof ElevatedPOSApiError) {
    // Strongly typed properties:
    console.error(err.status);          // 404
    console.error(err.message);         // "Not Found"
    console.error(err.detail);          // "Product not found"
    console.error(err.type);            // "https://elevatedpos.com.au/errors/not-found"

    // Convenience getters:
    if (err.isNotFound)        { /* handle 404 */ }
    if (err.isValidationError) { /* handle 422 — check err.detail */ }
    if (err.isUnauthorized)    { /* re-authenticate */ }
    if (err.isForbidden)       { /* insufficient permissions */ }
    if (err.isServerError)     { /* 5xx — retry with backoff */ }
  }
}

TypeScript Types

All types are exported from @elevatedpos/api-client.

ElevatedPOSClientConfig

interface ElevatedPOSClientConfig {
  apiKey: string;           // required — server-side only
  baseUrl?: string;         // default: https://api.elevatedpos.com.au
  timeout?: number;         // default: 30_000 ms
}

Product

interface Product {
  id: string; orgId: string; name: string; sku: string;
  basePrice: number; costPrice?: number; isActive: boolean;
  categoryId?: string; tags: string[]; description?: string;
  imageUrl?: string; barcode?: string; taxRate?: number;
  createdAt: string; updatedAt: string;
}

Order

interface Order {
  id: string; orgId: string; orderNumber: string;
  status: 'pending'|'confirmed'|'in_progress'|'ready'|'completed'|'cancelled'|'refunded';
  subtotal: number; discountTotal: number; taxTotal: number; total: number;
  customerId?: string; locationId?: string; lines: OrderLine[];
  createdAt: string; updatedAt: string;
}

Webhook

interface Webhook {
  id: string; orgId: string; label: string; url: string;
  events: WebhookEvent[]; enabled: boolean;
  secret?: string; // only present on creation response
  createdAt: string; updatedAt: string;
}

ElevatedPOSApiError

class ElevatedPOSApiError extends Error {
  status: number;   // HTTP status code (0 = network error)
  type: string;     // RFC 9457 problem type URI
  message: string;  // human-readable title
  detail?: string;  // additional detail

  get isUnauthorized(): boolean  // status === 401
  get isForbidden(): boolean     // status === 403
  get isNotFound(): boolean      // status === 404
  get isValidationError(): boolean // status === 422
  get isServerError(): boolean   // status >= 500
}

Full source on GitHub

Issues, pull requests, and discussions welcome.

View SDK