Home Integration API reference
REST API for integrations and external apps
Stock transfers
Lists stock transfer pairs by reading the parent sell_transfer row and its linked purchase_transfer row.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/stock-transfers |
| Permission | stock_transfer.view, stock_transfer.create, or stock_transfer.view_own. |
| Visibility | If locations are restricted, a row is returned when either the source or destination location is permitted. With only stock_transfer.view_own, rows are limited to transfers whose purchase side was created by the token user. |
| Status behavior | Completed transfers are stored on the sell side as final. The status filter accepts both completed and final, but current API-created completed transfers appear as final in the response. |
| CSV behavior | format=csv streams all matching rows with a UTF-8 BOM and ignores page and per_page. location_from and location_to are JSON-encoded in CSV cells. |
| Success response | 200 with paginated StockTransferRow rows. |
| Parameter | Type | Required | Description |
|---|---|---|---|
per_page, page | integer | No | Pagination controls. per_page accepts 1 to 100 and defaults to 20. |
start_date, end_date | string | No | Optional Y-m-d bounds on transaction_date. The date filter is only applied when both values are present. |
status | string | No | pending, in_transit, completed, or final. |
location_from_id, location_to_id | integer | No | Optional source and destination location filters. |
q | string | No | Minimum 2 characters when sent. Matches reference number, notes, numeric id, and source or destination location names. |
format | string | No | json (default) or csv. |
StockTransferRow object| Field | Type | Description |
|---|---|---|
id | integer | Parent sell_transfer id. |
ref_no | string | null | Transfer reference number. |
transaction_date | string | null | ISO-8601 transfer timestamp. |
status | string | null | Sell-side transfer status. Completed transfers appear as final. |
final_total, shipping_charges | number | null | Stored transfer totals. |
additional_notes | string | null | Saved transfer notes. |
purchase_transfer_id | integer | null | Linked purchase_transfer id. |
location_from, location_to | object | Location summaries with id and name. |
| Field | Type | Description |
|---|---|---|
data | array<StockTransferRow> | The current result page. |
meta.current_page, meta.last_page, meta.per_page, meta.total | integer | Laravel paginator metadata. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The stock transfer list was returned successfully. | { "data": [...], "meta": { ... } } or CSV download. |
403 | The token user lacks stock-transfer list access. | { "message": "Unauthorized" } |
422 | The query string failed validation or q was shorter than 2 characters. | Laravel validation JSON or { "message": string }. |
Returns one stock transfer pair by the parent sell_transfer id.
| Property | Value |
|---|---|
| Method | GET |
| Path | /api/v1/integration/stock-transfers/{id} |
| Path parameter | {id} is the parent sell_transfer id returned by the list endpoint. |
| Permission | Same permission and visibility rules as List stock transfers. |
| CSV behavior | format=csv streams one UTF-8 BOM row whose data_json column matches the JSON data payload. |
| Success response | 200 with one StockTransferDetail object. |
StockTransferLine object| Field | Type | Description |
|---|---|---|
id | integer | Sell-line id. |
product_id, variation_id | integer | Product and variation ids on the sell side of the transfer. |
product_label | string | Rendered product label built from the product and variation names. |
sub_sku | string | null | Variation SKU. |
quantity | number | Transferred sell quantity. |
unit_price, unit_price_inc_tax, item_tax | number | null | Sell-line pricing fields. |
line_tax | object | null | Tax summary with id, name, and amount. |
StockTransferDetail object| Field | Type | Description |
|---|---|---|
id | integer | Parent sell_transfer id. |
purchase_transfer_id | integer | Linked purchase_transfer id. |
ref_no | string | null | Transfer reference number. |
transaction_date | string | null | ISO-8601 transfer timestamp. |
status | string | null | Sell-side transfer status. Completed transfers appear as final. |
final_total, shipping_charges | number | null | Stored transfer totals. |
additional_notes | string | null | Saved transfer notes. |
location_from, location_to | object | Location summaries with id and name. |
lines | array<StockTransferLine> | Sell-side transfer lines in line-id order. |
| Field | Type | Description |
|---|---|---|
data | StockTransferDetail | The requested stock transfer payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The stock transfer was returned successfully. | { "data": { ... } } or CSV download. |
403 | The token user lacks stock-transfer list access. | { "message": "Unauthorized" } |
404 | The sell-transfer id, linked purchase-transfer row, or visibility check failed. | { "message": "Not found" } |
422 | The query string failed validation. | Laravel validation JSON. |
Creates a stock transfer pair by inserting a parent sell_transfer row and a linked purchase_transfer row.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/stock-transfers |
| Permission | stock_transfer.create. |
| Demo and subscription | Returns 403 in demo environments and 402 when the business subscription is inactive. |
| Location rule | location_id and transfer_location_id must belong to the business, must be different, and both must be inside the token user's permitted locations when location access is restricted. |
| Status behavior | The request accepts pending, in_transit, or completed. When completed is sent, the sell side is stored as final and the purchase side is stored as received. |
| Stock behavior | When the request status is completed, stock is decreased at the source location and increased at the destination for lines whose enable_stock flag resolves truthy, then the transfer lines are mapped to purchase lines. |
| Reference behavior | ref_no is auto-generated from the stock-transfer reference counter when omitted. |
| Total behavior | final_total defaults to the sum of line totals plus shipping_charges when omitted. |
| Success response | 201 with one StockTransferDetail object. |
| Field | Type | Required | Description |
|---|---|---|---|
location_id | integer | Yes | Source location id. |
transfer_location_id | integer | Yes | Destination location id. Must differ from location_id. |
transaction_date | string | Yes | Date string parsed through ProductUtil::uf_date(..., true). |
status | string | Yes | pending, in_transit, or completed. |
products | array<StockTransferCreateLineInput> | Yes | One or more transfer lines. |
ref_no | string | null | No | Optional custom transfer reference. |
additional_notes | string | null | No | Optional transfer notes. |
shipping_charges | string | number | null | No | Optional shipping amount parsed with num_uf. Defaults to 0. |
final_total | string | number | null | No | Optional explicit final total parsed with num_uf. |
StockTransferCreateLineInput object| Field | Type | Required | Description |
|---|---|---|---|
product_id | integer | Yes | Business product id. The controller performs a business-level existence check after validation. |
variation_id | integer | Yes | Variation id belonging to the selected product. |
quantity | string | number | Yes | Transfer quantity parsed with num_uf. |
unit_price | string | number | Yes | Transfer unit price parsed with num_uf. |
enable_stock | boolean | null | No | Optional stock flag. When omitted, the controller falls back to the product's enable_stock setting. |
product_unit_id, sub_unit_id | integer | null | No | Optional sub-unit metadata copied into the sell-side line builder. |
base_unit_multiplier | number | null | No | Optional multiplier used to convert purchase-side quantity and price values into base-unit storage. |
lot_no_line_id | integer | null | No | Optional purchase-line id used to copy lot number and expiry metadata into the purchase-transfer line when a matching purchase line exists. |
| Field | Type | Description |
|---|---|---|
data | StockTransferDetail | The created stock transfer payload. |
| Status | When it happens | Response shape |
|---|---|---|
201 | The stock transfer pair was created successfully. | { "data": { ... } } |
402 | The business subscription is inactive. | { "message": string } |
403 | Demo mode is active, the token user lacks stock_transfer.create, or the token user may not access both transfer locations. | { "message": string } |
422 | The request body failed validation or a product or variation check failed during line enrichment. | Laravel validation JSON. |
500 | The transfer transaction failed unexpectedly or the linked purchase-transfer row could not be reloaded after creation. | { "message": string } |
Updates the workflow state of an existing stock transfer pair.
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/v1/integration/stock-transfers/{id}/update-status |
| Path parameter | {id} is the parent sell_transfer id. |
| Permission | stock_transfer.update. |
| Visibility | The endpoint checks the same permitted-location logic as list and show. The view_own owner restriction is applied only when the token user has stock_transfer.view_own but not stock_transfer.view. |
| Demo mode | Returns 403 in demo environments. |
| Status behavior | The request accepts pending, in_transit, or completed. When completed is sent, the sell side is saved as final and the purchase side is saved as received. |
| Stock behavior | Stock movement and purchase/sell mapping are applied only when transitioning to completed from pending or in_transit, preventing double-application when the sell side is already final. |
| Success response | 200 with one StockTransferDetail object. |
| Field | Type | Required | Description |
|---|---|---|---|
status | string | Yes | pending, in_transit, or completed. |
| Field | Type | Description |
|---|---|---|
data | StockTransferDetail | The updated stock transfer payload. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The transfer status was updated successfully. | { "data": { ... } } |
403 | Demo mode is active or the token user lacks stock_transfer.update. | { "message": string } |
404 | The sell-transfer id, linked purchase-transfer row, or visibility check failed. | { "message": "Not found" } |
422 | The request body failed validation. | Laravel validation JSON. |
500 | The status update transaction failed unexpectedly or the linked purchase-transfer row could not be reloaded afterward. | { "message": string } |
Deletes a stock transfer pair by the parent sell_transfer id.
| Property | Value |
|---|---|
| Method | DELETE |
| Path | /api/v1/integration/stock-transfers/{id} |
| Path parameter | {id} is the parent sell_transfer id. |
| Permission | stock_transfer.delete. |
| Visibility | The same permitted-location and optional view_own owner checks used by the integration visibility helper are applied before deletion. |
| Demo mode | Returns 403 in demo environments. |
| Edit-window rule | The business transaction_edit_days value must still allow the sell-transfer row to be edited. |
| Delete blockers | The delete is rejected when any purchase line on the linked purchase_transfer has quantity_sold > 0. |
| Delete behavior | When mapped sell/purchase links exist, the controller decrements quantity_sold on purchase lines, reverses stock from destination to source, deletes the line-mapping rows, then deletes both transfer transactions. |
| Success response | 200 with the deleted id. |
| Field | Type | Description |
|---|---|---|
message | string | Localized delete-success message. |
data.id | integer | The deleted parent sell_transfer id. |
| Status | When it happens | Response shape |
|---|---|---|
200 | The stock transfer pair was deleted successfully. | { "message": string, "data": { "id": integer } } |
403 | Demo mode is active or the token user lacks stock_transfer.delete. | { "message": string } |
404 | The sell-transfer id, linked purchase-transfer row, or visibility check failed. | { "message": "Not found" } |
422 | The business edit window expired or one of the linked purchase lines has already been sold from the destination side. | { "message": string } |
500 | The delete transaction failed unexpectedly. | { "message": "something_went_wrong" } |