Main
Home About Premium Contact
Tools
WorkStack CORE 🔥 PayCard Designer Invoice Maker WorkStack Cloud Waybills PO Generator Projects
Dashboard / Login

OAuth2 Authentication and Setup

Published on March 22, 2026

OAuth2 Authentication and Setup

Published on March 22, 2026 (Updated July 1, 2026)

WorkStack Core API – OAuth 2.0 Integration Guide

Version 2.0
WorkStack – The Operating System for Business

1. Introduction

WorkStack Core is a complete business management platform that stores user data (inventory, sales, clients, invoices, etc.). Third‑party applications can request access to a user's data using OAuth 2.0. WorkStack handles authentication, authorization, and data storage. Premium users gain access to advanced analytics.

1.1 Key Concepts

1.2 Benefits of Using OAuth

2. OAuth 2.0 Authorization Code Flow – Step by Step

2.1 Register Your Application

Before you can start, you must register your application with WorkStack. Provide:

After registration, you will receive:

2.2 Obtain an Authorization Code

Direct the user to the authorization endpoint:

GET https://workstack.com.ng/oauth/authorize.php
    ?response_type=code
    &client_id=YOUR_CLIENT_ID
    &redirect_uri=YOUR_REDIRECT_URI
    &scope=SCOPES
    &state=STATE

Parameters:

ParameterTypeRequiredDescription
response_typestringyesMust be code.
client_idstringyesYour client ID.
redirect_uristringyesMust match the registered URI exactly (including trailing slash).
scopestringyesSpace‑separated list of scopes (e.g., profile.read sales.read inventory.read).
statestringrecommendedA random string your app generates to prevent CSRF. It will be returned in the callback.

Example:

https://workstack.com.ng/oauth/authorize.php?response_type=code&client_id=rikizy_prod&redirect_uri=https%3A%2F%2Frikizy.com%2Foauth%2Fcallback&scope=profile.read%20sales.read%20inventory.read&state=abc123xyz

The user will be prompted to log in to WorkStack (if not already) and grant the requested permissions. After approval, WorkStack redirects to your redirect_uri with two query parameters:

2.3 Exchange Authorization Code for Tokens

Your server must exchange the code for an access token and a refresh token.

POST to https://workstack.com.ng/oauth/token.php with form data:

grant_type=authorization_code
client_id=YOUR_CLIENT_ID
client_secret=YOUR_CLIENT_SECRET
code=AUTHORIZATION_CODE
redirect_uri=YOUR_REDIRECT_URI

Response (success):

{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 86400,
  "refresh_token": "def50200...",
  "scope": "profile.read sales.read inventory.read"
}

Store these tokens securely, associated with the user. Never expose the access token to the client side.

2.4 Use the Access Token

Include the token in the Authorization header of every API request:

Authorization: Bearer YOUR_ACCESS_TOKEN

2.5 Refresh the Access Token

When the access token expires (after 86400 seconds), use the refresh token to get a new one.

POST to https://workstack.com.ng/oauth/token.php:

grant_type=refresh_token
client_id=YOUR_CLIENT_ID
client_secret=YOUR_CLIENT_SECRET
refresh_token=YOUR_REFRESH_TOKEN

Response:

{
  "access_token": "new_access_token",
  "token_type": "Bearer",
  "expires_in": 86400,
  "refresh_token": "new_refresh_token"
}

Replace the stored token pair with the new values.

3. Scopes and Permissions

Scopes define what your application is allowed to do. Request only the scopes you need.

