POSSUM API Quick-Start Integration Guide

This tutorial walks you through the same high-level flow used by the POSSUM.SyncService Windows service so you can bootstrap a terminal-to-back-office synchronisation agent with the POSSUM APIs.

Prerequisites

Step 1 — Request a bearer token

All API controllers derive from BaseAPIController and expect a bearer token that maps the request to a tenant database. Your sync agent should log in with the same credentials configured in the Windows service:

POST /Token
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=terminal.user@possum.com&password=SuperSecret123!

Successful requests return a JSON payload similar to:

{
  "access_token": "<jwt>",
  "token_type": "bearer",
  "expires_in": 1209599,
  ".issued": "2023-09-01T12:00:00Z",
  ".expires": "2023-09-15T12:00:00Z"
}

Store the access_token and include it in the Authorization: Bearer header for every subsequent request. Refresh the token when it expires or when the API returns HTTP 401.

Step 2 — Pull reference data

The first part of each sync cycle brings the terminal up-to-date with settings, users and catalogue data. Call each endpoint with the Dates query string populated with your last successful sync window.

Purpose HTTP call Notes
Settings, printers, campaigns GET /api/Setting/GetSettings?LastExecutedDate=2023-09-01T00:00:00Z&CurrentDate=2023-09-02T00:00:00Z&TerminalId={guid} Synchronise system configuration and update the Last_Executed marker when complete.
Users and permissions GET /api/Admin/GetUsers?LastExecutedDate=...&CurrentDate=...&TerminalId=... Persist updated staff accounts and role assignments to the terminal.
Products, prices, combos GET /api/Product/GetProducts?LastExecutedDate=...&CurrentDate=...&TerminalId=... Also call /api/Category/GetCategories and /api/Product/GetProductCombinations to fully rebuild the catalogue.
Customers & loyalty GET /api/Customer/GetCustomers?LastExecutedDate=...&CurrentDate=...&TerminalId=... Reuse the same token to fetch subscriptions, deposits and discount programs if needed.

After downloading each module, reuse the domain-specific controllers in your integration to upsert the data into the local POS database, mirroring the patterns in SyncController.

Step 3 — Push local activity back to POSSUM

Once inbound data is reconciled, upload any terminal-originated changes. The service batches these operations to keep the sequence deterministic:

  1. Orders and payments — POST open orders, completed orders, receipts and Swish payments through /api/Order/PostOpenOrder, /api/Order/PostOrder and /api/Order/PostSwishPayment.
  2. Invoice counters — Update numbering via POST /api/Setting/PostInvoiceCounter after you issue new invoices locally.
  3. Cash drawer and deposit history — Report session totals with POST /api/CashDrawerLog/PostCashDrawerLog and retrieve acknowledgements using GET /api/DepositHistory/GetDepositHistory.
  4. Customer updates — Call POST /api/Customer/PostCustomer for new or edited profiles captured at the terminal.
  5. Diagnostics — Forward device and employee logs through POST /api/Callback/PostDeviceLog and related endpoints so support can troubleshoot issues.

Each POST should mark the records as synced in your local store once the API responds with HTTP 200. If the call fails, log the exception and retry in the next cycle.

Step 4 — Maintain incremental sync windows

The SyncController keeps track of the last successful run by updating the Last_Executed setting in the terminal database. Reuse this approach so that your GET requests only retrieve deltas, which reduces payload sizes and server load. Always send the same TerminalId that is encoded in your token so the API routes the request to the correct tenant.

After all inbound and outbound calls return successfully:

Sample orchestration loop

The pseudocode below outlines how a headless service can implement the full flow end-to-end:

while (serviceRunning)
{
    token = AcquireToken();
    window = LoadLastExecuted();

    var headers = new { Authorization = $"Bearer {token}" };

    var settingData = GET("/api/Setting/GetSettings", window, headers);
    UpsertSettings(settingData);

    var productData = GET("/api/Product/GetProducts", window, headers);
    UpsertProducts(productData);

    var outboundOrders = LoadUnsyncedOrders();
    foreach (var order in outboundOrders)
    {
        POST("/api/Order/PostOrder", order, headers);
        MarkSynced(order);
    }

    PersistLastExecuted(DateTime.UtcNow);
    SleepUntilNextInterval();
}

By following this pattern you inherit the same resilience and traceability that the shipping POSSUM.SyncService relies on in production.