Products API

28 PracBill API endpoints for products. Base URL https://billing.pracbill.com.au/api.

Get a single product category.

GET /{api_key}/category/get/{catid}

Responses

  • 200 — Success. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Get all product categories for the department, keyed by catid.

GET /{api_key}/category/getAll

Responses

  • 200 — Success. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Get a single product in the API key's department (a product in another department, or a deleted one, returns `no product found`). Returns the catalogue and stock-control fields writable through `/products/add` and `/products/update/{pid}` as well as the original product fields. (The URI is singular `product`; there is no `/products/get/{pid}` route.)

GET /{api_key}/product/get/{pid}

Responses

  • 200 — Product retrieved successfully. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Create a product in the API key's department (PRACBILL-1967). Only the fields in `ProductWriteRequest` are accepted; any other field is rejected with `unsupported field(s): ...`. `title` is required. `taxrate_id`, `catid` and `vid` must reference a live record in the key's department (0 leaves it unset). Accepts a raw JSON body or the legacy `json={...}` form.

POST /{api_key}/products/add

Request body

FieldTypeDescription
partnumberstringPart number (maximum 32 characters)
vpartnumberstringVendor part number
titlestringProduct title (required on create; cannot be emptied)
descriptionstringLong description
costobjectCost price (numeric)
ex_tax_amountobjectPrice ex-tax (numeric)
inc_tax_amountobjectPrice inc-tax (numeric). Not derived from ex_tax_amount - send both if both should change
taxrate_idintegerTax code id (`taxrates.id`) in the key's department; 0 clears it. Also sets the product's `taxrate` percentage from that code
catidintegerCategory id in the key's department; 0 clears it
vidintegerVendor id in the key's department; 0 clears it
manufacturerstringManufacturer
modelstringManufacturer part number / model
weightobjectWeight in kg
lengthintegerLength in mm
widthintegerWidth in mm
heightintegerHeight in mm
hazmatcodestringHAZMAT code
trackedobjectNon-inventory item flag
stock_controlstring (none | serial | non_serial)Stock control mode
minstockintegerMinimum quantity to keep in stock
reorder_amountobjectQuantity to reorder
stocktake_dailyobjectInclude in the daily stocktake report
webstore_itemobjectShow on the webstore
description_shortstringBrief (webstore) description, HTML
special_notesstringSpecial notes

Responses

  • 200 — Product created; returns its `pid`. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Products for a category (excludes deleted products, ordered by title). Page 1. Rows are 20 per page; the server remembers the autotable token per api key (temp file `api-{token}-products.txt`).

GET /{api_key}/products/category/{catid}

Responses

  • 200 — Request received successfully. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Products for a category (excludes deleted products, ordered by title). Page 1. Rows are 20 per page; the server remembers the autotable token per api key (temp file `api-{token}-products.txt`).

GET /{api_key}/products/category/{catid}/page

Responses

  • 200 — Request received successfully. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Products for a category (excludes deleted products, ordered by title). Rows are 20 per page; the server remembers the autotable token per api key (temp file `api-{token}-products.txt`).

GET /{api_key}/products/category/{catid}/page/{page_number}

Responses

  • 200 — Request received successfully. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

List products (page 1). Handler `ProductsGetMyPage`. Excludes deleted products, ordered by title. Rows are 20 per page; the server remembers the autotable token per api key (temp file `api-{token}-products.txt`).

GET /{api_key}/products/get

Responses

  • 200 — Request received successfully. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

List products (page 1). Alias of `/products/get`. Rows are 20 per page; the server remembers the autotable token per api key (temp file `api-{token}-products.txt`).

GET /{api_key}/products/get/page

Responses

  • 200 — Request received successfully. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

List products for the given page. Note: a second class `productsGetPage` in the same file declares the same URIs but is shadowed by `ProductsGetMyPage` (declared first, equal priority) and is never dispatched. Rows are 20 per page; the server remembers the autotable token per api key (temp file `api-{token}-products.txt`).

GET /{api_key}/products/get/page/{page_number}

Responses

  • 200 — Request received successfully. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Get all products (no pagination), keyed by pid. Includes deleted products. When the department has no products returns `success: false`, `description: no products found`.

GET /{api_key}/products/getAll

Responses

  • 200 — All products retrieved successfully. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Update a product in the API key's department (PRACBILL-1967). Only the supplied fields change, and only the fields in `ProductWriteRequest` are accepted; any other field is rejected and nothing is written. The same validation as create applies; `title` may not be emptied. A product in another department, or a deleted one, returns `no product found`. Accepts a raw JSON body or the legacy `json={...}` form.

