Home Integration API reference

Integration API reference

REST API for integrations and external apps

Purchases

Purchase requisitions

This anchor groups the purchase-requisition endpoints.

List purchase requisitions

PropertyValue
MethodGET
Path/api/v1/integration/purchase-requisitions
Permissionpurchase_requisition.view_all or purchase_requisition.view_own.
Feature requirementSettings -> Purchases -> Enable Purchase Requisition must be enabled for the business.
VisibilityRows are limited to permitted locations. When the token user lacks purchase_requisition.view_all but has purchase_requisition.view_own, only requisitions created by that user are returned.
CSV behaviorformat=csv streams all matching rows with a UTF-8 BOM and ignores page and per_page. Nested location and created_by objects are JSON-encoded in CSV cells.
Success response200 with paginated PurchaseRequisitionRow rows.
ParameterTypeRequiredDescription
per_page, pageintegerNoPagination controls. per_page accepts 1 to 100 and defaults to 20.
location_idintegerNoFilters by requisition location id.
statusstringNoordered, partial, or completed.
start_date, end_datestringNoOptional Y-m-d bounds on transaction_date. The filter is only applied when both values are present.
required_by_start, required_by_endstringNoOptional Y-m-d bounds on delivery_date. The filter is only applied when both values are present.
qstringNoMinimum 2 characters when sent. Matches ref_no and numeric requisition id.
formatstringNojson (default) or csv.

PurchaseRequisitionRow object

FieldTypeDescription
idintegerPurchase-requisition id.
ref_nostring | nullRequisition reference number.
statusstring | nullCurrent requisition workflow status.
transaction_date, delivery_datestring | nullISO-8601 requisition timestamps.
locationobject | nullBusiness-location summary with id and name.
created_byobject | nullUser summary with id and combined display name.
FieldTypeDescription
dataarray<PurchaseRequisitionRow>The current result page.
meta.current_page, meta.last_page, meta.per_page, meta.totalintegerLaravel paginator metadata.
StatusWhen it happensResponse shape
200The requisition list was returned successfully.{ "data": [...], "meta": { ... } } or CSV download.
403The token user lacks view permission or purchase requisitions are disabled.{ "message": string }
422The query string failed validation or q was shorter than 2 characters.Laravel validation JSON or { "message": string }.

Get purchase requisition

PropertyValue
MethodGET
Path/api/v1/integration/purchase-requisitions/{id}
PermissionSame permission and visibility rules as List purchase requisitions.
CSV behaviorformat=csv streams one UTF-8 BOM row whose data_json column matches the JSON data payload.
Success response200 with one PurchaseRequisitionDetail object.

PurchaseRequisitionLine object

FieldTypeDescription
id, product_id, variation_idintegerIdentifiers for the requisition line and linked catalog records.
quantity, secondary_unit_quantity, po_quantity_purchasednumber | nullRequested quantity, optional secondary-unit quantity, and quantity already purchased on linked purchase orders.
product_name, sku, variation_name, variation_label, sub_sku, unitstring | nullResolved product and unit display fields.

PurchaseRequisitionDetail object

FieldTypeDescription
id, ref_nointeger | stringRequisition identifiers.
statusstring | nullWorkflow status.
transaction_date, delivery_datestring | nullISO-8601 requisition timestamps.
locationobject | nullBusiness-location summary with id and name.
created_byobject | nullUser summary with id, name, and email.
linesarray<PurchaseRequisitionLine>Requisition lines ordered by line id.
FieldTypeDescription
dataPurchaseRequisitionDetailThe requested requisition payload.
StatusWhen it happensResponse shape
200The requisition was returned successfully.{ "data": { ... } } or CSV download.
403The token user lacks view permission or purchase requisitions are disabled.{ "message": string }
404The requisition id does not exist in the visible query.{ "message": "Not found" }
422The query string failed validation.Laravel validation JSON.

Create purchase requisition

PropertyValue
MethodPOST
Path/api/v1/integration/purchase-requisitions
Permissionpurchase_requisition.create.
Feature requirementPurchase requisitions must be enabled for the business.
Location rulelocation_id must belong to the business. The controller does not separately enforce permitted-location membership on create.
Transaction defaultsThe controller creates type = purchase_requisition, status = ordered, and uses the current timestamp for transaction_date.
Line ruleAt least one line must have a positive quantity or secondary_unit_quantity.
Success response201 with the created id and reference number.
FieldTypeRequiredDescription
location_idintegerYesBusiness location id.
delivery_datestring | nullNoOptional required-by date in Y-m-d format.
purchasesarray<PurchaseRequisitionCreateLine>YesAt least one requisition line.

PurchaseRequisitionCreateLine object

FieldTypeRequiredDescription
product_idintegerYesProduct id.
variation_idintegerYesVariation id.
quantitynumber | nullNoRequested quantity for the line.
secondary_unit_quantitynumber | nullNoOptional secondary-unit quantity.
FieldTypeDescription
messagestringLocalized create-success message.
data.idintegerThe created requisition id.
data.ref_nostring | nullThe saved requisition reference number.
StatusWhen it happensResponse shape
201The requisition was created successfully.{ "message": string, "data": { "id": integer, "ref_no": string | null } }
403The token user lacks create permission or purchase requisitions are disabled.{ "message": string }
422The request body failed validation or all lines had zero quantity.Laravel validation JSON or { "message": string }.
500The requisition create transaction failed unexpectedly.{ "message": "something_went_wrong" }

Update purchase requisition status

