Programme Contracts
Publish reviewed Programme Visits
/a/ContractProgramme_publish
Create dated work and archive acknowledged prior incomplete work atomically.
When to use this endpoint
Call preview and review its complete impact first. Reuse the same scheduling fields and returned revision. Generate one request_key per intended publication and keep the exact request for uncertain-response 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 and Edit. The legacy Job edit restriction (permissions bit 128) removes Edit; TeamAccess field roles cannot add/edit 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 |
|---|---|---|---|
run_id | Positive integer or digit string | Yes | Active actor-owned run whose Programme is active. |
user_id | Positive integer or digit string | Yes | Active local assignee within your permitted team; use the workspace’s board user choices. |
start_date | YYYY-MM-DD | Yes | Real tenant-local calendar date. No future-only restriction. |
visits | Integer-compatible | No | Defaults to 1; cast to integer and must be 1 or 2, within remaining run Visit count. |
saturday, sunday, bank_holidays | 0/1 or boolean | No | Each defaults to 0. Setting 1 includes those calendar dates; 0 skips them. |
revision | SHA-256 string | Yes | Exact preview revision; publication recomputes the payload before writes. |
request_key | String | Yes | Nonblank trimmed key, max 64 characters. Actor and full input participate in replay hash. Preserve identical field values/types/order on retry. |
confirm_archive | 0/1 or boolean | No | Required as 1 when the preview lists prior incomplete work; defaults to 0. |
Example request
$result = FM_api('ContractProgramme_publish', [
'data' => json_encode([
'run_id' => 510,
'user_id' => 104,
'start_date' => '2026-11-09',
'visits' => 1,
'revision' => 'replace-with-preview-revision',
'request_key' => 'north-2026-11-09-1',
'confirm_archive' => 1,
]),
]);
Example response
{
"ok": 1,
"visit_ids": [
710
],
"job_ids": [
810,
811
],
"archived": 2
}
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":"This Contracts capability is not enabled"} | The operation’s additional feature flag is disabled. |
{"error":"The preview changed. Review the updated dates and prior work before publishing."} | Route, settings, current work or proposed payload changed. |
{"error":"Confirm archiving the prior incomplete work"} | Archive impact exists without confirm_archive=1. |
{"error":"Request key has already been used for different data"} | Key reused with a different request 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
- Exact completed retries return the stored result before preview revalidation; permissions/feature gates still apply. Same key with different data or actor fails. There is one durable batch acknowledgement, and transaction locking/occurrence uniqueness prevents duplicate publication.
- Archives prior incomplete Jobs from the preview as Cancelled (is_complete=5), retaining metadata/evidence. Previous live Visits for this Programme/user become archived. Completed Jobs are not changed to Cancelled.
- New Service Jobs get active Form, per-Form report number, ordinary configured Job reference (including deliberately blank references), Site snapshot, skills, checklist and immutable Programme provenance. Work is immediately released, including future-dated Jobs.
- Reactive entries adopt the original Job once, preserving its reference/Form/evidence; previous assignment is retained. They are not copied again on later Visits or a new run.
- No standalone Tasks are created from checklist definitions. The shared materializer writes directly; this route does not invoke the ordinary Job_new event/email workflow.
- Archiving removes live mobile visibility but retains late offline completion evidence. Disabling authoring later does not undo released Jobs or history. Compatible mobile download retention is required for pending evidence.
- New Jobs receive meeting_time at their scheduled start, due_date using that scheduled date, and an initial date_completed/epoch at the estimated end; they remain incomplete (is_complete=0). A populated estimate is not proof of completion.
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 Visits, Jobs/adoptions, provenance, archive metadata, linked Contract rows, Job and visits_published audits, mobile sync markers and replay result together. Generated linked Tasks from older data are marked archived only when their Programme metadata matches the Job. No files/evidence are removed.
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 → Publish Jobs, Preview, review prior work, acknowledge archive impact and Publish. Filter for ContractProgramme_publish; the UI keeps one generated key for the reviewed attempt.
Related endpoints
ContractProgramme_preview— Obtain the exact current revision and archive list.ContractProgramme_move— Change live work after publication.ContractProgramme_addJob— Add a one-off Service or inspection.