POST /{api_key}/products/update/{pid}

Request body

FieldTypeDescription
partnumberstringPart number (maximum 32 characters)
vpartnumberstringVendor part number
titlestringProduct title (required on create; cannot be emptied)
descriptionstringLong description
costobjectCost price (numeric)
ex_tax_amountobjectPrice ex-tax (numeric)
inc_tax_amountobjectPrice inc-tax (numeric). Not derived from ex_tax_amount - send both if both should change
taxrate_idintegerTax code id (`taxrates.id`) in the key's department; 0 clears it. Also sets the product's `taxrate` percentage from that code
catidintegerCategory id in the key's department; 0 clears it
vidintegerVendor id in the key's department; 0 clears it
manufacturerstringManufacturer
modelstringManufacturer part number / model
weightobjectWeight in kg
lengthintegerLength in mm
widthintegerWidth in mm
heightintegerHeight in mm
hazmatcodestringHAZMAT code
trackedobjectNon-inventory item flag
stock_controlstring (none | serial | non_serial)Stock control mode
minstockintegerMinimum quantity to keep in stock
reorder_amountobjectQuantity to reorder
stocktake_dailyobjectInclude in the daily stocktake report
webstore_itemobjectShow on the webstore
description_shortstringBrief (webstore) description, HTML
special_notesstringSpecial notes

Responses

  • 200 — Product updated; returns the updated product detail. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Soft-delete (retire) a product in the API key's department (PRACBILL-1967). Refused, with the product left unchanged, while the product still has stock on hand: a non-zero quantity of live `inventory_items` in a stock location, or unallocated serialised units. Move or write off the stock first (e.g. `DELETE /{api_key}/stock/{pid}`). A product in another department, or one already deleted, returns `no product found`.

DELETE /{api_key}/products/{pid}

Responses

  • 200 — Product soft-deleted. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

List a product's serial numbers

GET /{api_key}/products/{pid}/serials

Every active, non-deleted serial for the product, allocated or not, ordered by serial number. Each record carries the allocation status the inventory product view shows.

Responses

  • 200 — The product's serials. Failures (invalid key, unknown/other-department product, serial not on this product, validation) are also returned with HTTP 200 and `success: false` + `description`.

Register a serial number

POST /{api_key}/products/{pid}/serials

Adds an unallocated serial to the product. `serialnumber` is required and must be unique across every product. Only `serialnumber`, `model` and `poid` are accepted; any other field is rejected.

Request body

FieldTypeDescription
serialnumberstringRequired on create; unique across all products
modelstring
poidintegerPurchase order id; blank or 0 for none

Responses

  • 200 — The created serial. Failures (invalid key, unknown/other-department product, serial not on this product, validation) are also returned with HTTP 200 and `success: false` + `description`.

Delete a serial number

DELETE /{api_key}/products/{pid}/serials/{snid}

Soft-deletes the serial. An allocated serial is rejected until it is unallocated.

Responses

  • 200 — The serial was deleted. Failures (invalid key, unknown/other-department product, serial not on this product, validation) are also returned with HTTP 200 and `success: false` + `description`.

Update a serial number

POST /{api_key}/products/{pid}/serials/{snid}

Changes the supplied fields; omitted fields keep their value. Only `serialnumber`, `model` and `poid` are accepted. Allocation is not editable here; use the allocate/unallocate endpoints.

Request body

FieldTypeDescription
serialnumberstringRequired on create; unique across all products
modelstring
poidintegerPurchase order id; blank or 0 for none

Responses

  • 200 — The updated serial. Failures (invalid key, unknown/other-department product, serial not on this product, validation) are also returned with HTTP 200 and `success: false` + `description`.

Allocate a serial number

POST /{api_key}/products/{pid}/serials/{snid}/allocate

Allocates the serial to an invoice (`iid` > 0) or an order (`iid` = minus the order id). The invoice or order must exist in the key's department; otherwise the validation reason is returned (e.g. `Invoice #123 does not exist.`). An already-allocated serial is re-allocated.

Request body

FieldTypeDescription
iid requiredintegerInvoice id, or minus the order id. 0 is rejected; use unallocate.

Responses

  • 200 — The allocated serial. Failures (invalid key, unknown/other-department product, serial not on this product, validation) are also returned with HTTP 200 and `success: false` + `description`.

Unallocate a serial number