PropertyValue
MethodPUT or PATCH
Path/api/v1/integration/purchase-requisitions/{id}/status
Permissionpurchase_requisition.create or purchase_requisition.delete.
Feature requirementPurchase requisitions must be enabled for the business.
VisibilityThe target requisition is loaded through the same permitted-location and own/all visibility query used by the list endpoint.
Allowed statusesordered, partial, or completed.
Success response200 with the updated id and status.
FieldTypeRequiredDescription
statusstringYesNew requisition workflow status.
FieldTypeDescription
messagestringLocalized update-success message.
data.idintegerThe requisition id.
data.statusstringThe saved requisition status.
StatusWhen it happensResponse shape
200The requisition status was updated successfully.{ "message": string, "data": { "id": integer, "status": string } }
403The token user lacks the required permission or purchase requisitions are disabled.{ "message": string }
404The requisition id does not exist in the visible query.{ "message": "Not found" }
422The request body failed validation.Laravel validation JSON.

Delete purchase requisition

PropertyValue
MethodDELETE
Path/api/v1/integration/purchase-requisitions/{id}
Permissionpurchase_requisition.delete.
Feature requirementPurchase requisitions must be enabled for the business.
Delete scopeThe action looks up the row by business and type = purchase_requisition. Unlike list and show, it does not reapply the list visibility filters.
Delete behaviorClears purchase_requisition_line_id on linked purchase lines before deleting the requisition.
Success response200 with the deleted id.
FieldTypeDescription
messagestringLocalized delete-success message.
data.idintegerThe deleted requisition id.
StatusWhen it happensResponse shape
200The requisition was deleted successfully.{ "message": string, "data": { "id": integer } }
403The token user lacks delete permission or purchase requisitions are disabled.{ "message": string }
404No purchase requisition with that id exists for the business.{ "message": "Not found" }
500The requisition delete failed unexpectedly.{ "message": string }

Purchase orders

This anchor groups the purchase-order endpoints.

List purchase orders

PropertyValue
MethodGET
Path/api/v1/integration/purchase-orders
Permissionpurchase_order.view_all or purchase_order.view_own.
Feature requirementSettings -> Purchases -> Enable purchase order must be enabled for the business.
VisibilityRows are limited to permitted locations. When the token user lacks purchase_order.view_all but has purchase_order.view_own, only orders created by that user are returned.
CSV behaviorformat=csv streams all matching rows with a UTF-8 BOM and ignores page and per_page.
Success response200 with paginated PurchaseOrderRow rows.
ParameterTypeRequiredDescription
per_page, pageintegerNoPagination controls. per_page accepts 1 to 100 and defaults to 20.
location_idintegerNoFilters by purchase-order location id.
contact_idintegerNoFilters by contact id.
statusstringNoordered, partial, or completed.
shipping_statusstringNoExact match against the stored shipping status.
start_date, end_datestringNoOptional Y-m-d bounds on transaction_date. The filter is only applied when both are present.
qstringNoMinimum 2 characters when sent. Matches reference number, document, numeric id, and linked contact fields.
formatstringNojson (default) or csv.

PurchaseOrderRow object

FieldTypeDescription
idintegerPurchase-order id.
ref_no, documentstring | nullStored reference and document fields.
transaction_datestring | nullISO-8601 transaction timestamp.
status, shipping_statusstring | nullOrder workflow and shipping status.
final_total, total_before_tax, tax_amount, discount_amountnumber | nullOrder totals from the transaction header.
po_qty_remainingnumber | nullRemaining quantity not yet purchased against the order.
contactobject | nullContact summary with id, name, mobile, contact_id, and supplier_business_name.
locationobject | nullBusiness-location summary with id and name.
FieldTypeDescription
dataarray<PurchaseOrderRow>The current result page.
meta.current_page, meta.last_page, meta.per_page, meta.totalintegerLaravel paginator metadata.
StatusWhen it happensResponse shape
200The purchase-order list was returned successfully.{ "data": [...], "meta": { ... } } or CSV download.
403The token user lacks view permission or purchase orders are disabled.{ "message": string }
422The query string failed validation or q was shorter than 2 characters.Laravel validation JSON or { "message": string }.

Get purchase order

PropertyValue
MethodGET
Path/api/v1/integration/purchase-orders/{id}
PermissionSame permission and visibility rules as List purchase orders.
CSV behaviorformat=csv streams one UTF-8 BOM row whose data_json column matches the JSON data payload.
Success response200 with one PurchaseOrderDetail object.

PurchaseOrderLine object

FieldTypeDescription
id, product_id, variation_idintegerIdentifiers for the purchase-order line and linked catalog records.
quantity, po_quantity_purchased, quantity_remainingnumberOrdered quantity, already purchased quantity, and remaining quantity.
pp_without_discount, discount_percent, purchase_price, purchase_price_inc_tax, item_taxnumber | nullLine pricing and tax fields.
line_taxobject | nullOptional tax summary with id, name, and amount.
purchase_requisition_line_idinteger | nullOptional linked purchase-requisition line id.
product_name, sub_skustring | nullResolved product display fields.

PurchaseOrderDetail object