Scope Description API Actions
profile.read Read user profile (business name, etc.)
sales.read Read sales records, analytics, forecasts sales, get_sale_details, analytics_summary, sales_trend, top_products, payment_methods, get_insights, customer_metrics, inventory_turnover, sales_forecast, cash_flow, profit_margin
sales.write Create, edit, void sales record_sale, clear_debt, void_sale
inventory.read Read inventory items inventory, search_items, get_item_variants, get_item_details, get_variants
inventory.write Create, edit, delete inventory items add_item, edit_item, delete_item, save_variant, generate_variants, delete_variant
clients.read Read client ledger get_clients_json, get_client_by_id, get_client_debts
clients.write Create, edit, delete clients add_client, edit_client, delete_client
invoices.read Read invoices list_invoices, get_invoice (via api_cloud.php)
invoices.write Create, edit, delete invoices save_invoice_draft, delete_invoice (via api_cloud.php)
reports.read Generate and download reports export_clients_csv, export_sales_csv, export_inventory_csv, sales_report_pdf, export_clients_pdf, export_inventory_pdf, export_full_data, logs
expenses.read Read expense records list_expenses
expenses.write Create, edit expenses add_expense, edit_expense
bundles.read Read bundle definitions get_bundles, get_bundle_details, get_bundle_items
bundles.write Create, edit, delete bundles save_bundle, delete_bundle
suppliers.read Read supplier list list_suppliers, list_suppliers_for_select
suppliers.write Create, edit, delete suppliers add_supplier, edit_supplier, delete_supplier
deliveries.read Read delivery records and tracking list_deliveries, get_delivery, get_delivery_by_code
deliveries.write Create, update, manage deliveries create_delivery, update_delivery, update_delivery_status, complete_delivery_with_code, return_delivery, delete_delivery, add_carrier, list_carriers, delete_carrier, add_rider, list_riders, delete_rider
import.data Import clients and inventory via CSV/JSON import_clients, import_inventory, import_data, download_client_template, download_product_template

Note: All analytics actions (analytics_summary, sales_trend, etc.) require the user to have an active premium subscription. If they do not, the API returns 403 Forbidden with a message to upgrade.

4. API Endpoints – Detailed Reference

All endpoints are accessed via https://workstack.com.ng/api_core.php (or api_cloud.php for invoices). Use the action parameter to specify the operation.

4.1 Core Business Analytics (Premium Only)

These endpoints provide insights into business performance. They all require the sales.read scope and a premium subscription.

4.1.1 analytics_summary

Description: Get basic counts, revenue, expenses, and profit for a given period.
Use cases: Dashboard overview, period‑over‑period comparison, executive summaries.

HTTP Method: GET or POST
Endpoint: api_core.php?action=analytics_summary

Parameters:

ParameterTypeRequiredDescription
rangestringnoOne of: today, yesterday, week, month, year, custom. Default: month.
start_datedateif range=customStart date in YYYY-MM-DD.
end_datedateif range=customEnd date in YYYY-MM-DD.

Example request:

GET https://workstack.com.ng/api_core.php?action=analytics_summary&range=month
Authorization: Bearer <token>

Example response:

{
  "success": true,
  "client_count": 42,
  "product_count": 127,
  "revenue": 1250000,
  "expenses": 350000,
  "profit": 900000
}

Error codes:

4.1.2 sales_trend

Description: Get sales totals grouped by month (last 12 months or custom range).
Use cases: Trend charts, year‑over‑year analysis, forecasting.

Parameters: Same as analytics_summary.

Example response:

{
  "success": true,
  "trend": [
    { "month": "2025-01", "total": 120000 },
    { "month": "2025-02", "total": 150000 },
    { "month": "2025-03", "total": 180000 }
  ]
}

4.1.3 top_products

Description: List the 5 best‑selling products by quantity sold.
Use cases: Identify popular items, stock prioritization, marketing focus.

Parameters: Same as analytics_summary.

Example response:

{
  "success": true,
  "products": [
    { "item_name": "Bag of Pure Water", "total_qty": 45, "total_revenue": 45000 },
    { "item_name": "Cement", "total_qty": 30, "total_revenue": 30000 }
  ]
}

4.1.4 payment_methods

Description: Breakdown of sales by payment method (Cash, Transfer, POS, Debt).
Use cases: Understand customer payment preferences, cash flow planning.

Parameters: Same as analytics_summary.

Example response:

{
  "success": true,
  "methods": [
    { "payment_method": "Cash", "count": 12, "total": 300000 },
    { "payment_method": "Transfer", "count": 8, "total": 250000 },
    { "payment_method": "Debt", "count": 5, "total": 150000 }
  ]
}

4.1.5 get_insights

Description: Return a list of business insights (e.g., best seller, low stock, top debtor) for the period.
Use cases: Proactive recommendations, alerts, decision support.

Parameters: Same as analytics_summary.

Example response:

{
  "success": true,
  "insights": [
    {
      "type": "success",
      "title": "🔥 Best Seller",
      "message": "Bag of Pure Water is your top seller with 45 units sold."
    },
    {
      "type": "warning",
      "title": "⚠️ Low Stock",
      "message": "Items running low: Cement (3 left)"
    }
  ]
}

