Programme Contracts
Add one-off work to a live Visit
/a/ContractProgramme_addJob
Create an extra Service Job or quality inspection without modifying the reusable route.
When to use this endpoint
Choose an existing live Visit/day in Job Progress. Select its scoped Contract/Site, kind and duration. Use one stable request_key for exact retries.
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. Also requires features2.contractProgrammePublishing. Requires Contracts 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.
Non-administrators also need Jobs Add; TeamAccess field roles cannot add through this workflow.
For newly created work, the configured CRM Job customer/Contract eligibility restriction is checked independently. Publication revalidates it before changing prior work; adopted reactive Jobs use their existing identity.
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 |
|---|---|---|---|
visit_id | Positive integer or digit string | Yes | Existing live, non-deleted Visit. Actor owns its run or can see published work in that Visit. |
contract_id | Positive integer or digit string | Yes | Active, non-deleted Contract (active=1) with an accessible Programme configuration. Inactive/Completed Contracts reject new Service and QI work. |
site_id | Positive integer or digit string | Yes | Active non-deleted child Customer linked to the Contract. |
day_number | Positive integer or digit string | Yes | Existing numbered day in the Visit’s saved route revision. |
date | YYYY-MM-DD | Yes | Explicit tenant-local calendar date; accepted independently of the Visit start/end range. |
user_id | Positive integer or digit string | No | Defaults to Visit user; both Visit user and target must be active/in permitted team. |
kind | S or Q | No | Defaults to S (Service). Q requires contractProgrammeQI and a configured active grading set, QI Form and choice field. |
duration_minutes | Positive integer or digit string | No | Defaults to Contract default_duration; 1–1440 minutes. |
request_key | String | Yes | Nonblank trimmed replay key, max 64 characters. Same actor and exact request return saved result; changed data with same key fails. |
Example request
$result = FM_api('ContractProgramme_addJob', [
'data' => json_encode([
'visit_id' => 710,
'contract_id' => 210,
'site_id' => 1043,
'day_number' => 1,
'date' => '2026-11-10',
'kind' => 'S',
'request_key' => 'extra-north-2026-11-10-1',
]),
]);
Example response
{
"ok": 1,
"id": 812
}
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":"Inactive or completed Contracts cannot receive new work"} | The selected Contract is not active. No new Job, audit or replay acknowledgement is saved. |
{"error":"No start time remains on the selected date"} | Existing work runs through the remaining date; choose another date or adjust the live schedule. |
{"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":"This Contracts capability is not enabled"} | The operation’s additional feature flag is disabled. |
{"error":"Choose a live Visit"} | Visit is missing, deleted or not live. |
{"error":"Choose an existing Visit day"} | day_number not in saved route revision. |
{"error":"Request key has already been used for different data"} | Replay key reused with another payload or actor. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Creates a new Job and ad_hoc provenance; it does not adopt an existing reactive Job or change the master route. Position is one greater than the maximum in this Visit/day.
- The Job starts no earlier than account work-day-start (fallback 09:00), after the latest scheduled end of existing work for the selected local user/date. Ordinary Jobs and earlier ad hoc Jobs count, including work crossing from the previous date; cancelled, deleted and archived work do not. Duration comes from hours. Capacity remains advisory. If no start remains before local midnight, the call fails rather than silently scheduling on another date.
- The Contract must be active. The explicit live date may differ from the Visit’s original date range, supporting rescheduled work; it does not change the reusable route or the saved Visit boundary.
- QI snapshots the current grading set revision/labels/categories and choice-field identity. Later set edits do not rewrite it. New Job checklist snapshots and normal reference/report numbering follow the shared materializer.
- An exact completed replay returns its original id and schedule without allocating another time, even if the Contract was later deactivated. Current authentication/feature/role gates still apply. No ordinary Job_new event/email workflow is invoked.
- The new Job’s due_date uses its scheduled date and its initial date_completed is an estimated end. is_complete remains 0; these timestamps do not indicate finished work.
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.
- Commits new Job, Contract link, Site open-Job counter, provenance, Job/ad_hoc_job_added audits, snapshots and replay acknowledgement atomically. Does not create standalone Tasks.
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
In Job Progress open Add Job on a live day. Filter for ContractProgramme_addJob. CRM2 supplies that day’s Visit, user, day_number and scheduled_date, a selected Contract/Site and one generated key.
Related endpoints
ContractProgramme_publish— Create a live Visit before adding one-off work.ContractProgramme_saveConfig— Configure Service/QI Forms and grading choices.ContractProgramme_saveGrades— Maintain the grading set used by new inspections.