FieldTypeDescription
id, ref_nointeger | stringPurchase-order identifiers.
documentstring | nullStored document filename or path.
transaction_date, delivery_datestring | nullISO-8601 order timestamps.
status, shipping_statusstring | nullOrder workflow and shipping status.
exchange_rate, final_total, total_before_tax, tax_amount, discount_amount, shipping_chargesnumber | nullOrder totals and exchange-rate values.
discount_type, shipping_details, additional_notes, pay_term_type, shipping_address, delivered_tostring | nullSaved order metadata fields.
pay_term_numbernumber | nullPayment-term number.
purchase_requisition_idsarray<integer>Linked requisition ids.
order_taxobject | nullOrder-level tax summary with id, name, amount, and is_tax_group.
contactobject | nullContact summary with id, name, mobile, email, contact_id, and supplier_business_name.
locationobject | nullBusiness-location summary with id and name.
linesarray<PurchaseOrderLine>Order lines sorted by line id.
FieldTypeDescription
dataPurchaseOrderDetailThe requested purchase-order payload.
StatusWhen it happensResponse shape
200The purchase order was returned successfully.{ "data": { ... } } or CSV download.
403The token user lacks view permission or purchase orders are disabled.{ "message": string }
404The purchase-order id does not exist in the visible query.{ "message": "Not found" }
422The query string failed validation.Laravel validation JSON.

Create purchase order

PropertyValue
MethodPOST
Path/api/v1/integration/purchase-orders
Permissionpurchase_order.create.
Feature and subscriptionPurchase orders must be enabled and the business must have an active subscription.
Location rulelocation_id must belong to the business. The controller does not separately enforce permitted-location membership on create.
Multipart behaviorThe endpoint accepts optional document upload and also passes shipping_documents through media upload when sent.
Success response201 with the created id and reference number.
FieldTypeRequiredDescription
contact_idintegerYesBusiness contact id used on the order.
location_idintegerYesBusiness location id.
transaction_datestringYesOrder date accepted by Laravel date validation.
total_before_tax, final_totalnumberYesOrder totals before and after tax.
exchange_ratenumber | nullNoOptional exchange rate. Defaults to 1.
ref_nostring | nullNoOptional order reference number.
discount_typestring | nullNofixed or percentage.
discount_amount, tax_amount, shipping_chargesnumber | nullNoOptional order-level financial adjustments.
tax_idinteger | nullNoOptional tax id.
shipping_details, additional_notes, shipping_address, shipping_status, delivered_tostring | nullNoOptional shipping and notes fields.
delivery_datestring | nullNoOptional delivery date.
pay_term_numbernumber | nullNoOptional payment-term number.
pay_term_typestring | nullNodays or months.
purchase_requisition_idsarray<integer> | nullNoOptional linked purchase-requisition ids whose status should be refreshed.
purchasesarray<PurchaseOrderLineInput>YesAt least one purchase-order line.

PurchaseOrderLineInput object

FieldTypeRequiredDescription
product_id, variation_idintegerYesProduct and variation ids.
quantity, pp_without_discount, purchase_price, purchase_price_inc_tax, item_taxnumberYesRequired quantity and pricing fields.
discount_percentnumber | nullNoOptional line discount percentage.
purchase_line_tax_id, sub_unit_id, product_unit_id, purchase_requisition_line_idinteger | nullNoOptional tax, unit, and requisition-link ids.
secondary_unit_quantitynumber | nullNoOptional secondary-unit quantity.
lot_numberstring | nullNoOptional lot number.
mfg_date, exp_datestring | nullNoOptional manufacturing and expiry dates.
FieldTypeDescription
messagestringLocalized create-success message.
data.idintegerThe created purchase-order id.
data.ref_nostring | nullThe saved reference number.
StatusWhen it happensResponse shape
201The purchase order was created successfully.{ "message": string, "data": { "id": integer, "ref_no": string | null } }
402The business subscription is inactive.{ "message": string }
403The token user lacks create permission or purchase orders are disabled.{ "message": string }
422The request body failed validation.Laravel validation JSON.
500The purchase-order create transaction failed unexpectedly.{ "message": "something_went_wrong" }

Update purchase order

PropertyValue
MethodPUT or PATCH
Path/api/v1/integration/purchase-orders/{id}
Permissionpurchase_order.update.
Feature and subscriptionPurchase orders must be enabled and the business must have an active subscription.
Lookup scopeThe action loads the order by business and type = purchase_order. It does not reapply the list visibility rules on update.
Request bodySame schema as Create purchase order, plus optional purchases.*.purchase_line_id for existing rows. location_id is not accepted on update.
Success response200 with the updated id and reference number.
FieldTypeRequiredDescription
purchases.*.purchase_line_idintegerNoExisting purchase-order line id to update in place.
FieldTypeDescription
messagestringLocalized update-success message.
data.idintegerThe updated purchase-order id.
data.ref_nostring | nullThe saved reference number.
StatusWhen it happensResponse shape
200The purchase order was updated successfully.{ "message": string, "data": { "id": integer, "ref_no": string | null } }
402The business subscription is inactive.{ "message": string }
403The token user lacks update permission or purchase orders are disabled.{ "message": string }
404No purchase order with that id exists for the business.{ "message": "Not found" }
422The request body failed validation.Laravel validation JSON.
500The purchase-order update failed unexpectedly.{ "message": string }

Delete purchase order

PropertyValue
MethodDELETE
Path/api/v1/integration/purchase-orders/{id}
Permissionpurchase_order.delete.
Feature requirementPurchase orders must be enabled for the business.
Lookup scopeThe action loads the order by business and type = purchase_order. It does not reapply the list visibility rules on delete.
Delete behaviorClears purchase_order_line_id on linked purchase lines, writes an activity log entry, then deletes the order.
Success response200 with the deleted id.
FieldTypeDescription
messagestringLocalized delete-success message.
data.idintegerThe deleted purchase-order id.
StatusWhen it happensResponse shape
200The purchase order was deleted successfully.{ "message": string, "data": { "id": integer } }
403The token user lacks delete permission or purchase orders are disabled.{ "message": string }
404No purchase order with that id exists for the business.{ "message": "Not found" }
500The purchase-order delete failed unexpectedly.{ "message": string }