4.1.6 customer_metrics

Description: Top 10 customers by total spent (within the date range). Includes order count, average order, and last purchase date.
Use cases: Loyalty programs, personalized offers, credit limit assessment.

Parameters: Same as analytics_summary.

Example response:

{
  "success": true,
  "customers": [
    {
      "client_id": 1,
      "client_name": "John Doe",
      "client_phone": "08012345678",
      "order_count": 5,
      "total_spent": 150000,
      "avg_order": 30000,
      "last_purchase": "2025-03-15 10:30:00"
    }
  ]
}

4.1.7 inventory_turnover

Description: Get turnover rates and days in stock for each product.
Use cases: Identify slow‑moving items, optimize inventory, reduce holding costs.

Parameters: Same as analytics_summary.

Example response:

{
  "success": true,
  "items": [
    {
      "item_id": 1,
      "item_name": "Bag of Pure Water",
      "current_stock": 20,
      "sold": 10,
      "turnover_rate": 33.33,
      "days_in_stock": 60
    }
  ]
}

4.1.8 sales_forecast

Description: Predict next month's sales based on the last 6 months of data using linear regression.
Use cases: Financial planning, staffing, procurement.

Parameters: None.

Example request: action=sales_forecast

Example response:

{
  "success": true,
  "months": [ ... ],
  "forecast": 128000,
  "last_month": 120000,
  "trend": "up"
}

4.1.9 cash_flow

Description: Projected cash flow for the next 30 days based on average daily sales, expenses, and outstanding receivables/payables.
Use cases: Liquidity planning, investment timing.

Parameters: None.

Example response:

{
  "success": true,
  "avg_daily_sales": 8000,
  "avg_daily_expenses": 3000,
  "receivables": 50000,
  "payables": 20000,
  "projected_inflow_30d": 265000,
  "projected_outflow_30d": 110000,
  "net_cash_flow": 155000
}

4.1.10 profit_margin

Description: Show profit margins per product (requires cost_price column to exist).
Use cases: Pricing strategy, cost reduction, product mix optimization.

Parameters: None.

Example response:

{
  "success": true,
  "items": [
    {
      "item_id": 1,
      "item_name": "Bag of Pure Water",
      "unit_price": 800,
      "cost_price": 500,
      "gross_profit": 300,
      "margin_percent": 37.50
    }
  ]
}

Error: If the cost_price column does not exist, returns a message with the required ALTER statement.

4.2 Inventory Management

These endpoints manage stock items. They require the inventory.read scope for read operations and inventory.write for write operations.

4.2.1 inventory (alias get_inventory_json)

Description: List all inventory items (including variants).
Use cases: Stock overview, product catalog, POS integration.

HTTP Method: GET
Endpoint: api_core.php?action=inventory

Parameters: None.

Example request:

GET https://workstack.com.ng/api_core.php?action=inventory

Example response:

{
  "success": true,
  "items": [
    {
      "item_id": 1,
      "item_name": "Bag of Pure Water",
      "unit_price": 800,
      "stock_qty": 50,
      "low_stock_threshold": 5,
      "item_internal_notes": "Popular item",
      "parent_id": null,
      "attributes": null,
      "parent_name": null
    },
    {
      "item_id": 2,
      "item_name": "Bag of Pure Water (Colour:Red)",
      "unit_price": 800,
      "stock_qty": 10,
      "parent_id": 1,
      "attributes": { "Colour": "Red" }
    }
  ]
}

4.2.2 search_items

Description: Search for inventory items or bundles by name.
Use cases: Quick product lookup, autocomplete in POS.

Parameters:

ParameterTypeRequiredDescription
querystringyesSearch term (minimum 1 character).

Example: action=search_items&query=water

Response:

{
  "success": true,
  "items": [
    {
      "item_id": 1,
      "item_name": "Bag of Pure Water",
      "unit_price": 800,
      "parent_id": null,
      "variant_count": 2,
      "type": "item"
    }
  ]
}

Note: type is "item" for regular items, "parent" for items with variants, and "bundle" for bundles.

4.2.3 add_item

Description: Create a new inventory item (or variant).
Use cases: Product onboarding, adding new SKUs.

HTTP Method: POST
Parameters (form‑encoded):

