When to use this endpoint

Use the legacy blank-line/save flow for CRM1, or mapped creation/update for layout clients. Keep the line and its parent IDs together. A full CRM2 spreadsheet save uses Layout_setValue so header and all replacement lines commit together.

Authentication and permissions

Authenticate with signed API-key fields or a logged-in CRM session. API keys use their owner’s tenant; session dispatch applies CSRF checks. Office requisition access requires View and Edit on Requisition Order or Requisition Orders. A visible UI control is not sufficient authorization.

Tenant and TeamAccess/legacy department scope apply to headers and to the parent of each line. Deleted parents hide their lines. Scoped users can see their own unlinked requisitions; the legacy department-only rule retains its target-based visibility. There is no additional Requisition feature-entitlement check.

Parameters

ParameterTypeRequiredDescription
id, ro_idPositive integersYesExisting line and its actual parent. A mismatched parent fails before any write.
stock_type, supplier_id, stock_idIntegersYesstock_type=1 standard or 2 miscellaneous. Standard stock must exist and be active/unarchived; miscellaneous uses stock_id=0 and nonblank text. Supplier 0 is unassigned; a positive supplier must exist and be active.
stock_textStringNoDefaults blank, trimmed for this legacy save, maximum 255 bytes. Required nonblank for miscellaneous lines.
qtyNonnegative whole numberYesFractions are rejected rather than truncated; the stored quantity column remains integer.
cost, totalnet, totaltaxAmountsYescost and totaltax must be finite nonnegative amounts. The net amount is recomputed from qty × cost and rounded to two decimals; totalnet is retained as a required legacy input but is not trusted. Tax remains the explicit supplied amount.
nominalStringYesLegacy Account code/ID. Explicit nominal_id and nominal_code may disambiguate; conflicting matching accounts fail.
nominal_id, nominal_codeInteger/stringNoCanonical local Account identity. Storage remains code-only.
taxtypeStringYesTax-code label up to 32 bytes, blank allowed. No catalogue/rate inference is performed.

Example request

$result = FM_api('RequisitionOrderEntry_save', [
	'id' => '2088',
	'ro_id' => '1042',
	'stock_type' => '1',
	'supplier_id' => '601',
	'stock_id' => '501',
	'stock_text' => '',
	'qty' => '2',
	'cost' => '12.50',
	'nominal' => '200',
	'taxtype' => 'VAT20',
	'totalnet' => '25.00',
	'totaltax' => '5.00',
]);

Example response

{
  "ok": 1
}

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"}Required office page/action access is absent.
{"error":"requisition order does not exist"}The header is missing, deleted or outside the caller’s scope.
{"error":"Processed requisitions are read-only"}A material/header edit targets status 2.
{"error":"Unable to save requisition. Check the saved state before retrying."}A checked database/audit operation failed; verify saved state before replaying an uncertain request.

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

Behaviour and edge cases

  • Nominal storage remains the accounting code. Explicit nominal_id/nominalID resolve local Accounts; nominal_code is an explicit code. Legacy nominal/nominalCode and taxType.nominalID resolve a matching code before treating a numeric value as an Account ID. Conflicting explicit ID/code matches return an error. Unknown legacy text can remain a code. Reads add nominal_id (integer) and nominal_code (string), normalize nominalCode to the local ID when selected, and normalize taxType.nominalID to that ID.
  • Blank-line creation inserts only its parent and server timestamps/defaults; extra material fields are ignored. Material creation/update validates references and nonnegative whole quantities. A missing row or wrong parent returns an error.
  • The server calculates line net from quantity × unit cost; tax is the explicitly supplied amount. It sums stored line net/tax into the parent; delivery charges remain separate. Existing approval is retained.
  • Rebuilds only the parent’s unallocated initial containers (type 15), preserving allocations at their existing destinations. Changing material identity or reducing below allocated quantity fails atomically. No physical inventory movement occurs.
  • The header/line changes, aggregate totals and audit are checked in one tenant transaction. A failed write or audit rolls back the operation. Existing caller transactions use savepoints; the caller owns final commit. No request key deduplicates creation.

Side effects

  • Writes line/history, recalculates parent totals and last_edited, reconciles initial containers and invalidates line/header caches in the same operation. A full Layout_setValue replacement defers reconciliation until every replacement line is valid.

See it in Fieldmotion

CRM1

In CRM1 Requisition details edit a material row; filter for RequisitionOrderEntry_save. The UI sends stock_text even for stock rows and all current totals. Quote-to-requisition copying uses the same path.

CRM2

No direct caller was found in CRM2 source. Its requisition screen uses mapped layout reads/writes instead of this legacy endpoint.

Related endpoints