Update purchase order status

PropertyValue
MethodPUT or PATCH
Path/api/v1/integration/purchase-orders/{id}/status
PermissionBusiness admin only.
Feature requirementPurchase orders must be enabled for the business.
Lookup scopeThe action loads the order by business and type = purchase_order. It does not reapply the list visibility rules on status updates.
Allowed statusesordered, partial, or completed.
Success response200 with the updated id and status.
FieldTypeRequiredDescription
statusstringYesNew order status: ordered, partial, or completed.
FieldTypeDescription
messagestringLocalized success message.
data.idintegerThe purchase-order id.
data.statusstringThe saved order status.
StatusWhen it happensResponse shape
200The purchase-order status was updated successfully.{ "message": string, "data": { "id": integer, "status": string } }
403The token user is not a business admin or purchase orders are disabled.{ "message": string }
404No purchase order with that id exists for the business.{ "message": "Not found" }
422The request body failed validation.Laravel validation JSON.

List purchases

Lists purchase transactions that are visible to the token user.

Endpoint summary

PropertyValue
MethodGET
Path/api/v1/integration/purchases
PermissionAt least one of purchase.view, purchase.create, or view_own_purchase.
VisibilityRows are limited to permitted locations. When the token user lacks purchase.view but has view_own_purchase, only purchases created by that user are returned.
Overdue filterpayment_status=overdue narrows to due/partial purchases whose pay-term deadline is before the current date.
CSV behaviorformat=csv streams all matching rows with a UTF-8 BOM and ignores page and per_page. Nested contact and location objects are JSON-encoded in CSV cells.
Success response200 with paginated PurchaseRow rows.

Query parameters

ParameterTypeRequiredDescription
per_page, pageintegerNoPagination controls. per_page accepts 1 to 100 and defaults to 20.
location_id, contact_idintegerNoOptional filters for location and supplier/contact id.
start_date, end_datestringNoOptional Y-m-d bounds on transaction_date. The filter is only applied when both values are present.
payment_statusstringNopaid, due, partial, or overdue.
statusstringNoreceived, pending, or ordered.
qstringNoMinimum 2 characters when sent. Matches reference number, invoice number, document, numeric id, and linked supplier fields.
formatstringNojson (default) or csv.

PurchaseRow object

FieldTypeDescription
idintegerPurchase transaction id.
ref_no, documentstring | nullStored reference and document fields.
transaction_datestring | nullISO-8601 purchase timestamp.
status, payment_statusstring | nullPurchase workflow and payment state.
final_total, total_before_tax, tax_amount, discount_amount, total_paidnumber | nullPurchase totals from the transaction header and payment subquery.
contactobject | nullSupplier summary with id, name, mobile, contact_id, and supplier_business_name.
locationobject | nullBusiness-location summary with id and name.

Top-level JSON response

FieldTypeDescription
dataarray<PurchaseRow>The current result page.
meta.current_page, meta.last_page, meta.per_page, meta.totalintegerLaravel paginator metadata.

Status codes

StatusWhen it happensResponse shape
200The purchase list was returned successfully.{ "data": [...], "meta": { ... } } or CSV download.
403The token user lacks purchase-list access.{ "message": string }
422The query string failed validation or q was shorter than 2 characters.Laravel validation JSON or { "message": string }.

Check purchase reference (supplier + ref_no)

Checks whether a supplier reference number is available for this business.

Endpoint summary

PropertyValue
MethodGET
Path/api/v1/integration/purchases/check-ref-number
Permissionpurchase.create or purchase.update.
BehaviorIf ref_no is blank or contact_id is missing, the endpoint returns available = true without running the duplicate query.
Success response200 with an availability payload.

Query parameters

ParameterTypeRequiredDescription
ref_nostringNoSupplier reference number to check.
contact_idintegerNoSupplier/contact id for the uniqueness check.
exclude_transaction_idintegerNoOptional purchase id to ignore when editing an existing row.

Top-level JSON response

FieldTypeDescription
data.availablebooleanWhether the reference is available for the given supplier/contact.
data.ref_nostring | nullEchoes the trimmed reference value.
data.contact_idinteger | nullEchoes the contact id used for the lookup.

Status codes

StatusWhen it happensResponse shape
200The availability check completed successfully.{ "data": { "available": boolean, "ref_no": string | null, "contact_id": integer | null } }
403The token user lacks create/update purchase permission.{ "message": string }
422The query string failed validation.Laravel validation JSON.

Get purchase

Returns one visible purchase with line and payment details.

Endpoint summary

PropertyValue
MethodGET
Path/api/v1/integration/purchases/{id}
PermissionSame permission and visibility rules as List purchases.
CSV behaviorformat=csv streams one UTF-8 BOM row whose data_json column matches the JSON data payload.
Success response200 with one PurchaseDetail object.

PurchaseLine object

FieldTypeDescription
id, product_id, variation_idintegerIdentifiers for the purchase line and linked catalog records.
product_label, sub_skustring | nullResolved product display label and variation sub-SKU.
quantitynumberPurchased quantity.
purchase_price, purchase_price_inc_tax, pp_without_discount, discount_percent, item_taxnumber | nullLine pricing and tax fields.
line_taxobject | nullOptional tax summary with id, name, and amount.

PurchasePaymentSummary object

FieldTypeDescription
idintegerPayment-line id.
amountnumber | nullStored payment amount.
methodstring | nullPayment method key.
paid_onstring | nullISO-8601 payment timestamp.
payment_ref_nostring | nullGenerated payment reference number.
notestring | nullOptional payment note.
is_returnbooleanWhether the payment is a return/negative payment row.