ParameterTypeRequiredDescription
namestringyesItem name.
pricedecimalyesUnit price.
stockintyesInitial stock quantity.
thresholdintnoLow stock alert threshold (default 5).
notesstringnoInternal notes.
parent_idintnoIf this is a variant, the ID of the parent item.
attributesJSON stringnoAttributes for variants (e.g., {"Colour":"Red"}).
supplier_idintnoSupplier ID for this item.

Example POST: action=add_item&name=Product&price=1000&stock=50&threshold=5

Response: { "success": true, "item_id": 1 }

4.2.4 edit_item

Description: Update an existing inventory item.
Use cases: Price changes, stock adjustments, editing notes.

Parameters: Same as add_item, plus item_id.

Example: action=edit_item&item_id=1&name=New Name&price=900&stock=45

4.2.5 delete_item

Description: Delete an inventory item (and its variants, if cascading).
Use cases: Removing discontinued products.

Parameters: item_id

Example: action=delete_item&item_id=1

4.2.6 get_variants

Description: Get all variants of a parent item.
Use cases: Displaying options in POS, product configuration.

HTTP Method: POST
Parameters (POST body): parent_id

Example POST: action=get_variants&parent_id=1

Response: Array of variant items.

4.2.7 save_variant

Description: Create or update a single variant.
Use cases: Adding a new colour/size to an existing product.

Parameters:

Example: action=save_variant&parent_id=1&name=Red&price=900&stock=10&attributes={"Colour":"Red"}

4.2.8 delete_variant

Description: Delete a specific variant.

Parameters: variant_id

4.2.9 generate_variants

Description: Generate all possible combinations of attributes for a parent item (Cartesian product).
Use cases: Quickly create a full product family.

Parameters:

[
  { "type": "Colour", "values": ["Red", "Blue"] },
  { "type": "Size", "values": ["S", "M", "L"] }
]

Example: action=generate_variants&parent_id=1&attributes=[{"type":"Colour","values":["Red","Blue"]}]

Response: { "success": true, "count": 6 }

4.2.10 get_item_details

Description: Get full details for a single inventory item (including variant list if parent).
Use cases: Product editing screen, detail view.

HTTP Method: POST
Parameters (POST body): item_id

Example POST: action=get_item_details&item_id=1

Response: Item object with item_id, name, price, stock, variants (array if parent).

4.2.11 get_item_variants

Description: Get all variant rows for a parent item.
Use cases: Variant management UI.

HTTP Method: POST
Parameters (POST body): parent_id

Example POST: action=get_item_variants&parent_id=1

Response: Array of variant items.

4.3 Sales & Transactions

These endpoints record sales, manage debts, and retrieve sales history. They require sales.read for read actions and sales.write for write actions.

4.3.1 record_sale

Description: Record a new sale (POS). Deducts stock and updates client balance if payment method is "Debt".
Use cases: Checkout, point‑of‑sale, invoice payment.

HTTP Method: POST
Parameters (form‑encoded):

ParameterTypeRequiredDescription
client_idintnoClient ID (0 or omitted for walk‑in).
payment_methodstringnoOne of: Cash, Transfer, POS, Debt. Default: Cash.
cartJSONyesArray of items: [{"id":1, "qty":2, "price":1000}, ...].

Example POST:

action=record_sale&client_id=123&payment_method=Cash&cart=[{"id":1,"qty":2,"price":1000}]

Response: { "success": true, "sale_ids": [123, 124], "sale_id": 123 }. sale_id is the first ID when multiple items; use sale_ids array for all.

4.3.2 sales

Description: List sales for a given month.
Use cases: Sales history, monthly reports.

Parameters:

Example: action=sales&month=2025-03

Response:

{
  "success": true,
  "sales": [
    {
      "sale_id": 1001,
      "sale_date": "2025-03-15 10:30:00",
      "client_name": "John Doe",
      "payment_method": "Cash",
      "total_amount": 2000
    }
  ]
}

4.3.3 get_sale_details

Description: Get detailed information about a specific sale (including items).
Use cases: Receipt printing, detailed transaction view.

Parameters: sale_id

Example: action=get_sale_details&sale_id=1001

Response:

{
  "success": true,
  "sale": {
    "sale_id": 1001,
    "sale_date": "2025-03-15 10:30:00",
    "client_name": "John Doe",
    "payment_method": "Cash",
    "total_amount": 2000,
    "items": [
      { "item_name": "Product A", "qty_sold": 2, "unit_price": 1000, "line_total": 2000 }
    ]
  }
}

