When to use this endpoint

Use the Purchase Order line import tool after mapping file columns. This appends lines; it does not replace existing ones or deduplicate an earlier import.

Authentication and permissions

Authenticate with signed API-key fields or a logged-in CRM session. Session requests use dispatcher CSRF protection when configured. API keys use their owner’s permissions.

Requires explicit View on Purchase Order or Purchase Orders, plus Edit on either page. Non-administrators with legacy Purchase Orders visibility disabled (crm_access bit 256) are denied.

Explicit order IDs must identify active, visible records in the authenticated tenant. TeamAccess follows linked Contracts, Customers, Jobs, Quotes and Departments; legacy department filtering follows Customer, Quote-customer and ordinary customer-Job links. Scoped users cannot read unlinked or Warehouse orders through this check.

Parameters

ParameterTypeRequiredDescription
po_idPositive integer or digit stringYesActive, visible parent Purchase Order ID.
rowsJSON array stringYesArray of rows, each a positional array of cells. Must be JSON-encoded; native arrays are not decoded by this route.
mapJSON array stringYesArray aligned by column position. Each object uses to; from is ignored. Recognised to values: stock_type, stock_id, stock_text, amt, cost_net, total_net, total_tax, nominal_code, taxtype.

Example request

$result = FM_api('PurchaseOrder_importLineItems', [
	'po_id'=>'1042',
	'rows'=>json_encode([['Misc','Packing materials','1.5','10','15','3']]),
	'map'=>json_encode([
		['to'=>'stock_type'],['to'=>'stock_text'],['to'=>'amt'],
		['to'=>'cost_net'],['to'=>'total_net'],['to'=>'total_tax'],
	]),
]);

Example response

{
  "ok": 1,
  "lineitem_ids": [
    2081
  ]
}

Errors and unusual responses

ResponseCondition
{"error":"not logged in"}No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs.
{"error": "permission denied"}Page/action rights or the legacy visibility setting deny access.
{"error": "purchase order does not exist"}An explicit parent/header ID is absent, deleted or outside the caller’s scope.
{"error": "invalid parameter: rows"}rows decodes to something other than an array.
{"error": "invalid parameter: map"}map decodes to something other than an array.

Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.

Behaviour and edge cases

  • rows/map must be JSON array strings. Column mapping remains positional: map[i].to reads row[i]; from is ignored. Unknown targets are ignored, and a row with no recognised targets contributes false in lineitem_ids.
  • stock_type is 1 for exact Stock or an integer-converted 1; other values select miscellaneous type 2. IDs are numeric; nominal_code and taxtype remain text and use the mapped nominal adapter instead of integer truncation.
  • Each recognised row uses mapped line creation with a stock picker, quantity (default 0) and the supplied cost/net/tax. Numeric values must be finite/nonnegative, descriptions fit 255 Unicode characters and catalogue selections must exist and be available.
  • Supplied line totals remain authoritative; no quantity × cost or tax-rate formula is executed. The import appends lines with consecutive display positions; it does not replace/deduplicate earlier imports.
  • Creates initial Purchase availability for imported quantities. The complete import is transactional, including parent totals/history and approval reset. Supplier, carriage and changed line data clear approval and require approval again. Exact no-op saves retain approval. Non-administrators with crm_access bit 8192 cannot make financial changes to approved orders.

Side effects

  • Writes use the tenant-owner lock and a transaction or caller savepoint. A rejected operation rolls back its local writes and checked history. Earlier separate API requests remain committed.
  • Edit events, notifications and form follow-ups run after the owning commit. A saved/no-replay warning identifies committed data with a failed follow-up; inspect the saved state rather than repeating creation or sending.
  • Creates mapped lines and initial order containers, refreshes stored parent totals plus carriage, touches the header and records line history. No inventory receipt or supplier email is created.

See it in Fieldmotion

CRM1

In CRM1 Purchase Order details, import line items and inspect PurchaseOrder_importLineItems; the import helper serializes rows/map as JSON.

CRM2

In CRM2 Purchase Order details, choose Import for the spreadsheet and filter for PurchaseOrder_importLineItems.

Related endpoints