Tracepos Developer HubTracepos Developer Hub
Home
Guide
POS & Integrations
API Reference
Webhooks
Home
Guide
POS & Integrations
API Reference
Webhooks
  • Core Catalog & Outlets

    • Products API
    • Categories & Brands API
    • Warehouses & Outlets API
  • Parties & CRM

    • Customers & Suppliers API
  • Operations & Stock

    • Sales & Transactions API
    • Purchases & Procurement API
    • Inventory & Price Adjustments API
    • Returns & Reversals API
  • Financial Ledger & Expenses

    • Payments & Settlements API
    • Expense Management API
    • Double-Entry Accounting Architecture
  • Real-Time Sync

    • Webhooks & Real-Time Sync

Sales & Transactions API

The Sales API is the core transactional engine of Tracepos. When an order is submitted through this endpoint, Tracepos executes an atomic database transaction that:

  1. Decrements Stock: Deducts inventory from the warehouse using FIFO batch allocation (product_batches).
  2. Generates Invoices: Issues a sequence-controlled company invoice number (SAL-XXXXX).
  3. Processes Payments: Immediately settles full or partial payments if the all_payments array is provided.
  4. Posts Journal Entries: Creates a balanced double-entry accounting record (Debiting Cash/Receivables, Crediting Sales Revenue and Sales Tax).
  5. Fires Webhooks: Dispatches order.created or order.paid real-time events to all registered webhook endpoints.

1. List Sales Orders

Retrieve a paginated list of sales orders created in the authorized warehouse.

GET/api/v1/public/sales

Query Parameters

ParameterTypeDefaultDescription
datesString-Date range filter in YYYY-MM-DD,YYYY-MM-DD format (e.g. 2026-09-01,2026-09-30)
limitInteger20Items per page (maximum: 100)
pageInteger1Pagination page number

Code Examples

:::: code-group ::: code-group-item cURL

curl -X GET "https://api.tracepos.com/api/v1/public/sales?dates=2026-09-01,2026-09-30&limit=20" \
  -H "X-Tracepos-Public-Key: tp_pub_live_7f8a9c2d1e" \
  -H "X-Tracepos-Secret-Key: tp_sec_live_9b3e1f7a4c" \
  -H "Accept: application/json"

::: ::: code-group-item Node.js (Axios)

const axios = require('axios');

async function listSales(startDate, endDate) {
  const response = await axios.get('https://api.tracepos.com/api/v1/public/sales', {
    params: {
      dates: `${startDate},${endDate}`,
      limit: 20
    },
    headers: {
      'X-Tracepos-Public-Key': process.env.TRACEPOS_PUBLIC_KEY,
      'X-Tracepos-Secret-Key': process.env.TRACEPOS_SECRET_KEY,
      'Accept': 'application/json'
    }
  });

  return response.data.data;
}

::: ::: code-group-item Python (Requests)

import os
import requests

headers = {
    "X-Tracepos-Public-Key": os.getenv("TRACEPOS_PUBLIC_KEY"),
    "X-Tracepos-Secret-Key": os.getenv("TRACEPOS_SECRET_KEY"),
    "Accept": "application/json"
}

response = requests.get(
    "https://api.tracepos.com/api/v1/public/sales",
    params={"dates": "2026-09-01,2026-09-30", "limit": 20},
    headers=headers
)
sales = response.json().get("data", {})

::: ::: code-group-item PHP (Guzzle)

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.tracepos.com/api/v1/public/']);

$response = $client->get('sales', [
    'query' => [
        'dates' => '2026-09-01,2026-09-30',
        'limit' => 20
    ],
    'headers' => [
        'X-Tracepos-Public-Key' => getenv('TRACEPOS_PUBLIC_KEY'),
        'X-Tracepos-Secret-Key' => getenv('TRACEPOS_SECRET_KEY'),
        'Accept'                => 'application/json'
    ]
]);

$sales = json_decode($response->getBody()->getContents(), true)['data'];

::: ::::

Response (200 OK)

{
  "status": "success",
  "data": {
    "current_page": 1,
    "data": [
      {
        "id": 182,
        "unique_id": "ord_9182ab3c4d5e",
        "invoice_number": "SAL-00451",
        "order_type": "sales",
        "order_date": "2026-09-30",
        "subtotal": "5500.00",
        "tax_amount": "412.50",
        "discount": "0.00",
        "shipping": "0.00",
        "total": "5912.50",
        "paid_amount": "5912.50",
        "due_amount": "0.00",
        "order_status": "delivered",
        "payment_status": "paid",
        "user": {
          "id": 105,
          "name": "Adeola Adeleke"
        },
        "staff_member": {
          "id": 2,
          "name": "POS Terminal 01 Key"
        }
      }
    ],
    "total": 450
  }
}

2. Get Single Sale Order

Retrieve complete line items, applied product taxes, and customer details for a single sale.

GET/api/v1/public/sales/{id}

Response (200 OK)

{
  "status": "success",
  "data": {
    "id": 182,
    "unique_id": "ord_9182ab3c4d5e",
    "invoice_number": "SAL-00451",
    "order_date": "2026-09-30",
    "subtotal": "5500.00",
    "total": "5912.50",
    "paid_amount": "5912.50",
    "due_amount": "0.00",
    "payment_status": "paid",
    "user": {
      "id": 105,
      "name": "Adeola Adeleke",
      "phone": "+2348031234567"
    },
    "items": [
      {
        "id": 412,
        "product_id": 45,
        "quantity": 2,
        "unit_price": "2750.00",
        "subtotal": "5500.00",
        "product": {
          "id": 45,
          "name": "Premium Basmati Rice 5kg",
          "item_code": "RICE-5KG-01"
        }
      }
    ]
  }
}

