Jobs: scheduling and lifecycle
Assign selected jobs in bulk
/a/Jobs_setUser
Change selected job assignees through the legacy batch path and return the affected user IDs.
When to use this endpoint
Use the Jobs multi-edit Change User workflow. This is not an atomic batch of Job_setUserIdAndType calls; notifications and status handling differ.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. Legacy edit-restriction bit 128 is enforced; client administrators retain the existing admin exception.
The primary job selection is tenant-scoped. There is no automatic schedule-conflict or assignee-ownership check. Cross-tenant follow-ups use persisted outsourcing context.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
job_ids | Array or JSON array | Yes, or legacy alias | Nonempty job-ID list. Values are integer-coerced; duplicates/missing/deleted IDs are collapsed/omitted by the active-row lookup. No complete-match check. |
appointment_ids | Array or JSON array | Legacy alternative | Accepted only when job_ids is absent/null. Both CRM multi-edit callers still send this exact old wire name. Prefer job_ids in new integrations. |
user_id | Integer string | No | Defaults to 0 unassigned; negative is rejected. Positive type-0 IDs must resolve to an active tenant user. |
user_type | Integer string | No | 0 tenant user (default), 1 actively linked outsource company. Other values and type 1 with ID 0 are rejected. |
Example request
$result = FM_api('Jobs_setUser', [
'job_ids' => json_encode(['1042', '1088']),
'user_id' => '27', 'user_type' => '0',
]);
Example response
[27,"0"]
Returns unique affected NEW then OLD user IDs, not job IDs and not {ok:1}. Existing DB IDs are often strings. array_unique retains numeric keys; some multi-user batches encode as an object with sparse numeric keys rather than a JSON list. No changes returns [].
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: user_id"} | Negative target ID. |
{"error":"job_ids should be a JSON-encoded array of job IDs"} | Missing, null or empty list. |
{"error":"Failed to update job assignment"} | Primary write failed; earlier jobs can already be saved. |
{"error":"tenant job does not exist"} | An old outsourced counterpart could not be cancelled after local assignment. |
{"error":"Invalid job assignee"} | Unsupported type/ID or missing/inactive tenant user. |
{"error":"you are not linked to that outsource client"} | No active type-1 outgoing outsourcing link. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Enforces the edit restriction with client-admin exception and prevalidates the typed assignee. Does not reopen status 4, unlike the single assignment setters.
- Skips unchanged typed assignments. Writes previousUser, resets on_app=0 and advances sync metadata for each change.
- Old outsource copies are cancelled when metadata identifies them, but this path does not remove the local outsourced metadata. New type-1 assignment calls Outsourcing_sendJob without checking its response.
- Immediate Job_emailAbout is attempted when the tenant/form/Job Type notification gate enables it, even though this loop does not constrain the call to user_type=0. It does not create the assignment cron type-5/6 rows used by the single typed setter.
- Withdraws removal markers for the new numeric ID and records the old numeric user's removal without checking the old assignment type. No batch size limit or transaction; database row order is unspecified.
Side effects
- Updates assignments and mobile state; cancellation/creation of outsource copies, customer last_edited writes, immediate assignment mail, mobile deletion audits and Job_updateCosts.
- Assignment emails receive typed old/new snapshots; current customer numeric IDs are touched even for asset-target jobs. The wrapper does not add its own set-user history beyond nested follow-ups.
See it in Fieldmotion
CRM1
Select jobs → Change User. jobsMultiEdit.js sends the legacy appointment_ids field and a typed user selector.
CRM2
The same Change User bulk action in lib/jobsMultiEdit.js also sends appointment_ids. Its response is used as completion, not as a job-ID result list.
Related endpoints
Job_setUserIdsets a tenant-user assignee.Job_setUserIdAndTypehandles typed outsourcing handover.Jobs_setUsersAndTimesapplies a scheduler batch and reports saved prefixes.