POST /{api_key}/products/{pid}/serials/{snid}/unallocate

Returns the serial to stock (`iid` = 0). No request body.

Responses

  • 200 — The unallocated serial. Failures (invalid key, unknown/other-department product, serial not on this product, validation) are also returned with HTTP 200 and `success: false` + `description`.

Set the physical quantity of a non-serial product at a location (the new total, not a delta) through `moveInventoryItem()`. Serialised products are rejected - receive, transfer or remove units individually - as is a location holding negative (oversold) stock for the product.

POST /{api_key}/stock/adjust

Request body

FieldTypeDescription
pid requiredintegerNon-serial product ID
location_id requiredintegerStock location ID (not 0 / -1000)
quantity requiredintegerNew physical quantity at the location (0 to 1000000)

Responses

  • 200 — Stock adjusted (`stock adjusted`, or `stock unchanged` when the quantity already matches). Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

List the live stock locations in the API key's department, ordered by name.

GET /{api_key}/stock/locations

Responses

  • 200 — Locations retrieved. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Create a stock location. Setting `primary_sales_location` clears the flag on the department's other locations.

POST /{api_key}/stock/locations/add

Request body

FieldTypeDescription
namestringRequired on create; cannot be blank
descriptionstring
parent_locationintegerParent location ID in the same department, or 0 for none
primary_sales_locationbooleanBoolean-like (`true`/`false`, `1`/`0`)

Responses

  • 200 — Location created (`stock location created`). Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Partially update a stock location: only the fields sent change. The reserved locations 0 (Out) and -1000 (Overshipped) cannot be modified; the primary sales flag cannot be cleared directly (promote another location instead); a location cannot become its own ancestor.

POST /{api_key}/stock/locations/update/{id}

Request body

FieldTypeDescription
namestringRequired on create; cannot be blank
descriptionstring
parent_locationintegerParent location ID in the same department, or 0 for none
primary_sales_locationbooleanBoolean-like (`true`/`false`, `1`/`0`)

Responses

  • 200 — Location updated (`stock location updated`). Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Soft-delete a stock location. Refused while the location holds stock, has live child locations or is the primary sales location; the reserved locations 0 and -1000 cannot be deleted.

DELETE /{api_key}/stock/locations/{id}

Responses

  • 200 — Location deleted (`stock location deleted`). Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Get stock quantity on hand for a product, grouped by stock location.

GET /{api_key}/stock/quantity/{pid}

Responses

  • 200 — Stock quantities retrieved. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Receive stock into a location through `moveInventoryItem()` (records movement history and updates the on-hand total). Non-serial stock merges into the existing item at the location. Serialised products are received one unit per request with a unique `serial`; the duplicate check and the receipt are atomic (a concurrent receipt of the same serial waits, or is refused with `success: false` if it cannot get the serial's lock in time).

POST /{api_key}/stock/receive

Request body

FieldTypeDescription
pid requiredintegerProduct ID
location_id requiredintegerStock location ID (not 0 / -1000)
quantity requiredintegerPositive whole number (max 1000000); must be 1 for serialised products
serialstringRequired for serialised products, rejected otherwise. Must not exist on a live stock item; letters, digits, spaces and `. _ : / # + -` only.

Responses

  • 200 — Stock received (`stock received`). Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Move stock between two different locations in the department through `moveInventoryItem()`. Total on-hand stock is unchanged. Rejected without any write when the source holds too little stock; reserved locations 0/-1000 cannot be used.

POST /{api_key}/stock/transfer

Request body

FieldTypeDescription
pid requiredintegerProduct ID
from_location_id requiredintegerSource stock location ID (not 0 / -1000)
to_location_id requiredintegerDestination stock location ID (not 0 / -1000, not the source)
quantity requiredintegerPositive whole number
serialsarray of stringSerialised products only: exactly `quantity` serials at the source to move. Omit to move the oldest units.

Responses

  • 200 — Stock transferred (`stock transferred`). Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

Remove stock (move out) for a product from a location. Uses HTTP DELETE with an optional JSON body (raw JSON, or the legacy `data=` form). The product and location must belong to the API key's department.

DELETE /{api_key}/stock/{pid}

Request body

FieldTypeDescription
locationintegerStock location ID to remove stock from. Defaults to the primary sales location.
quantityintegerQuantity to remove. When omitted/0 a single unit is removed. Serialised products remove that many serials.

Responses

  • 200 — Stock removed. Failures (invalid key, validation, not found) are also returned with HTTP 200 and `success: false` + `description`.

← All API groups