4.3.4 clear_debt

Description: Record a debt payment (reduces client's current balance).
Use cases: Receiving payments from customers on credit.

Parameters:

Example: action=clear_debt&debt_id=DEBT-20250315-123456&amount=5000

Note: The legacy client_id + sale_amount parameters are deprecated. Use debt_id + amount instead.

4.3.5 void_sale

Description: Cancel a sale. Restores stock and reverses any debt adjustment.
Use cases: Correcting erroneous entries, refunds.

Parameters: sale_id

Example: action=void_sale&sale_id=1001

4.4 Customer Management

These endpoints manage clients (customer ledger). They require clients.read for read actions and clients.write for write actions.

4.4.1 get_clients_json

Description: List all clients with their current balance.
Use cases: Customer directory, debtors list.

Example: action=get_clients_json

Response:

{
  "success": true,
  "clients": [
    {
      "client_id": 1,
      "client_name": "John Doe",
      "client_phone": "08012345678",
      "current_balance": 5000,
      "client_notes": "Regular customer"
    }
  ]
}

4.4.2 get_client_by_id

Description: Get a single client by ID.
Use cases: Editing client details, showing profile.

Parameters: client_id

Example: action=get_client_by_id&client_id=1

4.4.3 add_client

Description: Create a new client.
Use cases: Adding a customer at checkout.

HTTP Method: POST
Parameters (POST body):

Response: { "success": true, "client_id": 456 }

4.4.4 edit_client

Description: Update client details.

Parameters: client_id, name, phone, email, balance, notes.

4.4.5 delete_client

Description: Delete a client. Only allowed if client has no sales.
Use cases: Removing duplicate or test entries.

Parameters: client_id

4.4.6 get_client_debts

Description: Get all unpaid debts for a specific client.

Parameters: client_id

Example response:

{
  "success": true,
  "debts": [
    {
      "debt_id": "DEBT-20250315-123456",
      "total_amount": 5000,
      "sale_date": "2025-03-15 10:30:00"
    }
  ]
}

4.5 Invoices (via api_cloud.php)

These endpoints manage digital invoices. They require invoices.read and invoices.write scopes.

4.5.1 list_invoices

Description: List invoices with optional filtering.
Use cases: Invoice dashboard, accounting integration.

Parameters:

Example: action=list_invoices&status=paid

Response: Array of invoice summaries.

4.5.2 get_invoice

Description: Get a single invoice with all details.
Use cases: Displaying invoice, printing.

Parameters: invoice_id

4.5.3 save_invoice_draft

Description: Create or update an invoice. All fields are sent as POST data.
Use cases: Drafting and finalising invoices.

Parameters: All invoice fields (client info, items, totals, dates, styling, etc.). See the full invoice structure in the database.

4.5.4 delete_invoice

Description: Delete an invoice.
Use cases: Removing drafts or cancelled invoices.

Parameters: invoice_id

4.6 Reports & Exports

These endpoints generate downloadable CSV/PDF reports. They require reports.read scope.

4.6.1 export_clients_csv

Description: Export all clients to CSV.
Use cases: Data backup, import to other systems.

Example: action=export_clients_csv
Response: CSV file download.

4.6.2 export_sales_csv

Description: Export all sales to CSV.
Use cases: Accounting software import, audit trail.

Example: action=export_sales_csv

4.6.3 export_inventory_csv

Description: Export inventory to CSV.
Use cases: Stocktaking, bulk updates.

4.6.4 sales_report_pdf

Description: Generate a PDF sales report for a date range.
Use cases: Monthly reports, client statements.

Parameters: start (YYYY‑MM‑DD), end (YYYY‑MM‑DD) via GET.
Example: action=sales_report_pdf&start=2025-03-01&end=2025-03-31

4.6.5 export_clients_pdf

Description: Generate and download a PDF report of all clients.

4.6.6 export_inventory_pdf

Description: Generate and download a PDF report of all inventory items.

4.6.7 export_full_data

Description: Export all business data (clients, inventory, sales, expenses, suppliers) as a ZIP file containing CSV files.

4.7 Expenses

These endpoints manage business expenses. They require expenses.read for read actions and expenses.write for write actions.

4.7.1 add_expense

Description: Record a new expense. When the category is Restock, stock quantity is automatically updated.
Use cases: Recording business costs, inventory restocking.

HTTP Method: POST
Parameters:

ParameterTypeRequiredDescription
amountfloatyesExpense amount (must be > 0).
categorystringnoAny category name. For restocking, use Restock. Default: General.
descriptionstringnoExpense description.
supplier_idintnoSupplier ID (if expense is related to a supplier).
item_idintif category=RestockInventory item ID to restock.
restock_qtyintif category=RestockQuantity to add to stock.

Example (General): action=add_expense&amount=5000&category=Utilities&description=Electricity+bill

Example (Restock): action=add_expense&amount=20000&category=Restock&item_id=1&restock_qty=20&supplier_id=1

4.7.2 list_expenses

Description: List all expenses for the current business, ordered by date descending.

Example response:

{
  "success": true,
  "data": [
    {
      "expense_id": 1,
      "amount": 5000,
      "category": "Utilities",
      "description": "Electricity bill",
      "date": "2025-03-15 10:30:00"
    }
  ]
}

4.7.3 edit_expense

Description: Update an existing expense record.

Parameters: expense_id (required), amount, category, description.

4.8 Bundles

Bundles are groups of inventory items sold together as a single product. They require bundles.read for read actions and bundles.write for write actions.

4.8.1 get_bundles

Description: List all bundles with item counts.

4.8.2 get_bundle_details

Description: Get a single bundle with its constituent items.
HTTP Method: POST
Parameters (POST body): bundle_id

4.8.3 get_bundle_items

Description: Get items within a bundle with stock quantities (useful for POS).
HTTP Method: POST
Parameters (POST body): bundle_id

4.8.4 save_bundle

Description: Create or update a bundle.

HTTP Method: POST
Parameters:

ParameterTypeRequiredDescription
bundle_idintnoOmit to create new bundle, include to update.
namestringyesBundle name.
descriptionstringnoBundle description.
pricedecimalyesBundle selling price (must be > 0).
itemsJSONyesArray of {"item_id": int, "quantity": int}.

4.8.5 delete_bundle

Description: Delete a bundle.
Parameters: bundle_id

4.9 Suppliers

These endpoints manage suppliers/vendors. They require suppliers.read for read actions and suppliers.write for write actions.

4.9.1 list_suppliers

Description: List all suppliers with full details.

4.9.2 list_suppliers_for_select

Description: List suppliers as id/name pairs (for dropdown selectors).

4.9.3 add_supplier

Description: Create a new supplier.
Parameters: name (required), contact_person, phone, email, address, notes.

4.9.4 edit_supplier

Description: Update supplier details.
Parameters: supplier_id, name, contact_person, phone, email, address, notes.

4.9.5 delete_supplier

Description: Delete a supplier.
Parameters: supplier_id

4.10 Delivery Management

These endpoints manage deliveries with customer/driver tracking codes and verification. They require deliveries.read for read actions and deliveries.write for write actions.

4.10.1 create_delivery

Description: Create a new delivery with auto-generated tracking codes.

HTTP Method: POST
Parameters:

ParameterTypeRequiredDescription
sale_idintnoAssociated sale ID.
waybill_numberstringnoCustom waybill number (auto-generated if omitted).
customer_namestringyesRecipient name.
customer_phonestringyesRecipient phone.
customer_addressstringyesDelivery address.
itemsJSONyesArray of delivery items.
carrier_typestringnostandard or personal. Default: standard.
carrier_idintnoCarrier or rider ID.

4.10.2 update_delivery

Description: Update delivery fields (partial update — only sent fields are changed).
Parameters: delivery_id + any updatable fields (customer, carrier, etc.).

4.10.3 update_delivery_status

Description: Update the delivery status. Does NOT support delivered — use complete_delivery_with_code for that.

Allowed values: assigned, picked_up, in_transit, failed, returned

Parameters: delivery_id, status, note (optional), proof_image (optional, base64).

4.10.4 list_deliveries

Description: List deliveries with carrier names, paginated.
Parameters: limit (default 50), offset (default 0).

4.10.5 get_delivery

Description: Get a single delivery by ID (business owner view).
Parameters: delivery_id

4.10.6 get_delivery_by_code

Description: Get delivery details using a tracking code (public — no auth required). Used by customers and drivers to track deliveries.

Parameters:

ParameterTypeRequiredDescription
codestringyesCustomer or driver tracking code.
typestringnocustomer or driver. Default: customer.

Note: Customer view hides driver tracking code and proof images. Driver view hides the verification code.

4.10.7 complete_delivery_with_code

Description: Mark a delivery as delivered using the verification code. This is the only way to set status to delivered.

Parameters: delivery_id, code (6-digit verification code).

4.10.8 return_delivery

Description: Mark a delivery as returned (allows changing from any status except returned or failed).
Parameters: delivery_id

4.10.9 delete_delivery

Description: Delete a delivery record.
Parameters: delivery_id

4.11 Carriers & Riders

Manage third-party carriers and personal riders for deliveries. These require deliveries.write scope.

4.11.1 add_carrier

Description: Register a third-party carrier company.
Parameters: name (required), website, tracking_url_template, phone.

4.11.2 list_carriers

Description: List active carriers.

4.11.3 delete_carrier

Description: Soft-delete a carrier (sets is_active = 0).
Parameters: carrier_id

4.11.4 add_rider

Description: Add a personal rider.
Parameters: name (required), phone (required), email, vehicle_type, license_plate, id_number.

4.11.5 list_riders

Description: List active personal riders.

4.11.6 delete_rider

Description: Soft-delete a rider (sets is_active = 0).
Parameters: rider_id

4.12 Imports

Import clients and inventory items from CSV or JSON data. Client imports require clients.write scope. Inventory imports require inventory.write scope.

4.12.1 import_clients

Description: Import clients from a CSV file. Premium feature.

HTTP Method: POST (multipart/form-data)
Parameters: file — CSV file with headers: name, phone, balance, notes. Max 2MB.

4.12.2 import_inventory

Description: Import inventory items from a CSV file. Premium feature.
Parameters: file — CSV file with headers: name, price, stock, threshold, notes. Max 2MB.

4.12.3 import_data

Description: Import data via JSON (not file upload). Supports clients and inventory types.
Parameters: type (clients or inventory), data (JSON array of objects). Max payload 2MB.

4.12.4 download_client_template

Description: Download a CSV template for client imports.

4.12.5 download_product_template

Description: Download a CSV template for inventory imports.

4.13 Utilities

4.13.1 check_token

Description: Validate an OAuth access token and return the associated user ID.
Use cases: Token health checks, debugging OAuth flows.

Authentication: Bearer token in Authorization header.

Example response:

{
  "success": true,
  "user_id": 42,
  "expires": "2025-03-23 10:30:00"
}

4.13.2 logs

Description: Retrieve activity logs for the authenticated user. Supports filtering and pagination.

Parameters:

ParameterTypeRequiredDescription
filterstringnoOne of: SALE, INVENTORY, LEDGER, EXPENSE
pageintnoPage number (default 1).
limitintnoItems per page, max 100 (default 50).

4.13.3 set_onboarding_completed

Description: Mark the onboarding tutorial as completed for the current user.

5. Error Handling

5.1 HTTP Status Codes

CodeMeaning
200OK
400Bad request (invalid parameters)
401Unauthorized (missing or invalid token)
403Forbidden (insufficient scope or premium required)
404Resource not found
500Internal server error

5.2 API Error Response

{
  "success": false,
  "message": "Detailed error description"
}

5.3 Common Errors

Error MessageLikely Cause
Not authenticatedMissing or invalid token, or token not passed correctly.
User has no active businessThe user has a token but no active business membership.
Invalid or expired tokenToken is not in the database or has expired.
Premium feature requiredUser does not have an active premium subscription.
Insufficient stock for itemAttempted to sell more than available stock.

6. Security Best Practices

7. Code Examples

7.1 PHP (cURL)

// Step 1: Redirect user
$state = bin2hex(random_bytes(16));
$_SESSION['oauth_state'] = $state;
$authUrl = 'https://workstack.com.ng/oauth/authorize.php?' . http_build_query([
    'response_type' => 'code',
    'client_id' => 'rikizy_prod',
    'redirect_uri' => 'https://rikizy.com/oauth/callback',
    'scope' => 'profile.read sales.read inventory.read',
    'state' => $state
]);
header('Location: ' . $authUrl);
exit;

// Step 2: Callback handler
if ($_GET['state'] !== $_SESSION['oauth_state']) die('Invalid state');
$code = $_GET['code'];

$tokenUrl = 'https://workstack.com.ng/oauth/token.php';
$postData = [
    'grant_type' => 'authorization_code',
    'client_id' => 'rikizy_prod',
    'client_secret' => YOUR_CLIENT_SECRET,
    'code' => $code,
    'redirect_uri' => 'https://rikizy.com/oauth/callback'
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $tokenUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);

$tokenData = json_decode($response, true);
$accessToken = $tokenData['access_token'];

// Step 3: Call API
$apiUrl = 'https://workstack.com.ng/api_core.php?action=inventory';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . $accessToken]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$apiResponse = curl_exec($ch);
curl_close($ch);