3. Create Sale (POS Checkout)

Record a completed or credit sale from a smart POS terminal, self-checkout kiosk, or eCommerce gateway.

POST/api/v1/public/sales

Request Parameters

ParameterTypeRequiredDescription
user_idInteger / StringYesCustomer ID (e.g. 105 or Walk-in customer ID 106)
order_dateDate (YYYY-MM-DD)YesTransaction date
product_itemsArrayYesLine items array (minimum 1 item)
product_items[].xidString / IntegerYesProduct hashed ID (xid) or numeric ID
product_items[].quantityNumericYesUnits purchased (e.g. 1, 2.5)
product_items[].unit_priceNumericYesSales price per unit
product_items[].selected_unit_idString / IntegerNoUnit of measure hash ID if multi-unit product
product_items[].tax_idString / IntegerNoApplied tax rule ID
product_items[].discount_rateNumericNoLine-item discount percentage
discountNumericNoOrder-level discount amount
shippingNumericNoShipping or delivery fee
invoice_numberStringNoCustom invoice number (auto-generated if omitted)
all_paymentsArrayNoImmediate payment breakdown (Cash, Card, Transfer)
all_payments[].amountNumericYes (if payment)Payment tender amount
all_payments[].payment_mode_idString / IntegerYes (if payment)Payment mode ID (e.g. 1 for Cash, 2 for POS Card)

Request Payload Example

{
  "user_id": 105,
  "order_date": "2026-09-30",
  "product_items": [
    {
      "xid": "J1rA2l6xN4",
      "quantity": 2,
      "unit_price": 2750.00
    },
    {
      "xid": "B9mP8k3vL0",
      "quantity": 1,
      "unit_price": 1200.00
    }
  ],
  "discount": 0.00,
  "shipping": 0.00,
  "all_payments": [
    {
      "amount": 6700.00,
      "payment_mode_id": 2
    }
  ]
}

Code Examples

:::: code-group ::: code-group-item cURL

curl -X POST "https://api.tracepos.com/api/v1/public/sales" \
  -H "X-Tracepos-Public-Key: tp_pub_live_7f8a9c2d1e" \
  -H "X-Tracepos-Secret-Key: tp_sec_live_9b3e1f7a4c" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "user_id": 105,
    "order_date": "2026-09-30",
    "product_items": [
      {
        "xid": "J1rA2l6xN4",
        "quantity": 2,
        "unit_price": 2750.00
      }
    ],
    "all_payments": [
      {
        "amount": 5500.00,
        "payment_mode_id": 2
      }
    ]
  }'

::: ::: code-group-item Node.js (Axios)

const axios = require('axios');

async function createSale(orderPayload) {
  const response = await axios.post(
    'https://api.tracepos.com/api/v1/public/sales',
    orderPayload,
    {
      headers: {
        'X-Tracepos-Public-Key': process.env.TRACEPOS_PUBLIC_KEY,
        'X-Tracepos-Secret-Key': process.env.TRACEPOS_SECRET_KEY,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      }
    }
  );

  return response.data;
}

::: ::: code-group-item Python (Requests)

import os
import requests

headers = {
    "X-Tracepos-Public-Key": os.getenv("TRACEPOS_PUBLIC_KEY"),
    "X-Tracepos-Secret-Key": os.getenv("TRACEPOS_SECRET_KEY"),
    "Content-Type": "application/json",
    "Accept": "application/json"
}

payload = {
    "user_id": 105,
    "order_date": "2026-09-30",
    "product_items": [
        {"xid": "J1rA2l6xN4", "quantity": 2, "unit_price": 2750.00}
    ],
    "all_payments": [
        {"amount": 5500.00, "payment_mode_id": 2}
    ]
}

response = requests.post("https://api.tracepos.com/api/v1/public/sales", json=payload, headers=headers)
result = response.json()

::: ::: code-group-item PHP (Guzzle)

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.tracepos.com/api/v1/public/']);

$response = $client->post('sales', [
    'headers' => [
        'X-Tracepos-Public-Key' => getenv('TRACEPOS_PUBLIC_KEY'),
        'X-Tracepos-Secret-Key' => getenv('TRACEPOS_SECRET_KEY'),
        'Content-Type'          => 'application/json',
        'Accept'                => 'application/json'
    ],
    'json' => [
        'user_id'       => 105,
        'order_date'    => '2026-09-30',
        'product_items' => [
            ['xid' => 'J1rA2l6xN4', 'quantity' => 2, 'unit_price' => 2750.00]
        ],
        'all_payments'  => [
            ['amount' => 5500.00, 'payment_mode_id' => 2]
        ]
    ]
]);

$result = json_decode($response->getBody()->getContents(), true);

::: ::::

Response (200 OK)

{
  "status": "success",
  "order_id": 182,
  "invoice_number": "SAL-00451",
  "total_amount": 5500.00
}

Split Tender Payments

Tracepos supports multi-tender transactions directly within all_payments. For example, a customer paying part Cash and part Card:

{
  "user_id": 105,
  "order_date": "2026-09-30",
  "product_items": [
    { "xid": "J1rA2l6xN4", "quantity": 4, "unit_price": 2500.00 }
  ],
  "all_payments": [
    { "amount": 4000.00, "payment_mode_id": 1 }, 
    { "amount": 6000.00, "payment_mode_id": 2 }
  ]
}

Tracepos automatically creates two Payment records and two OrderPayment ledger entries, marking the order as payment_status = "paid".

Next
Purchases & Procurement API