When to use this endpoint

Create an underlying Contract and explicitly supplied membership. Use the returned id for subsequent edits and reads.

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 Add for creation. 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
Contract fieldsMapped valuesname required on create; otherwise optionalname (required/nonblank on create, max 64), number (max 47), manager (max 64), address, notes, customers, budget (float), active (0 Completed, 1 Active, 2 Inactive), typeID, expiryDate/dateStarted (date), dateCompleted (datetime), meta and custom. custom is encoded text; whole meta must decode to an object/array.
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 1NoLegacy 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('AssetContract_createData', [
	'name'=>'Annual service',
	'customers'=>json_encode([[1,1042]]),
	'expiryDate'=>'2027-11-10',
]);

Example response

{
  "ok": 1,
  "id": 18
}

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.
  • Creates the underlying Contract and any explicitly supplied membership; it does not create Jobs or schedule expiry reminders/status work. Omitted optional values use mapped/storage defaults.
  • 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.

See it in Fieldmotion

CRM1

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

CRM2

In CRM2, open Assets > 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