Documentation

Complete guide to using SmartPOS AI point of sale system and API.

Getting Started

Welcome to SmartPOS AI! This guide will help you get your point of sale system up and running quickly.

Setup

SmartPOS AI is a cloud-based solution, so there's no software to install. Simply:

  • Create your account at smartposai.com/register
  • Verify your email address
  • Set up your business profile
  • Add your first products

Configuration

After registration, configure your settings in the Backoffice:

  • Business Details: Name, address, tax information
  • Tax Rates: Configure your regional tax rates
  • Payment Methods: Enable cash, card, and other payment options
  • Receipt Settings: Customize your receipt layout

API Authentication

The SmartPOS API provides read-only access to your products, receipts, and shifts. API access requires the Professional plan or above.

Getting Your API Key

  1. Log in to your Backoffice
  2. Go to Settings → API
  3. Click Generate API Key
  4. Copy the key immediately — it won't be shown in full again

Include your API key in the X-API-Key header with every request:

# Example request curl -X GET "https://yoursubdomain.smartposai.com/api/v1/products" \ -H "X-API-Key: spos_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"

🔐 Keep Your API Key Secure

Never expose your API key in client-side code or public repositories. Use environment variables to store sensitive credentials. You can regenerate your key at any time in Settings → API.

Base URL

All API endpoints use your subdomain as the base URL:

https://{your-subdomain}.smartposai.com/api/v1/

Products API

Retrieve your product catalog and stock levels.

GET /api/v1/products

List all products with optional filtering

Query Parameters

  • store_id — Filter by store (integer)
  • category_id — Filter by category (integer)
  • status — Filter by status: active or inactive (default: all)
  • limit — Results per page (default: 50, max: 200)
  • offset — Pagination offset (default: 0)

Example Response

{ "success": true, "data": [ { "id": 1, "sku": "ESP-001", "name": "Espresso", "price": "2.50", "cost": "0.80", "tax_rate": "20.00", "stock": 150, "category_id": 3, "status": "active", "image_url": null, "created_at": "2025-01-15 10:30:00" } ], "total": 84, "limit": 50, "offset": 0 }
GET /api/v1/products/{id}

Get a single product with per-store stock levels

Example Response

{ "success": true, "data": { "id": 1, "sku": "ESP-001", "name": "Espresso", "price": "2.50", "cost": "0.80", "tax_rate": "20.00", "stock": 150, "category_id": 3, "status": "active", "stores": [ { "store_id": 1, "store_name": "Main Store", "stock": 100 }, { "store_id": 2, "store_name": "Downtown", "stock": 50 } ] } }

Receipts API

Access completed sales receipts and their line items.

GET /api/v1/receipts

List receipts with date range and store filtering

Query Parameters

  • start_date — Start date in YYYY-MM-DD format
  • end_date — End date in YYYY-MM-DD format
  • store_id — Filter by store (integer)
  • limit — Results per page (default: 50, max: 200)
  • offset — Pagination offset (default: 0)

Example Response

{ "success": true, "data": [ { "id": 1042, "order_number": "ORD-20250130-0042", "total": "45.80", "subtotal": "38.17", "tax_total": "7.63", "discount_total": "0.00", "payment_method": "cash", "status": "completed", "customer_name": "John Doe", "created_at": "2025-01-30 14:22:05" } ], "total": 1042, "limit": 50, "offset": 0 }
GET /api/v1/receipts/{id}

Get a single receipt with all line items

Example Response

{ "success": true, "data": { "id": 1042, "order_number": "ORD-20250130-0042", "total": "45.80", "subtotal": "38.17", "tax_total": "7.63", "discount_total": "0.00", "payment_method": "cash", "status": "completed", "customer_name": "John Doe", "created_at": "2025-01-30 14:22:05", "items": [ { "product_name": "Espresso", "quantity": 2, "price": "2.50", "discount": "0.00", "tax": "1.00", "total": "6.00" } ] } }

Shifts API

Access employee shift data including cash tracking and sales totals.

GET /api/v1/shifts

List shifts with filtering by date, store, and status

Query Parameters

  • start_date — Start date in YYYY-MM-DD format
  • end_date — End date in YYYY-MM-DD format
  • store_id — Filter by store (integer)
  • status — Filter by status: open or closed
  • limit — Results per page (default: 50, max: 200)
  • offset — Pagination offset (default: 0)

Example Response

{ "success": true, "data": [ { "id": 87, "user_name": "Ana M.", "store_name": "Main Store", "status": "closed", "opening_cash": "200.00", "closing_cash": "485.30", "total_sales": "312.50", "total_orders": 28, "opened_at": "2025-01-30 08:00:00", "closed_at": "2025-01-30 16:05:00" } ], "total": 87, "limit": 50, "offset": 0 }
GET /api/v1/shifts/{id}

