Programme Contracts
Create a Programme Contract
/a/ContractProgramme_createContract
Create a manual Contract and its Site membership in one transaction.
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
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | Yes | Nonblank, trimmed Contract name, at most 64 characters. |
customer_id | Positive integer or digit string | Yes | Existing, non-deleted parent Customer (parent_id=0). |
site_ids | Array | No | Up to 500 positive child Customer IDs belonging directly to the selected parent. Defaults to []; duplicates are removed. The parent is always linked. |
manager_id | Positive integer or digit string | No | Defaults to the actor; must be active and in the team. The explicit Parent Manager role must choose itself. |
department_id | Positive integer or digit string | Conditional | Required when TeamAccess hierarchy is enabled; must be an available Contract Department. Otherwise accepted as an integer metadata value. |
area_id | Positive integer or digit string | No | Existing active Work Area; zero/blank/omitted means none. |
type_id | Positive integer or digit string | No | Existing Contract Type; zero/blank/omitted means none. |
sector | String | No | Configured exact Sector name or blank; at most 64 characters. |
active | 0, 1 or 2 | No | Defaults to 1: Active; 0 Completed, 2 Inactive. |
date_started, expiry_date | YYYY-MM-DD | No | Blank/omitted means null. Expiry must not precede start. |
number, address, notes | Strings | No | Trimmed; limits 47, 4096 and 16000 characters respectively; default blank. |
budget | Numeric | No | Finite 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
| 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":"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
ContractProgramme_saveConfig— Configure the new Contract’s operational Forms and checklist.ContractProgramme_saveDefaults— Maintain inherited module Forms.