PurchaseDetail object

FieldTypeDescription
id, ref_nointeger | stringPurchase identifiers.
documentstring | nullStored document filename or path.
transaction_datestring | nullISO-8601 purchase timestamp.
status, payment_statusstring | nullPurchase workflow and payment state.
final_total, total_before_tax, tax_amount, discount_amount, shipping_charges, total_paidnumber | nullPurchase totals from the header and payment lines.
additional_notes, staff_notestring | nullSaved notes.
purchase_order_idsarray<integer>Linked purchase-order ids.
contactobject | nullSupplier summary with id, name, mobile, email, contact_id, and supplier_business_name.
locationobject | nullBusiness-location summary with id and name.
order_taxobject | nullOrder-level tax summary with id, name, amount, and is_tax_group.
linesarray<PurchaseLine>Purchase lines sorted by line id.
paymentsarray<PurchasePaymentSummary>Payment lines linked to the purchase.

Top-level JSON response

FieldTypeDescription
dataPurchaseDetailThe requested purchase payload.

Status codes

StatusWhen it happensResponse shape
200The purchase was returned successfully.{ "data": { ... } } or CSV download.
403The token user lacks purchase-list access.{ "message": string }
404The purchase id does not exist in the visible query.{ "message": "Not found" }
422The query string failed validation.Laravel validation JSON.

Create purchase

Creates a new purchase and can optionally post initial payment lines in the same request.

Endpoint summary

PropertyValue
MethodPOST
Path/api/v1/integration/purchases
Permissionpurchase.create.
SubscriptionThe business must have an active subscription.
Location rulelocation_id must belong to the business. The controller does not separately enforce permitted-location membership on create.
Create behaviorThe controller creates type = purchase, initializes payment_status = due, updates the business purchase exchange rate, creates purchase lines, optionally creates payment lines, refreshes linked purchase-order status, and adjusts stock over-selling.
Upload ruleThe request may include multipart document; its size limit follows the configured document size limit.
Success response201 with the created id and reference number.

Request body

FieldTypeRequiredDescription
contact_idintegerYesBusiness contact id used on the purchase.
location_idintegerYesBusiness location id.
statusstringYesreceived, pending, or ordered.
transaction_datestringYesPurchase date accepted by Laravel date validation.
total_before_tax, final_totalnumberYesPurchase totals before and after tax.
exchange_ratenumber | nullNoOptional exchange rate. Defaults to 1.
ref_nostring | nullNoOptional supplier reference number.
discount_typestring | nullNofixed or percentage.
discount_amount, tax_amount, shipping_chargesnumber | nullNoOptional financial adjustments.
tax_idinteger | nullNoOptional business tax-rate id.
shipping_details, additional_notesstring | nullNoOptional notes and shipping text.
pay_term_numbernumber | nullNoOptional pay-term number.
pay_term_typestring | nullNodays or months.
purchase_order_idsarray<integer> | nullNoOptional linked purchase-order ids.
custom_field_1 ... custom_field_4string | nullNoOptional custom purchase fields.
shipping_custom_field_1 ... shipping_custom_field_5string | nullNoOptional shipping custom fields.
additional_expense_key_1 ... additional_expense_key_4string | nullNoOptional additional-expense labels.
additional_expense_value_1 ... additional_expense_value_4number | nullNoOptional additional-expense amounts.
paymentarray<PurchaseCreatePaymentInput> | nullNoOptional initial payment rows created with the purchase.
documentfile | nullNoOptional uploaded document.
purchasesarray<PurchaseLineInput>YesAt least one purchase line.

PurchaseLineInput object

FieldTypeRequiredDescription
product_id, variation_idintegerYesProduct and variation ids.
quantity, pp_without_discount, purchase_price, purchase_price_inc_tax, item_taxnumberYesRequired quantity and pricing fields.
discount_percentnumber | nullNoOptional line discount percentage.
purchase_line_tax_id, sub_unit_id, product_unit_id, purchase_order_line_idinteger | nullNoOptional line tax, unit, and purchase-order-link ids.
secondary_unit_quantitynumber | nullNoOptional secondary-unit quantity.
lot_numberstring | nullNoOptional lot number.
mfg_date, exp_datestring | nullNoOptional manufacturing and expiry dates.

PurchaseCreatePaymentInput object

FieldTypeRequiredDescription
amountnumberYesPayment amount.
methodstringYesPayment method key.
paid_onstring | nullNoOptional payment date.
account_idinteger | nullNoOptional account id.
notestring | nullNoOptional payment note.
is_returnboolean | nullNoOptional return-payment flag.

Top-level JSON response

FieldTypeDescription
messagestringLocalized create-success message.
data.idintegerThe created purchase id.
data.ref_nostring | nullThe saved supplier reference number.

Status codes

StatusWhen it happensResponse shape
201The purchase was created successfully.{ "message": string, "data": { "id": integer, "ref_no": string | null } }
402The business subscription is inactive.{ "message": string }
403The token user lacks create permission.{ "message": string }
422The request body failed validation.Laravel validation JSON.
500The purchase create transaction failed unexpectedly.{ "message": "something_went_wrong" }

Update purchase

Updates an existing visible purchase and rewrites its purchase-line set.

Endpoint summary

PropertyValue
MethodPUT or PATCH
Path/api/v1/integration/purchases/{id}
Permissionpurchase.update.
SubscriptionThe business must have an active subscription.
VisibilityThe target purchase is loaded through the same permitted-location and own/all visibility query used by list and show.
Edit blockersThe purchase cannot be updated when a linked return exists or when it falls outside the business edit window defined by transaction_edit_days.
Request bodyReuses the create schema except location_id and the optional initial payment array are not accepted on update. Existing lines may send purchases.*.purchase_line_id.
Success response200 with the updated id and reference number.

