When to use this endpoint

Use the underlying record ID; this namespace does not imply a customer filter. Supply customers deliberately to set Contract membership.

Authentication and permissions

Use signed API-key authentication or a logged-in CRM session. API keys act as their owner; session requests use dispatcher CSRF protection where configured. IDs and mapped queries address the authenticated tenant.

Login is required. CRM2 requests require Contracts View and Edit for changes. CRM2 TeamAccess scope applies to records and related data. These added CRM2 role/scope checks do not apply to CRM1 requests; CRM1 retains its legacy permission model. Tenant isolation and business validation apply to both clients.

When contractProgrammes and contractProgrammeImport are both enabled, source-owned Contracts remain protected from manual writes in both clients. Alias creates use Add for CRM2; existing-record edits require nonempty explicit IDs. CRM1 is not given a new CRM2 role requirement by this source guard.

Parameters

ParameterTypeRequiredDescription
id / idsPositive integer or native/JSON-encoded listYes for updates; optional for readsid takes precedence. Decimal integer strings are accepted and duplicates removed; invalid/nonpositive members reject the selection. Empty lists select no records. Omitted IDs on a read leave the other mapped filters in control.
field / valMapped field name / non-null valueYesfield must be a mapped editable name. val must be present and non-null; blank values follow the mapped clearing rules. Lifecycle/identity fields are rejected.
Contract fieldsMapped valuesname required on create; otherwise optionalUses the canonical Contract map: the fields above except custom is customValues (JSON), with departmentID, metaHoursBudget, metaNotInvoiceable and metaStage aliases. Identity/createdBy/cDate/lastEdited are read-only.
customersNative or JSON-encoded [type,id] tuplesNoExact tuples: 0 Customer, 1 Asset. IDs must reference available active records in this tenant and, for CRM2, scope. Duplicate tuples collapse; [] or blank clears membership. Saves synchronize the corresponding typed relationship links inside the tenant transaction.
invoiceable0 or 1Not an inline fieldLegacy name: writes meta.not_invoiceable as string "0" (invoiceable) or "1" (not invoiceable). Omission preserves the saved flag. Create defaults to "0". For inline edits use metaNotInvoiceable.

Example request

$result = FM_api('CustomerContract_updateField', ['id'=>'18','field'=>'name','val'=>'Updated label']);

Example response

{
  "ok": 1,
  "oldData": [
    {
      "id": "18",
      "name": "Previous name"
    }
  ]
}

Scalar numeric values may be strings or numbers depending on the database driver.

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": "Your role does not permit this action."}A CRM2 request lacks the required View/action grant.
{"error": "Record is unavailable or outside your permitted scope."}A selected write target is unavailable or outside CRM2 scope.
{"error": "missing or invalid parameter: id/ids"}An update omits its selection, or supplies an invalid/nonpositive ID.
{"error": "Unable to complete this operation. Check the saved state before retrying."}An unexpected persistence failure is reported; inspect saved state before retrying.

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

Behaviour and edge cases

  • Record identity and lifecycle values are server-owned. Inline writes reject id and lifecycle targets. Full edits tolerate unchanged lifecycle values from a fetched record and reject changed ones; create derives them on the server. Transport metadata such as CSRF/API/session keys and extra is not a business-field update.
  • Omitted or native-null optional mapped values are skipped on edits. Blank text is saved; blank date/datetime/JSON clears to SQL NULL where mapped. Date fields require real YYYY-MM-DD. Ordinary numeric fields retain the mapped numeric conversion; the explicit ID/reference/enum checks listed here run first.
  • Selected records are checked before writes. Tenant primary writes run in one checked transaction: a later validation/write failure rolls back earlier members of the batch. Empty/no-change updates return ok=1 and warning="No Change."; inline responses also carry oldData with previous storage-column values. Unknown business fields are ignored by the mapped writer.
  • Creation merges supplied metadata over spendStatus="ok", hoursSpentStatus="ok" and not_invoiceable="0"; creator and cDate come from the server. Existing Programme provenance markers cannot be forged/changed and are retained on metadata replacement. Whole meta otherwise replaces its saved object; omit it to preserve unrelated keys.
  • departmentID/meta.department_id must refer to an existing department when positive. CRM2 department-scoped creates default to the first allowed department, and CRM2 writes must remain within the effective department scope. CRM1 receives no CRM2 department restriction.
  • Present expiryDate cancels/replaces expiry reminders and status work for every actual selected Contract ID; present active without expiryDate reschedules status using saved expiry. Blank expiry clears the scheduled work; the legacy NaN-NaN-NaN expiry sentinel clears the stored date. These follow-ups also run for a no-change save when requested.
  • No direct caller of this exact namespace was found in the current mobile intermediary/app sources; mobile synchronization uses separate APIs.

Side effects

  • Changed mapped values stamp last_edited, invalidate the affected table cache and record field-change history. Read the saved object back before performing dependent work.
  • Expiry/status scheduling follows committed tenant persistence. A thrown follow-up failure returns ok=1, saved=1 and a warning to review scheduling rather than repeat the save; it cannot roll back the saved Contract. Check saved values and scheduled work before retrying.

See it in Fieldmotion

CRM1

In CRM1, open Customers > a record > Contracts. The current source uses Customer_contractsGetDT for the table and Contract_setNotes/Contract_setActive for edits; no direct call to this alias was found.

CRM2

In CRM2, open Customers > a record > Contracts. The current shared moduleContracts selects Contract/Contracts prefixes, including Contracts_getDataTable and Contract create/update routes; no direct current caller to this legacy alias was found. Inspect those requests rather than assuming the tab caption selects this namespace.

Related endpoints