When to use this endpoint

Use only when an integration intentionally manages the received status. Normal receipt workflows derive it from Goods Received Notes; cancellation has a separate helper.

Authentication and permissions

Authenticate with signed API-key fields or a logged-in CRM session. Session requests use dispatcher CSRF protection when configured.

Requires explicit View on Purchase Order or Purchase Orders. Writes also require the matching Edit permission; clearing invoice details requires Delete. A non-administrator blocked by the legacy Purchase Orders visibility flag (crm_access bit 256) is denied. API keys use their owner’s permissions.

The primary order is checked against the current tenant and Purchase Order record scope. Configured TeamAccess follows permitted linked Contracts, Customers, Jobs, Quotes and Departments; the legacy department filter follows direct Customer/Quote/customer-Job links. An inaccessible or missing order returns purchase order does not exist.

Parameters

ParameterTypeRequiredDescription
idInteger-compatibleYesPositive local Purchase Order ID/digit string; not the displayed po_num. Missing, malformed or inaccessible IDs fail.
valInteger-compatibleYesInteger 0 Open, 1 Part-Received, 2 Received, 3 Over-received or 4 Cancelled. Other values are rejected; cancellation has additional preconditions.

Example request

$result = FM_api('PurchaseOrder_setStatus', [
	'id'=>'1042',
	'val'=>'1',
]);

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": "missing or invalid parameter: id"}id integer-converts below 1.
{"error": "missing or invalid parameter: val"}val absent/null or integer-converts below zero.
{"error": "purchase order does not exist"}No matching row.
{"error": "permission denied"}The required page/action or legacy visibility setting denies access.
{"error": "Cannot cancel a Purchase Order that has started receiving"}Received status is not Open or already Cancelled.
{"error": "Cannot cancel a Purchase Order that has been sent"}The open order has date_sent set.

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

Behaviour and edge cases

  • Only integer statuses 0–4 are accepted: Open, Part-Received, Received, Over-received, Cancelled. Unknown/fractional values fail.
  • Setting Cancelled uses the same sent/receiving preconditions as PurchaseOrder_cancel; an alternate setter cannot bypass them.
  • This remains the received-status field, separate from date_approved, date_sent and CRM2 meta.status. Manually setting a received status does not create receipts, move stock or reconcile quantities.

Side effects

  • Header writes lock the existing order and tenant owner, check persistence and record history in the same transaction. Errors roll back the header and audit; a true no-op returns {ok:1,warning:"no change needed"} without a new event/history entry. Cache invalidation and edit-event follow-ups run after the owning transaction commits; an event exception returns saved=1 and a no-replay warning.
  • A changed header emits PurchaseOrder_edit after commit; configured account listeners may perform integration work. No order email/PDF is sent directly by this route.

See it in Fieldmotion

CRM1

The CRM1 Purchase Orders list exposes an inline status selector and calls PurchaseOrder_setStatus. The detail page directs normal received changes to Goods Received and uses PurchaseOrder_cancel for cancellation.

CRM2

No direct caller was found in CRM2 source. Its Purchase Order screen uses mapped reads and generic field saves rather than this legacy endpoint.

Related endpoints