When to use this endpoint

Create missing parent Customers and child Sites first. This creates the Contract and initial operational configuration; follow with Forms, checklist and QI settings. It remains available when source integration is enabled and does not create a source mapping.

Send operation fields inside one JSON-encoded data object. When data is present it replaces top-level operation fields; otherwise the handler accepts the top-level request. String data is limited to 2 MB. Reserved transport/internal keys are removed. Malformed or non-array JSON becomes an empty input, so validate JSON before sending.

Authentication and permissions

Authenticate with a signed API key or logged-in CRM session; session requests follow dispatcher CSRF checks. API-key requests use the key owner’s identity and permissions.

Requires the Contracts entitlement (features & 64), features2.contractProgrammes and Contracts View. Requires Contracts Add rather than Edit.

All storage belongs to the authenticated tenant. Contract operations follow the actor’s recursive HR manager/team scope, or the configured TeamAccess Contract/Department policy. Client administrators have broad Contract scope; private Programme and route ownership still applies. Active assignees must be within the permitted team.

The tenant must have the Programme storage upgrade (foundation 803; independent route ownership 804 before planning). Requests never create or repair tables. A missing/incompatible storage failure can return an initialization/storage error or Contracts operation failed. Check the saved state before retrying.

Parameters

ParameterTypeRequiredDescription
nameStringYesNonblank, trimmed Contract name, at most 64 characters.
customer_idPositive integer or digit stringYesExisting, non-deleted parent Customer (parent_id=0).
site_idsArrayNoUp to 500 positive child Customer IDs belonging directly to the selected parent. Defaults to []; duplicates are removed. The parent is always linked.
manager_idPositive integer or digit stringNoDefaults to the actor; must be active and in the team. The explicit Parent Manager role must choose itself.
department_idPositive integer or digit stringConditionalRequired when TeamAccess hierarchy is enabled; must be an available Contract Department. Otherwise accepted as an integer metadata value.
area_idPositive integer or digit stringNoExisting active Work Area; zero/blank/omitted means none.
type_idPositive integer or digit stringNoExisting Contract Type; zero/blank/omitted means none.
sectorStringNoConfigured exact Sector name or blank; at most 64 characters.
active0, 1 or 2NoDefaults to 1: Active; 0 Completed, 2 Inactive.
date_started, expiry_dateYYYY-MM-DDNoBlank/omitted means null. Expiry must not precede start.
number, address, notesStringsNoTrimmed; limits 47, 4096 and 16000 characters respectively; default blank.
budgetNumericNoFinite nonnegative number; defaults to zero.

Example request

$result = FM_api('ContractProgramme_createContract', [
	'data' => json_encode([
		'name' => 'North parks',
		'customer_id' => 1042,
		'site_ids' => [
			1043,
		],
		'sector' => 'Parks',
	]),
]);

Example response

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

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":"Programme Contracts is not enabled"}Workspace flag or Contracts entitlement is disabled.
{"error":"Permission denied"}Contracts View or the required action permission is unavailable.
{"error":"Choose an existing parent Customer"}Selected Customer is missing, deleted or a child.
{"error":"Site belongs to another Customer or is unavailable"}A Site is missing/deleted, is not a child, or belongs to another parent. This creation path does not check the Site is_active flag.
{"error":"Choose yourself as Contract Manager when creating a Contract."}Parent Manager attempted another manager.

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

Behaviour and edge cases

  • Contract, configuration, parent/Site membership links and compatibility Customer cache are committed together. It creates no Jobs.
  • The initial manager is recorded separately from source master ownership. Default Forms are inherited when the Contract is read or work is created.
  • Membership validation rejects deleted or unrelated Sites but does not require is_active=1 during creation. Route planning later requires active Sites.

Side effects

  • The service serializes writes on the tenant owner in a transaction. Validation, persistence, audit or TeamAccess outstanding-Job access failures roll back that transaction. Successful changed writes refresh linked Contract/Customer sync timestamps and shared mobile update markers, then invalidate CRM caches after success. These operations do not create schema or enable account features.
  • Records contract_created in the tenant audit. Standard Contract expiry notifications and status scheduling run after commit. A follow-up exception retains ok/id and adds saved=1 and a warning; do not recreate the Contract after that response.

See it in Fieldmotion

CRM1

No direct caller was found in CRM1 source. This workflow is implemented by the opted-in CRM2 Programme Contracts workspace.

CRM2

Open Contracts → Create in the Programme workspace, select a parent and its Sites, then Save. Filter Network for ContractProgramme_createContract; the UI sends site_ids as an array inside data.

Related endpoints