Additional update-only field

FieldTypeRequiredDescription
purchases.*.purchase_line_idintegerNoExisting purchase-line id to update in place.

Top-level JSON response

FieldTypeDescription
messagestringLocalized update-success message.
data.idintegerThe updated purchase id.
data.ref_nostring | nullThe saved supplier reference number.

Status codes

StatusWhen it happensResponse shape
200The purchase was updated successfully.{ "message": string, "data": { "id": integer, "ref_no": string | null } }
402The business subscription is inactive.{ "message": string }
403The token user lacks update permission.{ "message": string }
404The purchase id does not exist in the visible query.{ "message": "Not found" }
422A linked return exists, the purchase is outside the allowed edit window, or the request body failed validation.Laravel validation JSON or { "message": string }.
500The purchase update transaction failed unexpectedly.{ "message": string }

Record purchase payment

Records a payment against a visible purchase transaction.

Endpoint summary

PropertyValue
MethodPOST
Path/api/v1/integration/purchases/{id}/payments
Permissionpurchase.payments plus the same purchase visibility required by List purchases.
Demo and subscriptionReturns 403 in demo environments and 402 when the business subscription is inactive.
Payment-method rulemethod must be one of the payment methods currently allowed for the purchase location.
Advance ruleWhen method = advance, the payment amount cannot exceed the linked contact balance.
Related endpointsCreated payment rows can later be managed through the generic /api/v1/integration/transaction-payments/{id} endpoints.
Success response201 with the created payment id and refreshed purchase payment status.

Request body

FieldTypeRequiredDescription
amountnumberYesPayment amount. Minimum 0.01.
methodstringYesPayment method key.
paid_onstring | nullNoOptional payment date. Defaults to the current timestamp when omitted.
notestring | nullNoOptional payment note up to 1000 characters.
account_idinteger | nullNoOptional account id. Ignored when method = advance.
card_number, card_holder_name, card_transaction_number, card_type, card_month, card_year, card_securitystring | nullNoOptional card-payment metadata.
cheque_numberstring | nullNoOptional cheque number.
bank_account_numberstring | nullNoOptional bank-account reference.
transaction_no_1, transaction_no_2, transaction_no_3string | nullNoOptional transaction references used by custom_pay_1, custom_pay_2, and custom_pay_3.

Top-level JSON response

FieldTypeDescription
messagestringLocalized payment-added message.
data.transaction_id, data.payment_idintegerPurchase id and created payment id.
data.payment_ref_nostring | nullGenerated payment reference number.
data.payment_statusstring | nullRefreshed purchase payment status after the insert.
data.amountnumberStored payment amount.
data.methodstring | nullStored payment method.
data.paid_onstring | nullISO-8601 payment timestamp.

Status codes

StatusWhen it happensResponse shape
201The payment was recorded successfully.{ "message": string, "data": { ... } }
402The business subscription is inactive.{ "message": string }
403Demo mode is active or the token user lacks purchase.payments.{ "message": string }
404The purchase id does not exist in the visible query.{ "message": "Not found" }
422The purchase is already fully paid, the request body failed validation, the payment method is invalid for the location, or an advance payment exceeds the contact balance.Laravel validation JSON or { "message": string }.
500The purchase payment transaction failed unexpectedly.{ "message": "something_went_wrong" }

Delete purchase

Deletes a visible purchase and reverses stock-side effects when required.

Endpoint summary

PropertyValue
MethodDELETE
Path/api/v1/integration/purchases/{id}
Permissionpurchase.delete.
VisibilityThe target purchase is loaded through the same permitted-location and own/all visibility query used by list and show.
Delete blockersThe purchase cannot be deleted when a linked return exists. If lot tracking is enabled, deletion is also blocked when the lot has already been used in sales.
Stock behaviorFor received purchases the controller reverses stock quantities, deletes purchase lines, updates purchase-sell mappings, removes account transactions, and dispatches the purchase modified event.
Success response200 with the deleted id.

Top-level JSON response

FieldTypeDescription
messagestringLocalized delete-success message.
data.idintegerThe deleted purchase id.

Status codes

StatusWhen it happensResponse shape
200The purchase was deleted successfully.{ "message": string, "data": { "id": integer } }
403The token user lacks delete permission.{ "message": string }
404The purchase id does not exist in the visible query.{ "message": "Not found" }
422A linked return exists or a lot-number constraint blocks deletion.{ "message": string }
500The purchase delete transaction failed unexpectedly.{ "message": string }

List purchase returns

Lists purchase-return transactions for the current business.

Endpoint summary

PropertyValue
MethodGET
Path/api/v1/integration/purchase-returns
Permissionpurchase.view or purchase.create.
VisibilityRows are limited to permitted locations. Unlike purchase list visibility, this endpoint does not apply an own-purchase filter.
Search behaviorThe search also matches the parent purchase reference number when the return is linked to a purchase.
CSV behaviorformat=csv streams all matching rows with a UTF-8 BOM and ignores page and per_page.
Success response200 with paginated PurchaseReturnRow rows.

Query parameters

ParameterTypeRequiredDescription
per_page, pageintegerNoPagination controls. per_page accepts 1 to 100 and defaults to 20.
location_id, contact_idintegerNoOptional location and supplier/contact filters.
start_date, end_datestringNoOptional Y-m-d bounds on transaction_date. The filter is only applied when both values are present.
qstringNoMinimum 2 characters when sent. Matches ref, document, numeric id, supplier fields, and linked parent purchase ref.
formatstringNojson (default) or csv.