$data = json_decode($apiResponse, true);
print_r($data);

7.2 Python (requests)

import requests
import secrets

# Redirect user
state = secrets.token_hex(16)
auth_url = "https://workstack.com.ng/oauth/authorize.php"
params = {
    "response_type": "code",
    "client_id": "rikizy_prod",
    "redirect_uri": "https://rikizy.com/oauth/callback",
    "scope": "profile.read sales.read inventory.read",
    "state": state
}
# ... redirect the user to auth_url ...

# Callback
if request.GET.get('state') != session_state: raise Exception("Invalid state")
code = request.GET.get('code')

# Exchange code
token_url = "https://workstack.com.ng/oauth/token.php"
data = {
    "grant_type": "authorization_code",
    "client_id": "rikizy_prod",
    "client_secret": YOUR_CLIENT_SECRET,
    "code": code,
    "redirect_uri": "https://rikizy.com/oauth/callback"
}
resp = requests.post(token_url, data=data)
token_data = resp.json()
access_token = token_data["access_token"]

# Call API
api_url = "https://workstack.com.ng/api_core.php"
headers = {"Authorization": f"Bearer {access_token}"}
params = {"action": "inventory"}
api_resp = requests.get(api_url, headers=headers, params=params)
print(api_resp.json())

7.3 Node.js (Express)

