Jobs: field and bulk edits
Change a job’s contract
/a/Job_setContractId
Attach a job to a contract or clear its contract association from a focused edit.
When to use this endpoint
Attach a job to a contract or clear its contract association from a focused edit.
Read the target job first with Jobs_getSome to obtain the current values and confirm the IDs belong to the intended account.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. The request uses the authenticated account’s job IDs, not mobile app IDs.
The legacy userdata.permissions bit 128 blocks editing with No permission to edit; this handler does not exempt client administrators from that bit. It does not add an assignee/department scope.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Integer string | Yes | Physical job ID in the authenticated account, converted with intval; must be positive. |
contract_id | Integer string | Yes | Contract ID converted to integer; zero detaches. Omitted defaults to -1 and is rejected. Blank/nonnumeric present input coerces to zero. |
Example request
$result = FM_api('Job_setContractId', ['id'=>'1042', 'contract_id'=>'302']);
Example response
{"ok":1}
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":"missing or invalid parameter: id"} | id is absent or converts to a nonpositive integer. |
{"error":"No permission to edit"} | The legacy edit restriction bit is set. |
{"error":"missing or invalid parameter: contract_id"} | The integer contract ID is negative, including omitted input. |
{"error":"job does not exist"} | No active job row is read, or that read fails. |
{"ok":1,"warning":"value already set"} | The converted requested ID matches the stored contract and the positive destination is active. |
{"error":"Contract does not exist"} | The positive destination contract is missing/deleted; the previous association is preserved. |
{"error":"Unable to save contract"} | A transactional read, write or commit failed; the association is rolled back. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Locks the active job and old/new contract rows in a tenant transaction. A positive destination must exist and be active, including when the requested contract ID equals the saved ID.
- Compares the converted integer contract IDs. An unchanged valid association returns a no-change warning without writes.
- Changed assignments replace all type-6 job/contract relationships; zero detaches. The job column, relationship writes and old/new contract customer-cache dirty markers commit together. Any checked read/write or transaction failure rolls back.
- This is not a contract create or customer change. It does not mirror to an outsourced job.
Side effects
- Updates the job’s last_edited/edited_uuid and invalidates the meetings cache.
- Records job history and contract add/remove history for the changed association.
- Flags both the previous and destination contract’s customer caches dirty when their rows exist, including a move between two positive contract IDs. No mail is sent.
See it in Fieldmotion
CRM1
Open a job’s Main page, click its Contract field and select a contract or blank entry. pageJob.js sends Job_setContractId; inspect that request in Network.
CRM2
No direct CRM2 caller was found in the canonical/legacy route search. CRM2’s layout-driven updates are a separate contract.
Related endpoints
Contracts_listsupplies selectable contracts.Jobs_getSomereads selected job records before editing and verifies the stored result afterward.