PurchaseReturnRow object

FieldTypeDescription
idintegerPurchase-return transaction id.
ref_no, documentstring | nullStored reference and document fields.
transaction_datestring | nullISO-8601 return timestamp.
status, payment_statusstring | nullReturn workflow and payment state.
final_total, total_before_tax, tax_amount, total_paidnumber | nullReturn totals from the header and payment subquery.
return_parent_idinteger | nullLinked parent purchase id when this return was created against a purchase.
parent_purchaseobject | nullParent purchase summary with id and ref_no.
contactobject | nullSupplier summary with id, name, mobile, contact_id, and supplier_business_name.
locationobject | nullBusiness-location summary with id and name.

Top-level JSON response

FieldTypeDescription
dataarray<PurchaseReturnRow>The current result page.
meta.current_page, meta.last_page, meta.per_page, meta.totalintegerLaravel paginator metadata.

Status codes

StatusWhen it happensResponse shape
200The purchase-return list was returned successfully.{ "data": [...], "meta": { ... } } or CSV download.
403The token user lacks purchase-return list access.{ "message": string }
422The query string failed validation or q was shorter than 2 characters.Laravel validation JSON or { "message": string }.

Get purchase return

Returns one purchase return by id, including parent-linked or standalone return lines.

Endpoint summary

PropertyValue
MethodGET
Path/api/v1/integration/purchase-returns/{id}
PermissionSame permission and visibility rules as List purchase returns.
Line sourceLinked returns read lines from the parent purchase where quantity_returned > 0. Standalone combined returns read lines from the return itself.
CSV behaviorformat=csv streams one UTF-8 BOM row whose data_json column matches the JSON data payload.
Success response200 with one PurchaseReturnDetail object.

PurchaseReturnLine object

FieldTypeDescription
purchase_line_id, product_id, variation_idintegerIdentifiers for the source purchase line and linked catalog records.
product_label, sub_skustring | nullResolved product display label and variation sub-SKU.
quantity_returnednumberReturned quantity for the line.
purchase_price_inc_tax, line_totalnumber | nullUnit price including tax and computed line total.
sourcestringparent_purchase for linked returns or purchase_return for standalone combined returns.

PurchaseReturnDetail object

FieldTypeDescription
id, ref_nointeger | stringPurchase-return identifiers.
documentstring | nullStored document filename or path.
transaction_datestring | nullISO-8601 return timestamp.
status, payment_statusstring | nullReturn workflow and payment state.
final_total, total_before_tax, tax_amount, total_paidnumber | nullReturn totals from the header and payment lines.
return_parent_idinteger | nullLinked parent purchase id when present.
parent_purchaseobject | nullParent purchase summary with id and ref_no.
contactobject | nullSupplier summary with id, name, mobile, email, contact_id, and supplier_business_name.
locationobject | nullBusiness-location summary with id and name.
order_taxobject | nullReturn tax summary with id, name, amount, and is_tax_group.
linesarray<PurchaseReturnLine>Returned lines currently included in the payload.
paymentsarray<PurchasePaymentSummary>Payment lines linked to the return.

Top-level JSON response

FieldTypeDescription
dataPurchaseReturnDetailThe requested purchase-return payload.

Status codes

StatusWhen it happensResponse shape
200The purchase return was returned successfully.{ "data": { ... } } or CSV download.
403The token user lacks purchase-return list access.{ "message": string }
404The purchase-return id does not exist in the visible query.{ "message": "Not found" }
422The query string failed validation.Laravel validation JSON.

Create purchase return

This anchor documents both return-creation flows: returns against an existing purchase and standalone combined returns.

Create return from a purchase

PropertyValue
MethodPOST
Path/api/v1/integration/purchase-returns
Permissionpurchase.update.
Demo and subscriptionReturns 403 in demo environments and 402 when the business subscription is inactive.
Parent purchase accessThe target purchase must belong to the business, be type purchase, be in a permitted location, and when the token user only has view_own_purchase, the purchase must have been created by that user.
BehaviorCreates or updates the single purchase_return row linked to that purchase, updates quantity_returned on parent purchase lines, adjusts stock, and recalculates the return totals.
Success response201 with the return id, ref number, and parent purchase id.
FieldTypeRequiredDescription
transaction_idintegerYesParent purchase transaction id.
returnsarray<PurchaseReturnInputLine>YesReturn quantities keyed by purchase line id.
tax_amountnumber | nullNoOptional return tax amount.
ref_nostring | nullNoOptional custom return reference number.

PurchaseReturnInputLine object

FieldTypeRequiredDescription
purchase_line_idintegerYesPurchase-line id that belongs to the given parent purchase.
quantitynumberYesReturned quantity for that line. The controller applies sub-unit multipliers where configured.
FieldTypeDescription
messagestringLocalized return-added message.
data.idintegerThe purchase-return id.
data.ref_nostring | nullThe saved return reference number.
data.parent_purchase_idintegerThe parent purchase id.
StatusWhen it happensResponse shape
201The purchase return was created or updated successfully.{ "message": string, "data": { "id": integer, "ref_no": string | null, "parent_purchase_id": integer } }
402The business subscription is inactive.{ "message": string }
403Demo mode is active or the token user lacks purchase.update.{ "message": string }
404The parent purchase id does not exist or is not accessible to the token user.{ "message": "Not found" }
422The request body failed validation or a returns[].purchase_line_id does not belong to the given purchase.Laravel validation JSON or { "message": string }.
500The purchase-return create transaction failed unexpectedly.{ "message": "something_went_wrong" }

Create standalone combined purchase return