Get shift details including sales breakdown

Example Response

{ "success": true, "data": { "id": 87, "user_name": "Ana M.", "store_name": "Main Store", "status": "closed", "opening_cash": "200.00", "closing_cash": "485.30", "expected_cash": "487.50", "difference": "-2.20", "total_sales": "312.50", "total_orders": 28, "opened_at": "2025-01-30 08:00:00", "closed_at": "2025-01-30 16:05:00", "notes": null } }

Errors & Rate Limits

The API uses standard HTTP status codes. All error responses include a JSON body with a descriptive message.

Status Codes

  • 200 — Success
  • 401 — Invalid or missing API key
  • 403 — Feature not available on your plan
  • 404 — Resource not found
  • 500 — Internal server error

Error Response Format

{ "success": false, "error": "Invalid API key or inactive account." }

Rate Limiting

API requests are limited to 100 requests per minute per API key. If you exceed this limit, you'll receive a 429 status code. Wait a moment before retrying.

Webhooks

Webhooks allow you to receive real-time HTTP notifications when events occur in your SmartPOS AI account. When an event is triggered, we send a POST request with a JSON payload to your registered URL.

Plan Requirement

Webhooks require the Professional plan or above. Free and Starter plans do not have webhook access.

Supported Events

  • receipt.created — A new receipt/sale has been completed
  • product.created — A new product was added
  • product.updated — A product was modified (name, price, stock, etc.)
  • product.deleted — A product was deleted
  • shift.opened — A new shift was started
  • shift.closed — A shift was ended
  • customer.created — A new customer was added
  • customer.updated — A customer record was modified
  • stock.adjusted — Stock level was manually adjusted
  • refund.created — A refund was issued
GET /api/v1/webhooks

List all registered webhooks

Example Response

{ "success": true, "data": [ { "id": 1, "url": "https://example.com/webhook", "events": ["receipt.created", "product.updated"], "is_active": true, "last_triggered_at": "2026-02-07 14:30:00", "failure_count": 0, "created_at": "2026-01-15 10:00:00" } ] }
POST /api/v1/webhooks

Register a new webhook endpoint

Request Body

{ "url": "https://example.com/webhook", "events": ["receipt.created", "shift.closed"] }
DELETE /api/v1/webhooks/{id}

Delete a webhook by ID

Webhook Payload Format

When an event occurs, we send a POST request to your URL with this JSON structure:

{ "event": "receipt.created", "timestamp": "2026-02-07T14:30:00Z", "data": { "id": 1042, "order_number": "ORD-20260207-0042", "total": "45.80", "payment_method": "cash", "status": "completed" } }

Request Headers

Every webhook delivery includes these HTTP headers:

  • Content-Type: application/json
  • User-Agent: SmartPOS-Webhook/1.0
  • X-SmartPOS-Event — The event name (e.g. receipt.created)
  • X-SmartPOS-Signature — HMAC-SHA256 signature of the request body (see below)
  • X-SmartPOS-Delivery-Id — Unique delivery ID for idempotency
  • X-SmartPOS-Timestamp — Unix timestamp of when the event was generated

Verifying the Signature (Recommended)

Each webhook is signed with HMAC-SHA256 using your webhook secret (shown once when you create the webhook). Verify the X-SmartPOS-Signature header to confirm the request really came from SmartPOS AI.

// Node.js example const crypto = require('crypto'); function verifySignature(rawBody, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); }

🔐 Always use timing-safe comparison

Use crypto.timingSafeEqual() (Node) or hash_equals() (PHP) when comparing signatures. Plain string comparison is vulnerable to timing attacks.

Retry Policy

If your endpoint does not return a 2xx status code within 10 seconds, the delivery is marked as failed and retried with exponential backoff:

  • 1st retry: after 1 minute
  • 2nd retry: after 5 minutes
  • 3rd retry: after 30 minutes
  • 4th retry: after 2 hours
  • 5th retry: after 12 hours

After 5 failed retries (or 10 total consecutive failures across deliveries), the webhook is automatically deactivated. Use the X-SmartPOS-Delivery-Id header to handle duplicates idempotently if a retry succeeds after you already processed it.

POST /api/v1/webhooks/{id}/test

Send a test payload to your webhook endpoint (useful for verifying your handler before going live)

Webhook Reliability

If your endpoint returns a non-2xx status code, the delivery is marked as failed. After 10 consecutive failures, the webhook is automatically deactivated. You can re-activate it from Settings → API → Webhooks.

Offline Mode

SmartPOS AI works even without an internet connection. Here's how it works:

  • Transactions are stored locally using IndexedDB
  • Data automatically syncs when connection is restored
  • Products and prices are cached for offline access
  • Receipts can be printed locally