Purchase orders
Create a legacy Purchase Order
/a/PurchaseOrder_new
Create an empty order header with a supplier and the next displayed number.
When to use this endpoint
Use the CRM1 New action, then add lines with PurchaseOrderEntry_new/save. This route has snake_case inputs; the mapped createData route uses a different field contract.
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 Add on either page. Non-administrators with legacy Purchase Orders visibility disabled (crm_access bit 256) are denied.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
supplier_id | Integer-compatible string | Yes | Positive integer/digit string of at most 11 bytes. The supplier must exist, be active, visible and not on hold. |
reference | Text | No | Default "no reference". Blank remains blank; maximum 32 bytes, including multi-byte text. |
form_id | Integer-compatible | No | Default 0. No active/type-5 lookup in this handler. |
delivery_address | Text | No | Default empty string. Other mapped delivery/contact fields are not consumed here. |
Example request
$result = FM_api('PurchaseOrder_new', [
'supplier_id'=>'42',
'form_id'=>'5',
'reference'=>'PO-2026-1042',
]);
Example response
{
"ok": 1,
"id": 1042
}
Errors and unusual responses
| Response | Condition |
|---|---|
{"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: supplier_id"} | Missing, nonpositive or over-11-byte supplier input. |
{"error": "reference too long. max length 32"} | Reference exceeds 32 bytes. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Validates the supplier through its own page/record scope and rejects missing, inactive or held suppliers. A nonzero form_id must be an active type-5 form; 0 remains the blank-form option.
- Reference defaults to "no reference"; blank remains blank. Its legacy limit is 32 bytes. Creation/last-edited time and creator come from the authenticated server context, and the empty order starts with zero totals.
- MAX(po_num)+1 and insertion share the tenant-owner lock, so concurrent office creators cannot reserve the same next number. Each successful call still creates a new header; retries have no idempotency token.
- No line rows, allocations, inventory receipts or supplier emails are created. Use the returned local id to add lines.
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.
- Records checked creation history and fires PurchaseOrder_new after commit. The legacy route does not issue the mapped create notification.
See it in Fieldmotion
CRM1
In CRM1 Purchase Orders, click New, select supplier/form and watch PurchaseOrder_new; the returned id opens the detail page.
CRM2
CRM2 creates mapped headers through Layout_setValue → PurchaseOrder_createData. No direct CRM2 PurchaseOrder_new screen caller was found. The mobile app goes through m/www’s separate PurchaseOrder_save/OrdersM workflow; its validation and ownership rules do not establish this office endpoint’s contract.
Related endpoints
PurchaseOrderEntry_new— Reserve a blank line.PurchaseOrder_createData— Use the mapped header field set.