PropertyValue
MethodPOST
Path/api/v1/integration/purchase-returns/combined
Permissionpurchase.update.
Demo and subscriptionReturns 403 in demo environments and 402 when the business subscription is inactive.
Location rulelocation_id must belong to the business and be included in the token user's permitted locations.
Validation ruleEvery products[].variation_id must belong to the stated product_id and to the current business.
BehaviorCreates a standalone purchase_return with no parent purchase, creates return lines on the return itself, and decreases stock immediately.
Success response201 with the return id and return_parent_id = null.
FieldTypeRequiredDescription
location_idintegerYesBusiness location id.
transaction_datestringYesReturn date.
final_totalnumberYesTotal return amount including tax.
tax_amountnumber | nullNoOptional return tax amount.
tax_idinteger | nullNoOptional business tax-rate id.
contact_idinteger | nullNoOptional contact id for the standalone return.
ref_nostring | nullNoOptional custom return reference number.
documentfile | nullNoOptional uploaded document, up to 5 MB.
productsarray<CombinedPurchaseReturnLineInput>YesAt least one return line.

CombinedPurchaseReturnLineInput object

FieldTypeRequiredDescription
product_id, variation_idintegerYesProduct and variation ids.
unit_pricenumberYesReturn unit price.
quantitynumberYesReturned quantity. Minimum 0.0001.
lot_numberstring | nullNoOptional lot number.
exp_datestring | nullNoOptional expiry date in Y-m-d format.
FieldTypeDescription
messagestringLocalized return-added message.
data.idintegerThe standalone purchase-return id.
data.ref_nostring | nullThe saved return reference number.
data.return_parent_idnullAlways null for this standalone flow.
StatusWhen it happensResponse shape
201The standalone purchase return was created successfully.{ "message": string, "data": { "id": integer, "ref_no": string | null, "return_parent_id": null } }
402The business subscription is inactive.{ "message": string }
403Demo mode is active or the token user lacks purchase.update.{ "message": string }
404The chosen location is not allowed for the token user.{ "message": "Not found" }
422The request body failed validation or a variation does not belong to the given product and business.Laravel validation JSON or { "message": string }.
500The standalone purchase-return create transaction failed unexpectedly.{ "message": "something_went_wrong" }

Record purchase return payment

Records a payment against a visible purchase return.

Endpoint summary

PropertyValue
MethodPOST
Path/api/v1/integration/purchase-returns/{id}/payments
Permissionpurchase.payments plus the same return visibility required by List purchase returns.
Demo and subscriptionReturns 403 in demo environments and 402 when the business subscription is inactive.
Payment-method rulemethod must be one of the payment methods currently allowed for the return location.
Advance ruleWhen method = advance, the payment amount cannot exceed the linked contact balance.
Success response201 with the created payment id and refreshed return payment status.

Request body

FieldTypeRequiredDescription
amountnumberYesPayment amount. Minimum 0.01.
methodstringYesPayment method key.
paid_onstring | nullNoOptional payment date. Defaults to the current timestamp when omitted.
notestring | nullNoOptional payment note up to 1000 characters.
account_idinteger | nullNoOptional account id. Ignored when method = advance.
card_number, card_holder_name, card_transaction_number, card_type, card_month, card_year, card_securitystring | nullNoOptional card-payment metadata.
cheque_numberstring | nullNoOptional cheque number.
bank_account_numberstring | nullNoOptional bank-account reference.
transaction_no_1, transaction_no_2, transaction_no_3string | nullNoOptional transaction references used by custom_pay_1, custom_pay_2, and custom_pay_3.

Top-level JSON response

FieldTypeDescription
messagestringLocalized payment-added message.
data.transaction_id, data.payment_idintegerReturn id and created payment id.
data.payment_ref_nostring | nullGenerated payment reference number.
data.payment_statusstring | nullRefreshed return payment status after the insert.
data.amountnumberStored payment amount.
data.methodstring | nullStored payment method.
data.paid_onstring | nullISO-8601 payment timestamp.

Status codes

StatusWhen it happensResponse shape
201The payment was recorded successfully.{ "message": string, "data": { ... } }
402The business subscription is inactive.{ "message": string }
403Demo mode is active or the token user lacks purchase.payments.{ "message": string }
404The purchase-return id does not exist in the visible query.{ "message": "Not found" }
422The return is already fully paid, the request body failed validation, the payment method is invalid for the location, or an advance payment exceeds the contact balance.Laravel validation JSON or { "message": string }.
500The purchase-return payment transaction failed unexpectedly.{ "message": "something_went_wrong" }

Delete purchase return

Deletes a visible purchase return and restores stock or parent purchase quantities as needed.

Endpoint summary

PropertyValue
MethodDELETE
Path/api/v1/integration/purchase-returns/{id}
Permissionpurchase.delete.
Demo modeReturns 403 in demo environments.
VisibilityThe target return is loaded through the same permitted-location query used by list and show.
Delete behaviorStandalone combined returns restore stock from the return's own lines. Parent-linked returns restore parent purchase quantities by resetting quantity_returned on the parent purchase lines.
Success response200 with the deleted id.

Top-level JSON response

FieldTypeDescription
messagestringLocalized delete-success message.
data.idintegerThe deleted purchase-return id.

Status codes

StatusWhen it happensResponse shape
200The purchase return was deleted successfully.{ "message": string, "data": { "id": integer } }
403Demo mode is active or the token user lacks purchase.delete.{ "message": string }
404The purchase-return id does not exist in the visible query.{ "message": "Not found" }
500The purchase-return delete transaction failed unexpectedly.{ "message": "something_went_wrong" }