Prerequisites
- Provisioned POS outlet and terminal IDs with matching credentials in the POSSUM back office.
- Firewall access from your integration host to the POSSUM.Api base URL (for example
https://possum.example.com). - The local terminal database connection string so that you can persist the inbound payloads.
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:
- Orders and payments — POST open orders, completed orders, receipts and Swish payments through
/api/Order/PostOpenOrder,/api/Order/PostOrderand/api/Order/PostSwishPayment. - Invoice counters — Update numbering via
POST /api/Setting/PostInvoiceCounterafter you issue new invoices locally. - Cash drawer and deposit history — Report session totals with
POST /api/CashDrawerLog/PostCashDrawerLogand retrieve acknowledgements usingGET /api/DepositHistory/GetDepositHistory. - Customer updates — Call
POST /api/Customer/PostCustomerfor new or edited profiles captured at the terminal. - Diagnostics — Forward device and employee logs through
POST /api/Callback/PostDeviceLogand 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:
- Write the current timestamp to your
LastExecutedDatesetting. - Reset your scheduler (timer or hosted service) to run the next cycle after the configured interval.
- Refresh the bearer token proactively if it will expire before the next cycle.
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.