const axios = require('axios');
const crypto = require('crypto');

app.get('/connect', (req, res) => {
  const state = crypto.randomBytes(16).toString('hex');
  req.session.oauthState = state;
  const authUrl = `https://workstack.com.ng/oauth/authorize.php?${new URLSearchParams({
    response_type: 'code',
    client_id: 'rikizy_prod',
    redirect_uri: 'https://rikizy.com/oauth/callback',
    scope: 'profile.read sales.read inventory.read',
    state
  })}`;
  res.redirect(authUrl);
});

app.get('/oauth/callback', async (req, res) => {
  const { code, state } = req.query;
  if (state !== req.session.oauthState) return res.status(400).send('Invalid state');

  const tokenResponse = await axios.post('https://workstack.com.ng/oauth/token.php', 
    new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: 'rikizy_prod',
      client_secret: YOUR_CLIENT_SECRET,
      code,
      redirect_uri: 'https://rikizy.com/oauth/callback'
    }),
    { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
  );

  const { access_token } = tokenResponse.data;

  const apiResponse = await axios.get('https://workstack.com.ng/api_core.php', {
    params: { action: 'inventory' },
    headers: { Authorization: `Bearer ${access_token}` }
  });
  console.log(apiResponse.data);
});

8. Frequently Asked Questions

Q: Do my users need a WorkStack account?
A: Yes. They must have a WorkStack account (free or premium) and be logged in to authorize.

Q: Can free users access all APIs?
A: Free users can access all non‑analytics endpoints. Analytics require a premium subscription.

Q: How long is an access token valid?
A: 24 hours. Use the refresh token to obtain a new one.

Q: What scopes should I request?
A: Only those your app actually needs. For example, if you only need to display sales data, request sales.read.

Q: Can I test locally?
A: Yes, you need to register a redirect URI that points to your local environment (e.g., http://localhost:3000/callback). WorkStack must be able to reach that URL (ngrok can help).

Q: How do I handle users without a WorkStack account?
A: Your app can redirect them to WorkStack's sign‑up page (https://workstack.com.ng/portal) before starting the OAuth flow.

Q: What if the user's premium expires?
A: Analytics endpoints will return a 403. Your app can detect this and prompt the user to upgrade.

Q: Can I check if a user has premium without accessing their data?
A: Yes. Request the profile.read scope and call analytics_summary. A 403 indicates they are not premium.

9. Support

For questions, issues, or to register your application:

Documentation version 2.0 – last updated July 2026

← Back to Resources